5/28/2013

Maven Study Note: Jar Packaging and Installation (maven-assembly-plugin & maven-install-plugin)

Maven is so powerful. As a new comer, I believe I only explored the very basic level of usage of Maven.
One of the most frequent usages of Maven is its packaging function. Recently I did a little bit research on this part and make several tests.

Main cmd:  mvn clean install (-Dmaven.test.skip=true) everybody knows this...skip.

Besides the basic packaging function, there are a lot of extensions.

Package an executable jar with all the dependencies

<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-assembly-plugin</artifactId>
 <version>2.3</version>
 <executions>
   <execution>
     <id>assemblyApp</id>
     <phase>package</phase>
     <goals>
       <goal>single</goal>
     </goals>
     <configuration>
       <finalName>${project.artifactId}</finalName>
       <appendAssemblyId>true</appendAssemblyId>
       <archive>
         <manifest>
           <mainClass>
             com.test.commons.App
           </mainClass>
         </manifest>
       </archive>
       <descriptors>
         <descriptor>src/main/assembly/app-executable-jar.xml</descriptor>
         <descriptor>src/main/assembly/app-executable-artifact.xml</descriptor>
       </descriptors>
     </configuration>
   </execution>
 </executions>
</plugin>

app-executable-jar.xml:

<assembly
       xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
   <id>with-dependencies</id>
   <formats>
       <format>jar</format>
   </formats>
   <includeBaseDirectory>false</includeBaseDirectory>
   <dependencySets>
       <dependencySet>
           <outputDirectory>/</outputDirectory>
           <useProjectArtifact>true</useProjectArtifact>
           <unpack>true</unpack>
           <scope>runtime</scope>
       </dependencySet>
   </dependencySets>
</assembly>

app-executable-artifact.xml:


<assembly
   xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
   <id>bin</id>
   <formats>
       <format>dir</format>
       <format>zip</format>
   </formats>
   <includeBaseDirectory>false</includeBaseDirectory>
   <fileSets>
       <fileSet>
           <directory>${basedir}/src/main/assembly/app-bin</directory>
           <outputDirectory>/</outputDirectory>
           <filtered>true</filtered>
       </fileSet>
       <fileSet>
           <directory>${project.build.directory}</directory>
           <outputDirectory>/</outputDirectory>
           <includes>
               <include>${artifact.artifactId}-with-dependencies.jar</include>
           </includes>
       </fileSet>
   </fileSets>
</assembly>


In directory ${basedir}/src/main/assembly/app-bin, there is one batch file for execution:

Run.bat:

java -jar XXXXX(${artifact.artifactId})-with-dependencies.jar

Build Result:
In target:
there will be two jar files:
${project.artifactId}-${project.version}.jar
${project.artifactId}-with-dependencies.jar
there will be one zip file:
${project.artifactId}-bin.zip
there will be one directory, which holds the extracted files of the zip file.
${project.artifactId}-bin

If you do not want to specify main class. Then remove the archive config in the maven-assembly-plugin, and in Run.bat:

java -jar XXXXX(${artifact.artifactId})-with-dependencies.jar com.test.commons.App

Useful.

Sometimes, we may want to package the src to differect jar file for different support. In this case, we may want to realize flexible packaging using maven. Here comes the second scenario:

Package Src into different jar file, can customize to include/exclude any dependencies or class files.

For example, I want to develop one encryption and decryption service provider. For encryption consumer, I do not want to expose decryption method to them. And vise verse, for decryption consumer, I do not want to expose encryption method to them. So in this case, I need different jar file for encryption and decryption. And I do not want to separate the source code. Then we can config maven to surpport this kind of packaging.

To remove class in the jar file, we can use maven shade plugin, but personally I don't like it. I prefer maven assembly plugin because I think it is more flexible. Personal Opinion.

