• Home
  • RSS Feed
  • Log in

Maven appassembler Plugin: Dealing with Long Classpaths on Windows
Posted by ShriKant Vashishtha in the early afternoon: November 22nd, 2009

When it comes to generating command-line scripts for Java applications, Maven "appassembler" plugin comes handy. Its "assemble" goal does all the maven magic, i.e. searching the dependencies used for creating the Java application, adding them into the classpath of resultant script and finally copying all relevant jars to a single place. It was all working very nicely until I stumbled across the problem of long classpaths in the Windows OS.

Irrespective of whether you use DOS prompt or cygwin, Windows limits the length of environment variables. Though there are various options to overcome this problem using Java 6 wildcard classpath, mapping the path to some drive etc, they all look like workarounds to me as problem can recur again anytime.

After some amount of research, I found appassembler plugin resolves this issue with booter-windows and booter-unix daemons. From the outset it looked like daemon does something else as the name is a bit misleading but in reality it's a generic way to start your Java applications. The booter-unix/booter-windows platforms were introduced for the sole purpose of resolving the long classpath issue (see MAPPASM-43) in appassembler maven plugin. Here's how it looks like in the pom you are working with:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>appassembler-maven-plugin</artifactId>
    <configuration>
        <repositoryLayout>flat</repositoryLayout>
        <installArtifacts>false</installArtifacts>
        <target>${project.build.directory}/appassembler</target>
        <defaultJvmSettings>
            <initialMemorySize>512M</initialMemorySize>
            <maxMemorySize>1024M</maxMemorySize>
            <extraArguments>
                <extraArgument>-DconfigFile=../../etc/config.properties</extraArgument>
                <extraArgument>-Dlog4j.configuration=../../etc/log4j.properties</extraArgument>
            </extraArguments>
        </defaultJvmSettings>
        <configurationDirectory>etc</configurationDirectory>
        <daemons>
            <daemon>
                <id>applicationName</id>
                <mainClass>com.xebia.appassebler.sample.Main</mainClass>
                <platforms>
                    <platform>booter-unix</platform>
                    <platform>booter-windows</platform>
                </platforms>
                <environmentSetupFileName>app-env</environmentSetupFileName>
            </daemon>
        </daemons>
    </configuration>
    <executions>
        <execution>
            < phase>package</phase>
            <goals>
                 <goal>generate-daemons</goal>
                 <goal>create-repository</goal>
            </goals>
        </execution>
    </executions>
</plugin>

If you look at the code carefully, you'll find "app-env" as a parameter to "environmentSetupFileName" tag. It is quite useful in passing environment variables to the resultant script. Using app-env (for UNIX) and app-env.bat (for Windows) environment setup files, I could pass a modified $REPO environment variable so that the copied repository containing dependencies is shared between booter-unix and booter-windows folders as follows:

|-- booter-unix

|   |-- bin

|   |   |-- applicationName
|   |   `-- app-env

|   `-- etc

|       `-- applicationName.xml

|-- booter-windows

|   |-- bin

|   |   |-- app-env.bat

|   |   `-- applicationName.bat

|   `-- etc

|       `-- applicationName.xml

|-- etc

|   |-- config.properties

|   `-- log4j.properties

`-- repo

    |-- <dependency1>.jar

    |-- <dependency2>.jar

    |-- ...

To copy the environment files and result of appassembler:generate-daemons maven goal to the appropriate locations we can use "maven-assembly-plugin" as follows:

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptor>src/main/conf/descriptor.xml</descriptor>
    </configuration>
    <executions>
       <execution>
          <goals>
              <goal>single</goal>
          </goals>
          <phase>package</phase>
       </execution>
    </executions>
</plugin>

Here's what src/main/conf/assembly.xml looks like:

<assembly>
    <id>bin</id>
    <formats>
        <format>tar.gz</format>
        <format>zip</format>
        <format>dir</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>target/appassembler/booter-unix</directory>
            <outputDirectory>/booter-unix</outputDirectory>
            <excludes>
                <exclude>*.bat</exclude>
                <exclude>*.cmd</exclude>
            </excludes>
            <lineEnding>unix</lineEnding>
            <fileMode>0744</fileMode>
        </fileSet>
        <fileSet>
            <directory>target/appassembler/booter-windows</directory>
            <outputDirectory>/booter-windows</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>target/appassembler/repo</directory>
            <outputDirectory>/repo</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>src/main/conf</directory>
            <includes>
                <include>app-env.bat</include>
            </includes>
            <outputDirectory>/booter-windows/bin</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>src/main/conf</directory>
            <includes>
                <include>app-env</include>
            </includes>
            <outputDirectory>/booter-unix/bin</outputDirectory>
            <lineEnding>unix</lineEnding>
        </fileSet>
    </fileSets>
</assembly>

Now, if you run "mvn clean package", it provides you the structure as mentioned in listing 2. You can execute the script from booter-windows/bin/applicationName.bat on Windows without worrying about long classpaths now.

  • Share/Bookmark

Tags: long classpath on windows, maven appassembler, maven appassembler booter
Filed under Java, Maven | 3 Comments »



3 Responses to “Maven appassembler Plugin: Dealing with Long Classpaths on Windows”



    jonas Says:
    Posted at: November 22, 2009 at 2:47 pm

    What about just using the assembly plugin with the the jar-with-dependencies output descriptor which will explode all dependencies for you inside the assembled jar? What’s the point of having externalized dependencies in separate .jar files? If you need to keep configuration files external just add the “etc” directory to the class path, e.g. java -cp ./etc:myproject-jar-with-dependecies.jar com.MainClass



    ShriKant Vashishtha Says:
    Posted at: November 23, 2009 at 5:16 pm

    assembly plugin can be another way to get away with the long classpath issue. However many people may not want to explode all dependencies in one single jar because of several reasons. The solution mentioned works for them.



    Alexander Says:
    Posted at: December 21, 2009 at 1:46 pm

    Looks like you reinvented the wheel



Leave a Reply

Click here to cancel reply.

Deployment automation for Java application running on Websphere, WebLogic and JBoss

Archives

  • March 2010
  • February 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009

Xebia Sites

  • Xebia Corporate
  • Xebia France
  • Xebia India

Categories

  • Java (282)
  • Agile (109)
  • General (50)
  • Testing (42)
  • Performance (42)
  • Hibernate (36)
  • Scrum (33)
  • Podcast (31)
  • Architecture (31)
  • Spring (28)
  • SOA (24)
  • Maven (22)
  • Project Management (22)
  • Middleware (23)
    • Deployment (14)
  • Flex (17)
  • JPA (17)
  • Eclipse (15)
  • Xebia Labs (15)
  • Quality Assurance (14)

Tag Cloud

    SOA Java IntelliJ product owner XML Groovy Introduction to Agile Closures Scrum Performance Lean Agile Awareness Workshop Poppendieck Architecture Ajax Maven Scala Agile Semantic Web Grails fitnesse Functional Programming Hibernate Testing Xebia Seam qcon JavaOne Spring esb