Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a simple app with user-accessible config files using Maven

Tags:

maven-2

I need to produce a simple app for my customer configure and run at their site. I am using the Spring framework, so I have a number of config files that must be on the class path. I am using Maven2 with Netbeans as my IDE.

I am able to create and run my app using Netbeans/Maven and I am using the Application Assembler Maven plugin to generate the runnable application. All this works fine except that my Spring config files have to be placed in src/main/resources which means that they get packaged into the resulting JAR file.

I need my customer to be able to modify the config files to do their testing, but it's not reasonable to ask them to modify the copies that are packaged in the JAR.

There are perhaps a number of solutions, but it seems to me that the simplest would be to get Maven to not package the app and the config files into a JAR at all, just leaving them in something like a classes directory from which they can be run. This would allow the user to modify the config files easily. Unfortunately I can't figure out how to get Maven to "package" the app in this manner, or how to get the AppAssembler to generate the resulting runnable.

Here is an extract of my pom.xml that may help illustrate what I am trying to do:

...
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>3.1.0.RELEASE</version>
    </dependency>
    ... stuff deleted ...
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>appassembler-maven-plugin</artifactId>
        <version>1.2</version>
        <configuration>
          <!-- Set the target configuration directory to be used in the bin scripts -->
          <configurationDirectory>conf</configurationDirectory>
          <!-- Copy the contents from "/src/main/config" to the target
               configuration directory in the assembled application -->
          <copyConfigurationDirectory>true</copyConfigurationDirectory>
          <!-- Include the target configuration directory in the beginning of
               the classpath declaration in the bin scripts -->
          <includeConfigurationDirectoryInClasspath>
              true
          </includeConfigurationDirectoryInClasspath>
          <platforms>
            <platform>windows</platform>
          </platforms>
        <programs>
          <program>
            <mainClass>org.my.path.App</mainClass>
            <name>app</name>
          </program>
        </programs>
        </configuration>
      </plugin>
    </plugins>
  </build>
...
like image 204
Glenn Lawrence Avatar asked Dec 27 '22 05:12

Glenn Lawrence


2 Answers

If not misleading, I think you want to let the jar and config to be separated, with jar exposed for client's testing. The following can do this for you using copy-maven-plugin, it can accomplish almost tasks what assembly-plugin would do ,ex: copy, dependency and much more - download, upload ,move ,... .

        <plugin>
            <groupId>com.github.goldin</groupId>
            <artifactId>copy-maven-plugin</artifactId>
            <version>0.2.5</version>
            <executions>
                <execution>
                    <id>create-archive</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <resources>
                    <!--copy your scripts to ${myOutPutPath}/bin-->
                    <resource>
                        <targetPath>${myOutPutPath}/bin</targetPath>
                        <directory>${project.basedir}/src/main/scripts</directory>
                        <includes>
                            <include>*</include>
                        </includes>
                    </resource>
                    <resource>
                        <!--copy your configs-->
                        <targetPath>${myOutPutPath}/conf</targetPath>
                        <directory>${project.basedir}/src/main/config</directory>
                        <include>*</include>
                    </resource>
                </resources>
            </configuration>
        </plugin>

Package main jar and put to your ${myOutPutPath}

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3.1</version>
            <!-- The configuration of the plugin -->
            <configuration>
                <outputDirectory>${myOutPutPath}</outputDirectory>
                <!-- Configuration of the archiver -->
                <archive>
                    <!-- Manifest specific configuration -->
                    <manifest>
                        <!-- Classpath is added to the manifest of the created jar file. -->
                        <addClasspath>true</addClasspath>
                        <!--
                           Configures the classpath prefix. This configuration option is
                           used to specify that all needed libraries are found under lib/
                           directory.
                       -->
                        <classpathPrefix>lib/</classpathPrefix>
                        <!-- Specifies the main class of the application -->
                        <mainClass>com.xinguard.snmp.SNMP_ETL</mainClass>
                    </manifest>
                    <!-- you need to add some classpath by yourself, like conf here for client to use-->
                    <manifestEntries>
                        <Class-Path>conf/</Class-Path>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>

then package the lib jar to lib directory under jar directory.

       <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${myOutPutPath}/lib</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
like image 25
WeiChing 林煒清 Avatar answered Jan 06 '23 02:01

WeiChing 林煒清


Neither single packed jar file or bunch of unpacked classes files are good format for professional client delivery. Look at those brilliant apache apps like tomcat, ant and maven, they are shipped as a tar.gz or zip file, after download, simply extract them and you will get a nice and clean directory structure:

conf --> put config file like *.properties, logback.xml here
doc --> readme.txt, userguide.doc etc
lib --> put you core.jar with dependency jar file here
run.bat --> run script for Windows
run.sh --> run script for Unix

We can do these kinds of stuff with Maven as well. Note that you should design and implement your core jar to read *.properties from the conf directory properly. then use maven-assembly-plugin pack you app into this classical directory structure.

Sample pom.xml for a command-line app:

  <!-- Pack executable jar, dependencies and other resource into tar.gz -->
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.2-beta-5</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals><goal>attached</goal></goals>
      </execution>
    </executions>
    <configuration>
      <descriptors>
        <descriptor>src/main/assembly/binary-deployment.xml</descriptor>
      </descriptors>
    </configuration>
  </plugin>

Sample binary-deployment.xml for a command-line app:

<!--
  release package directory structure:
    *.tar.gz
      conf
        *.xml
        *.properties
      lib
        application jar
        third party jar dependencies
      run.sh
      run.bat
-->
<assembly>
  <id>bin</id>
  <formats>
    <format>tar.gz</format>
  </formats>
  <includeBaseDirectory>true</includeBaseDirectory>
  <fileSets>
    <fileSet>
      <directory>src/main/java</directory>
      <outputDirectory>conf</outputDirectory>
      <includes>
        <include>*.xml</include>
        <include>*.properties</include>
      </includes>
    </fileSet>
    <fileSet>
      <directory>src/main/bin</directory>
      <outputDirectory></outputDirectory>
      <filtered>true</filtered>
      <fileMode>755</fileMode>
    </fileSet>
    <fileSet>
      <directory>src/main/doc</directory>
      <outputDirectory>doc</outputDirectory>
      <filtered>true</filtered>
    </fileSet>
  </fileSets>
  <dependencySets>
    <dependencySet>
      <outputDirectory>lib</outputDirectory>
      <useProjectArtifact>true</useProjectArtifact>
      <unpack>false</unpack>
      <scope>runtime</scope>
    </dependencySet>
  </dependencySets>
</assembly>
like image 122
yorkw Avatar answered Jan 06 '23 02:01

yorkw