Here I only introduce the maven assembly plugin usage:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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">
   <modelVersion>4.0.0</modelVersion>
   <prerequisites>
       <maven>3.0.3</maven>
   </prerequisites>

   <properties>
       <java.version>1.6</java.version>
       <spring.version>3.1.0.RELEASE</spring.version>
       <commons-codec.version>1.6</commons-codec.version>
       <commons-lang.version>2.6</commons-lang.version>
       <jasypt.version>1.7.1</jasypt.version>
       <log4j.version>1.2.16</log4j.version>
       <log4j-extras.version>1.1</log4j-extras.version>
       <junit.version>4.8.2</junit.version>

       <sonar.host.url>
           http://localhost/sonar
       </sonar.host.url>

   </properties>

   <groupId>com.test.commons</groupId>
   <artifactId>test-common-security</artifactId>
   <packaging>jar</packaging>
   <version>1.0.0</version>
   <name>test-common-security</name>

   <dependencies>
       <dependency>
           <groupId>commons-codec</groupId>
           <artifactId>commons-codec</artifactId>
           <version>${commons-codec.version}</version>
       </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-context</artifactId>
           <version>${spring.version}</version>
       </dependency>


       <dependency>
           <groupId>log4j</groupId>
           <artifactId>log4j</artifactId>
           <version>${log4j.version}</version>
       </dependency>
       <dependency>
           <groupId>log4j</groupId>
           <artifactId>apache-log4j-extras</artifactId>
           <version>${log4j-extras.version}</version>
       </dependency>
       <dependency>
           <groupId>org.jasypt</groupId>
           <artifactId>jasypt</artifactId>
           <version>${jasypt.version}</version>
       </dependency>
       <dependency>
           <groupId>commons-lang</groupId>
           <artifactId>commons-lang</artifactId>
           <version>${commons-lang.version}</version>
       </dependency>
       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>${junit.version}</version>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-test</artifactId>
           <version>${spring.version}</version>
           <scope>test</scope>
       </dependency>
   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>2.3.1</version>
               <configuration>
                   <source>${java.version}</source>
                   <target>${java.version}</target>
               </configuration>
           </plugin>

           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-source-plugin</artifactId>
               <version>2.1.2</version>
           </plugin>

           <plugin>
               <groupId>org.codehaus.mojo</groupId>
               <artifactId>sonar-maven-plugin</artifactId>
               <version>2.0</version>
           </plugin>

           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-assembly-plugin</artifactId>
               <version>2.3</version>
               <executions>
                   <execution>
                       <id>assemblyEncoder</id>
                       <phase>package</phase>
                       <goals>
                           <goal>single</goal>
                       </goals>
                       <configuration>
                           <finalName>${project.artifactId}</finalName>
                           <appendAssemblyId>true</appendAssemblyId>
                           <archive>
                               <manifest>
                                   <mainClass>
                                       com.test.commons.security.EncoderApp
                                   </mainClass>
                               </manifest>
                           </archive>
                           <descriptors>
                               <descriptor>src/main/assembly/encoder-executable-jar.xml</descriptor>
                               <descriptor>src/main/assembly/encoder-executable-artifact.xml</descriptor>
                           </descriptors>
                       </configuration>
                   </execution>

                   <execution>
                       <id>assemblyKeyPairGen</id>
                       <phase>package</phase>
                       <goals>
                           <goal>single</goal>
                       </goals>
                       <configuration>
                           <finalName>${project.artifactId}</finalName>
                           <appendAssemblyId>true</appendAssemblyId>
                           <archive>
                               <manifest>
                                   <mainClass>
                                       com.test.commons.security.util.KeyPairGenApp
                                   </mainClass>
                               </manifest>
                           </archive>
                           <descriptors>
                               <descriptor>src/main/assembly/keypairgen-executable-jar.xml</descriptor>
                               <descriptor>src/main/assembly/keypairgen-executable-artifact.xml</descriptor>
                           </descriptors>
                       </configuration>
                   </execution>

                   <execution>
                       <id>assemblyEncryptionJar</id>
                       <phase>package</phase>
                       <goals>
                           <goal>single</goal>
                       </goals>
                       <configuration>
                           <finalName>${project.artifactId}</finalName>
                           <appendAssemblyId>true</appendAssemblyId>
                           <descriptors>
                               <descriptor>src/main/assembly/encryption-jar.xml</descriptor>
                           </descriptors>
                       </configuration>
                   </execution>

                   <execution>
                       <id>assemblyDecryptionJar</id>
                       <phase>package</phase>
                       <goals>
                           <goal>single</goal>
                       </goals>
                       <configuration>
                           <finalName>${project.artifactId}</finalName>
                           <appendAssemblyId>true</appendAssemblyId>
                           <descriptors>
                               <descriptor>src/main/assembly/decryption-jar.xml</descriptor>
                           </descriptors>
                       </configuration>
                   </execution>

               </executions>
           </plugin>

           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-install-plugin</artifactId>
               <version>2.4</version>
               <executions>
                   <execution>
                       <id>install-encryption</id>
                       <phase>package</phase>
                       <goals>
                           <goal>install-file</goal>
                       </goals>
                       <configuration>
                           <file>target/${project.artifactId}-encryption-${project.version}.jar</file>
                           <groupId>${project.groupId}</groupId>
                           <artifactId>${project.artifactId}-encryption</artifactId>
                           <version>${project.version}</version>
                           <packaging>jar</packaging>
                       </configuration>
                   </execution>

                   <execution>
                       <id>install-decryption</id>
                       <phase>package</phase>
                       <goals>
                           <goal>install-file</goal>
                       </goals>
                       <configuration>
                           <file>target/${project.artifactId}-decryption-${project.version}.jar</file>
                           <groupId>${project.groupId}</groupId>
                           <artifactId>${project.artifactId}-decryption</artifactId>
                           <version>${project.version}</version>
                           <packaging>jar</packaging>
                       </configuration>
                   </execution>

               </executions>
           </plugin>

       </plugins>
   </build>

   <reporting>
       <plugins>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-surefire-report-plugin</artifactId>
               <version>2.12</version>
           </plugin>
       </plugins>
   </reporting>
