views:

437

answers:

5

basically what I have is an application server running liferay portal. and we also have custom portlets that have shared custom libraries as well as third party ones. for instance dwr-3.0, several drools jar files, spring-webmvc, spring, etc.

the problem is that is a nightmare for server administration, because when there is a deploy somebody always forgets what version was in the server etc.

We use maven 2, and what I was thinking is to do something like a maven project that pulls the dependencies (using dependencyManagement) from the parent pom and the default goal is something like "unjar all the dependencies and jar them in a unique jar". that way we would have a unique jar with a standard version that is deployed along with the rest of the files instead of having to deploy.

Do you guys know how can I do that if it is at all possible? I have been playing around with maven-assembly-plugin without much success. If assembly is the way to go, do you have an example to give me a kickstart?

Thanks in advance

+1  A: 

It sounds like maybe the Dependency Plugin is what you need.

I'm thinking you can unpack all the dependency jars to a specified location, then repack them into your new jar.

I hope it works out for you.

Vinnie
+1  A: 

I think that what you described is possible. First, create a parent POM where you declare dependencies in the <dependencyManagement> element:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>groupIdA<groupId>
  <artifactId>parent</artifactId>
  <packaging>pom<packaging>
  <version>1-SNAPSHOT</version>
  ...
  <dependencyManagement>
    <!-- Standard dependencies used in several build modules. Ensures all modules
         use the same version for these dependencies -->
    <dependencies>
      <dependency>
        <groupId>org.directwebremoting</groupId>
        <artifactId>dwr</artifactId>
        <version>3.0.M1</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>3.0.0.RELEASE</version>
      </dependency>
      ...
    </dependencies>
  <dependencyManagement>
  ...
</project>

Then, in a child project, declare the dependencies you need without declaring their version:

<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <artifactId>parent</artifactId>
    <groupId>groupIdA</groupId>
    <version>1-SNAPSHOT</version>
  </parent>
  <artifactId>childB</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <dependencies>
    <dependency>
      <groupId>org.directwebremoting</groupId>
      <artifactId>dwr</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
    </dependency>
      ...
  </dependencies>
  ...
</project>

Finally, use the default jar-with-dependencies predefined assembly descriptor to create a general assembly of a binary package with all the dependency libraries included unpacked inside the archive.

<project>
  [...]
  <build>
    [...]
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2-beta-5</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id> <!-- this is used for inheritance merges -->
            <phase>package</phase> <!-- append to the packaging phase. -->
            <goals>
              <goal>single</goal> <!-- goals == mojos -->
            </goals>
          </execution>
        </executions>
      </plugin>
      [...]
    </plugins>
  </build>
</project>

To create the project assembly, trigger the package phase:

mvn package

And this will produce the following assembly in the target directory:

target/child-1.0-SNAPSHOT-jar-with-dependencies.jar

I'm just not sure of what you want to do with this assembly (use it as dependency in portlet projects vs pull dependencies from the parent POM? ease the liferay deployment only?). All options are possible though.

Refer to the Maven Assembly plugin documentation for more details.

Pascal Thivent
Hi Pascal, I tried several different configurations of the assembly plugin without much success, meaning I could not make it do what I wanted.What I want to do with the generated jar file is have a unique jar file that is loaded in the shared lib directory of jboss so all the different portlets share the classes.Currently, we have all the jar files in server/servername/lib/ext but is a painfully annoying when there is a change in the libraries, really error prone, this way we have a unique jar file, that has only the required libraries, drop one file and you are done.
feniix
Pascal Thivent
I am not saying it does not work :)In my case, with the list of libraries I wanted, the assembly method is leaving some libraries out, I think it is a bug but the dependency method has exactly ALL the classes from the dependencies and the assembly method is missing some. It is weird though, I will see if I try to report a bug to apache fsf
feniix
+2  A: 

Another alternative is the maven-shade-plugin or even jarjar. I've used both, together with package renaming without any problems.

gpampara
I will take a look at that plugin, looks like is more straightforward to do what I want.
feniix
+1  A: 

I finally was able to resolve it in the following way, I have not tested in the application server, but the resulting archive is a jar file with the content of all the desired dependencies. Thanks Vincent for the tip :)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&gt;
<modelVersion>4.0.0</modelVersion>
<groupId>com.test.jarbundle</groupId>
<artifactId>bundle</artifactId>
<version>1.0</version>
<name>bundle</name>
<packaging>jar</packaging>
<url>http://maven.apache.org&lt;/url&gt;
<dependencies>
    <dependency>
        <groupId>org.directwebremoting</groupId>
        <artifactId>dwr</artifactId>
        <version>3.0.M1</version>
        <scope>runtime</scope>
        <exclusions>
         <exclusion>
          <artifactId>cometd</artifactId>
          <groupId>org.mortbay.jetty</groupId>
         </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring</artifactId>
        <version>2.5</version>
        <scope>runtime</scope>
        <exclusions>
         <exclusion>
          <artifactId>commons-logging</artifactId>
          <groupId>commons-logging</groupId>
         </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>2.5</version>
        <scope>runtime</scope>
        <exclusions>
         <exclusion>
          <artifactId>commons-logging</artifactId>
          <groupId>commons-logging</groupId>
         </exclusion>
         <exclusion>
          <artifactId>aopalliance</artifactId>
          <groupId>aopalliance</groupId>
         </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc-portlet</artifactId>
        <version>2.5</version>
        <scope>runtime</scope>
        <exclusions>
         <exclusion>
          <artifactId>commons-logging</artifactId>
          <groupId>commons-logging</groupId>
         </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-core</artifactId>
        <version>4.0.3</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>4.0.3</version>
        <scope>runtime</scope>
        <exclusions>
         <exclusion>
          <artifactId>antlr-runtime</artifactId>
          <groupId>org.antlr</groupId>
         </exclusion>
         <exclusion>
          <artifactId>core</artifactId>
          <groupId>org.eclipse.jdt</groupId>
         </exclusion>
         <exclusion>
          <artifactId>janino</artifactId>
          <groupId>janino</groupId>
         </exclusion>
         <exclusion>
          <artifactId>xercesImpl</artifactId>
          <groupId>xerces</groupId>
         </exclusion>
         <exclusion>
          <artifactId>xml-apis</artifactId>
          <groupId>xml-apis</groupId>
         </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-jsr94</artifactId>
        <version>4.0.3</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-decisiontables</artifactId>
        <version>4.0.3</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>jar.App</mainClass>
                    </manifest>
                </archive>
            </configuration> 
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${basedir}/target/dependency</directory>
        </resource>
    </resources>
</build>

And then you run

mvn package

link text

feniix
Good! Glad to help.
Vinnie
A: 

And finally the best solution was using maven-shade-plugin:

(snip)
    <build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <finalName>${artifactId}-${version}-tmp</finalName>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.3.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <shadedArtifactAttached>true</shadedArtifactAttached>
                        <shadedClassifierName>full</shadedClassifierName>
                        <artifactSet>
                            <excludes>
                                <exclude>classworlds:classworlds</exclude>
                                <exclude>junit:junit</exclude>
                                <exclude>jmock:*</exclude>
                                <exclude>org.apache.maven:lib:tests</exclude>
                                <exclude>log4j:log4j:jar:</exclude>
                            </excludes>
                        </artifactSet>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

(snip)

What is awesome about shade plugin is that it warns you when you are including classes that are overlapping (an example is the spring jar (the full one) with aopalliance classes)

feniix