Question
Overall Goal
I want to build a Java WebApp (war file) where folders containing static content have a version number append to it for cachability. Renaming should happen automatically during build.
Details
The WebApp is already structured in a way that all static content is grouped together inside folders:
/lib -> All JavaScript libraries, eg /lib/angular-1.0.3 (source at src/main/webapp)
/app -> My Own Code, at the moment /app/myApp (source at src/main/webapp)
/api -> all dynamic servlets (source at src/main/java)
index.jsp -> host page that bootstraps the WebApp
Everything starting with /api and index.jsp is dynamic and not cachable at all.
Everything starting with /lib is static and versioned, thus we can set an expires header of 'access + 12 month'. Content changes require a new version number. This is easy with libraries, as they don't change much an the version number is hardcoded.
Since my own app (built with AngularJS) is also static, I want to set its expires header to 'access + 12 month', too. To do so, I need to add the current version number from Maven to the end of the folder name, thus turning /app/myApp from the source directory to /app/myApp-1.2.3 in the target directory / final war file.
POM File
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<goals>
<goal>jslint</goal>
<goal>compress</goal>
</goals>
</execution>
</executions>
<configuration>
<excludeResources>true</excludeResources>
<removeIncluded>true</removeIncluded>
<suffix>.min</suffix>
<excludes>
<exclude>**/*.xml</exclude>
<exclude>**/*.properties</exclude>
<exclude>**/lib/**/*.js</exclude>
<exclude>**/lib/**/*.css</exclude>
</excludes>
<aggregations>
<aggregation>
<insertNewLine>true</insertNewLine>
<output>${project.build.directory}/${project.build.finalName}/app/myApp/js/all.min.js</output>
<includes>
<include>${project.basedir}/src/main/webapp/app/myApp/js/header.txt</include>
<include>**/*.min.js</include>
</includes>
</aggregation>
</aggregations>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.1</version>
<executions>
<execution>
<id>prepare-war</id>
<phase>prepare-package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.2</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<ignoreMissingFile>false</ignoreMissingFile>
<file>${project.build.directory}/myApp/index.jsp</file>
<replacements>
<replacement>
<token>PROJECT_VERSION</token>
<value>${project.version}</value>
</replacement>
</replacements>
</configuration>
</plugin>
I am looking for a way to copy all ressources to the target-directory, run yuicompressor, update the links and rename app/myApp to app/myApp-x.y.z
Compressing and updating the links already, but I can't find a way to rename my own app at build time.
Thanks
Solution
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<goals>
<goal>jslint</goal>
<goal>compress</goal>
</goals>
</execution>
</executions>
<configuration>
<excludeResources>true</excludeResources>
<removeIncluded>true</removeIncluded>
<suffix>.min</suffix>
<failOnWarning>true</failOnWarning>
<excludes>
<exclude>**/*.xml</exclude>
<exclude>**/*.properties</exclude>
<exclude>**/lib/**/*.js</exclude>
<exclude>**/lib/**/*.css</exclude>
</excludes>
<sourceDirectory>${project.basedir}/src/main/webapp/app/myApp</sourceDirectory>
<outputDirectory>${project.build.directory}/${project.build.finalName}/app/myApp-${project.version}</outputDirectory>
<aggregations>
<aggregation>
<insertNewLine>true</insertNewLine>
<output>${project.build.directory}/${project.build.finalName}/app/myApp-${project.version}/js/all.min.js</output>
<includes>
<include>${project.basedir}/src/main/webapp/app/myApp/js/header.txt</include>
<include>**/*.min.js</include>
</includes>
</aggregation>
</aggregations>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>prepare-war</id>
<phase>prepare-package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
<configuration>
<useCache>true</useCache>
<!-- this exclude the directory to rename from the default copy resources procedure -->
<warSourceExcludes>app/myApp/**,.idea/**</warSourceExcludes>
<!-- this will do the renaming : i.e. we specify the source directory relative to pom.xml and the target directory relative to root -->
<webResources>
<resource>
<directory>src/main/webapp/app/myApp</directory>
<excludes>
<exclude>**/*.js</exclude>
</excludes>
<targetPath>/app/myApp-${project.version}</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.2</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<ignoreMissingFile>false</ignoreMissingFile>
<file>${project.build.directory}/myApp/index.jsp</file>
<replacements>
<replacement>
<token>%PROJECT_VERSION%</token>
<value>${project.version}</value>
</replacement>
</replacements>
</configuration>
</plugin>
</plugins>
I think you can do it by configuring a <webResources> element in your maven-war-plugin config.
Doing something like this should work
<configuration>
<!-- this exclude the directory to rename from the default copy resources procedure -->
<warSourceExcludes>app/myApp/**</warSourceExcludes>
<!-- this will do the renaming :
i.e. we specify the source directory relative to pom.xml
and the target directory relative to root -->
<webResources>
<resource>
<directory>src/main/webapp/app/myApp</directory>
<!-- override the destination directory for this resource -->
<targetPath>app/myApp-${project.version}</targetPath>
</resource>
</webResources>
</configuration>
EDIT
I'm not used to work with yucompressor plugin but it seems that you can easily change the output directory through <outputDirectory> element:
<outputDirectory>${project.build.directory}/${project.build.finalName}/app/myApp-${project.version}/js/all.min.js</outputDirectory>
If all your code is in all.min.js (I think that's what the yucompressor do, but I'm not sure) : then you don't need the <webResources> section in the war plugin, but you have to keep <warSourceExcludes>app/myApp/**</warSourceExcludes> to avoid duplication.
EDIT 2
As an answer to your comment.
Try the following:
use yucompressor for *.css and *.js as indicated in previous EDIT
exclude /myapp from usual war-plugin copy resources procedure using <warSourceExcludes>app/myApp/**</warSourceExcludes>
use a webResources section to include all you non *.js and non *.css to myApp-${project.version}:
<webResources>
<resource>
<directory>src/main/webapp/app/myApp</directory>
<excludes>
<exclude>**/*.js</exclude>
<exclude>**/*.css</exclude>
</excludes>
<!-- override the destination directory for this resource -->
<targetPath>app/myApp-${project.version}</targetPath>
</resource>
</webResources>
Related
I am trying to use the jspc-maven-plugin from Apache Sling. When I compile my JSPs, they end up in my target/org/apache/jsp directory. I want them to go go directly under target or under target/classes w/o the org/apache/jsp part. How can I achieve this? Here is my plugin specification:
<plugin>
<groupId>org.apache.sling</groupId>
<artifactId>jspc-maven-plugin</artifactId>
<executions>
<execution>
<id>compile-jsp</id>
<goals>
<goal>jspc</goal>
</goals>
<configuration>
<sourceDirectory>${basedir}/source/html</sourceDirectory>
<outputDirectory>${basedir}/target</outputDirectory>
<includes>
<include>**/*.jsp</include>
</includes>
<showSuccess>true</showSuccess>
<failOnError>false</failOnError>
<compilerSourceVM>${javac.source}</compilerSourceVM>
<compilerTargetVM>${javac.target}</compilerTargetVM>
<servletPackage/> <!-- doesn't seem to matter - deprecated -->
</configuration>
</execution>
</executions>
</plugin>
I need to use values from properties file in maven pom.xml, so i used properties-maven-plugin to read my properties file as follows
pom.xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>${basedir}/src/main/resources/qura.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
qura.properties file contains something like this..
config.file.path = resources/python/config/test.py
I need use this config.file.path variable in resource element of pom.xml
pom.xml
<resources>
<resource>
<directory>${basedir}/multilang/</directory>
<includes>
<include>${config.file.path}</include>
</includes>
</resource>
<resources>
But the value for ${config.file.path} is not taking up from qura.properties file and I couldn't find test.py file in jar.
what I'm doing wrong in this code?
Thanks in Advance
try using version 1.0.0 and removing spaces around equal sign in properties file.
eg:
key=value
IMO, it does not matter whether you put the spaces or not around equal sign in properties file. You may need to check if the ${config.file.path} exists in the directory specified by ${basedir}/multilang
The below snippet works for me.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-resources</id>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>src/main</directory>
<includes>
<include>${config.file.path}</include>
</includes>
</resource>
</resources>
</configuration>
<inherited></inherited>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>${basedir}/src/main/resources/qura.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Using Eclipse Luna with m2eclipse, I have a parent Maven project (facturas_root) and two Maven modules inheriting from it (sharepoint_ws and api_sharepoint).
sharepoint_ws was to be used only to generate JAXWS classes to connect to the Sharepoint WebServices, so I downloaded the related WSDL and included those as resources of the project. At generate-sources phase, it works correctly and generates the sources in target\generated-sources\ws-consume\mypackage\.
Now, the issue is that I made api_sharepoint import the sharepoint_ws dependency, but it does not detect any class. I assumed that it was because the generated classes were not at src/main/java, so I added a plugin to copy them there. Now, the problem is that at the compile phase of sharepoint_ws, it finds twice the source file of each class and throws an error.
My pom.xml -> build
<plugins>
<!-- clean /src/main/java and /target/generated-sources -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.6.1</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>clean</goal>
</goals>
<configuration>
<filesets>
<fileset>
<directory>${basedir}/src/main/java/es</directory>
</fileset>
<fileset>
<directory>${basedir}/target/generated-sources</directory>
</fileset>
</configuration>
</execution>
</executions>
</plugin>
<!-- generate jaxws -->
<plugin>
<groupId>org.jboss.ws.plugins</groupId>
<artifactId>maven-jaxws-tools-plugin</artifactId>
<version>1.1.2.Final</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>wsconsume</goal>
</goals>
<configuration>
<wsdls>
<wsdl>${basedir}/resources/lists.wsdl</wsdl>
</wsdls>
<targetPackage>es.ssib.otic.facturas.sharepoint_ws</targetPackage>
<outputDirectory>${basedir}/target/generated-sources</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- copy sources -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-filtering</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<resources>
<resource>
<directory>${basedir}/target/generated-sources/wsconsume</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
In order to try to exclude target/generated-sources I have addded this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<configuration>
<excludes>
<exclude>**/target/generated-sources/*.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
As stated above, I do comment the "copy" plugin, the module depending on sharepoint_ws does not have any ot its classes available; I do use it I get errors in the tune of
[ERROR] /C:/Users/s004256/workspace/facturas_root/sharepoint_ws/src/main/java/es/ssib/otic/facturas/sharepoint_ws/DeleteList.java:[34,8] duplicate class: es.ssib.otic.facturas.sharepoint_ws.DeleteList
for each generated list.
In the first place, I recommend you'd better declare target/generated-sources as a source folder, instead of copying files here and there:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>add-source</id>
<phase>initialize</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
This should be enough to make Maven compile the target/generated-sources/*.java and package them all in the library, and also for Eclipse to recognize target/generated-sources as a source directory (after you execute Maven/Update Project).
By the way: You should take care of binding the plugins to a phase in the correct order: If you bound all tasks to "generate-sources", you have no gurantee about in which order will they be executed. And the same goes for the "compile" phase: You have to set properly the source folders, with its inclusions and exclusions, before the compile phase.
Take a look a the Default Maven Lifecycle and try to chose different, sequential phases for your tasks.
How can I tell maven to create a particular directory structure and to put jar files in certain places?
For example I want to put put some jars in a directory called plugins which are loaded at runtime.
Is that possible? Or am I missing the principles behind maven?
It looks like your jars is your project dependency, so to copy all dependencies at plugins folder use next:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-alldeps</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/plugins</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<excludeTransitive>false</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
When your project use jars like resources, use maven resource section or next plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-config-files</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/plugins/</outputDirectory>
<resources>
<resource>
<filtering>false</filtering>
<directory>${project.basedir}/jars/</directory>
<includes>
<include>file1.jar</include>
<include>file5.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
I have a very simple pom.xml that generates a fully working web service if deployed locally (Tomcat 7). This is its <build> section:
<build>
<finalName>${artifact.id}</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<id>generate-sources</id>
<configuration>
<sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/wsdl/mywebservice.wsdl</wsdl>
<extraargs>
<extraarg>-impl</extraarg>
<extraarg>-verbose</extraarg>
</extraargs>
<wsdlLocation>${basedir}/src/main/wsdl/mywebservice.wsdl</wsdlLocation>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/target/generated/src/main/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${basedir}/src/main/wsdl/mywebservice.wsdl</file>
<type>wsdl</type>
</artifact>
<artifact>
<file>${basedir}/src/main/xsd/myschema.xsd</file>
<type>xsd</type>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The reason it only works if deployed locally and not when deployed to a remote server is because the remote server cannot find the .wsdl and the .xsd files in development source directories ${basedir}/target/generated/src/main/ and they are also nowhere to be found in the WAR file.
Apparently, I am missing something in my pom.xml that would make Maven add or attach those files to the WAR.
I tried the attach-artifact goal (as quoted above) but it only copies the files to my local (development) .m2 repository, not to the WAR file.
How do I add or attach files to the actual .war file to be deployed?
I solved the mystery.
Posting the answer here in case another newbie to Maven (plus CXF?) encounters this problem:
It turns out that the attach-artifact execution is totally unneeded and is a shot in the wrong direction.
All I had to do was to add at the top of the <build> section, just before <plugins> the following:
<resources>
<resource>
<directory>src/main/wsdl</directory>
</resource>
<resource>
<directory>src/main/xsd</directory>
</resource>
</resources>
That's all. Maven then automagically places all files in those directories in WEB-INF/classes/.