</project>


The assemblyEncryptionJar and assemblyDecryptionJar execution in assembly plug in, package the src to different  jar files for encryption and decryption.

encryption-jar.xml

<assembly
   xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
   <id>encryption-${project.version}</id>
   <formats>
       <format>jar</format>
   </formats>
   <includeBaseDirectory>false</includeBaseDirectory>
   <dependencySets>
       <dependencySet>
           <outputDirectory>/</outputDirectory>
           <useProjectArtifact>true</useProjectArtifact>
           <includes>
               <include>${project.groupId}:${project.artifactId}</include>
           </includes>
           <unpack>true</unpack>
           <unpackOptions>
               <excludes>
                   <exclude>com/test/commons/security/text/TextDecryptor.class</exclude>
                   <exclude>com/test/commons/m/aes/AESDecryptor.class</exclude>
               </excludes>
           </unpackOptions>
           <scope>runtime</scope>
       </dependencySet>
   </dependencySets>
</assembly>


Basically, we add dependency ${project.groupId}:${project.artifactId}, unpack it, exclude several classes that we do not want to add.

decryption-jar.xml

<assembly
   xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
   <id>decryption-${project.version}</id>
   <formats>
       <format>jar</format>
   </formats>
   <includeBaseDirectory>false</includeBaseDirectory>
   <dependencySets>
       <dependencySet>
           <outputDirectory>/</outputDirectory>
           <useProjectArtifact>true</useProjectArtifact>
           <includes>
               <include>${project.groupId}:${project.artifactId}</include>
           </includes>
           <unpack>true</unpack>
           <unpackOptions>
               <excludes>
                   <exclude>com/test/commons/security/BasicAuthUtil.class</exclude>
                   <exclude>com/test/commons/security/Encoder.class</exclude>
                   <exclude>com/test/commons/security/EncoderApp.class</exclude>
                   <exclude>com/test/commons/security/EncryptionSSOConfig.class</exclude>
                   <exclude>com/test/commons/security/EncryptionSSOException.class</exclude>
                   <exclude>com/test/commons/security/EncryptionSSOUtil.class</exclude>
                   <exclude>com/test/commons/security/util/*</exclude>
                   <exclude>com/test/commons/security/text/TextEncryptor.class</exclude>
                   <exclude>com/test/commons/security/aes/AESEncryptor.class</exclude>
               </excludes>
           </unpackOptions>
           <scope>runtime</scope>
       </dependencySet>
   </dependencySets>
</assembly>

In this way, five jar files will be generated.

-test-common-security-2.0.1.jar
-test-common-security-encryption-2.0.1.jar
-test-common-security-decryption-2.0.1.jar
-test-common-security-with-dependencies.jar
-test-common-security-keypairgen-with-dependencies.jar

two zip files will be generated:
-test-common-security-bin.zip
-test-common-security-keypairgen-bin.zip

two directory will be generated:
-test-common-security-bin
-test-common-security-keypairgen-bin

To install test-common-security-encryption-2.0.1.jar and test-common-security-decryption-2.0.1.jar into maven's repository and into specified folder. We need to config the installation of maven using maven install plugin. Configuration as above.

Useful Reference:
http://maven.apache.org/plugins/maven-install-plugin/install-file-mojo.html

The maven official manual book is enough and if you read the component of maven plugins, you can easily find out ways to config maven based on your own requirement.

No comments:

Post a Comment