Making maven do file copying between building and running - maven

Revised Question (old question below):
Problem: When building and running a Jenkins plugin project in NetBeans using Maven, Java class loader used by log4j does not find some files (like configuration file, a custom appender, JDBC driver). They need to be copied to another location under target, and then they are found.
The solution I think I want is this: I want to give maven an extra command line argument(s), configured in NetBeans. This should make maven do extra step after building and before running anything. The step can either be the file copying (specified in pom.xml or by the command arguments), or it can be running a script (specified in pom.xml or by the command line arguments).
What to add to pom.xml? Some maven plugin?
Old Question (for reference)
I have a maven project for "my-jenkins-plugin". I need to use log4j with it. I currently have log4j.xml at this path:
./src/main/resources/log4j.xml
When I do clean&build in Netbeans, it gets copied to these places:
./target/classes/log4j.xml
./target/generated-classes/emma/classes/log4j.xml
./target/my-jenkins-plugin/WEB-INF/classes/log4j.xml
However, log4j does not find the file from any of these locations. I need to manually copy it to this location:
./target/work/webapp/WEB-INF/classes/log4j.xml
And then it works as expected.
More details: Maven 2, Netbeans 7.2. It's standard Jenkins plugin, project originally created with mvn hpi:create, and Netbeans uses Jetty to run Jenkins. Classpath used when running under NetBeans is java.class.path=C:\work\maven\boot\classworlds-1.1.jar (which is an existing jar) and I haven't found a way to add anything to this classpath, but if I add log4j.xml to root of that jar file, it is also found and works (obviously this is not a satisfactory solution). I know if log4j works or not simply by looking at console output, either it's correct log lines, or the dreaded log4j:WARN No appenders could be found for logger (TestLog). log4j:WARN Please initialize the log4j system properly. error and nothing else.
Question: How can I have either
the log4j.xml found in the first set of locations,
or log4j.xml found in a location outside target dir, like C:\log4j\log4j.xml
or make maven and/or netbeans to copy log4j.xml to a location where it is found now
or any other nice way to let me give my plugin log4j.xml after clean&build automatically, when debugging with NB?

You could use the Maven Ant plugin to run an Ant script that did the copying, or use the Maven resources plugin, which seems aimed at your exact use case of copying stuff to the output directory.
Also be aware that you can parameterize your build as described here (ignore the Jenkins part of that title, the answer relates to general Maven usage).

You could use this plugin in a profile:
<pluginRepositories>
<pluginRepository>
<id>evgenyg</id>
<name>Evgeny Goldin repo</name>
<url>http://evgenyg.artifactoryonline.com/evgenyg/repo/com/github/goldin/</url>
</pluginRepository>
</pluginRepositories>
<profiles>
<profile>
<id>copy</id>
<build>
<plugins>
<plugin>
<groupId>com.github.goldin</groupId>
<artifactId>copy-maven-plugin</artifactId>
<version>0.2.5</version>
<executions>
<execution>
<id>create-archive</id>
<phase>generate-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<resources>
<resource>
<targetPath>${project.build.outputDirectory}/work/webapp/WEB-INF/classes/</targetPath>
<directory>${project.basedir}/src/main/resources</directory>
<includes>
<include>log4j.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
To activate: mvn -Pcopy generate-resources

You can use copy artifact plugin. As in hudson.

This is how I got maven to copy .class and .jar files to new location before executing hpi:run goal. The log4j.xml is still copied in my Java code in a static{} block before instantiating log4j. To use this profile, I added -P netbeans to maven command line args in Netbeans:
Profile and plugin definition in pom.xml:
<profiles>
<profile>
<id>netbeans</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>copy</id>
<phase>compile</phase>
<configuration>
<target>
<ant antfile="${basedir}/log4j/ant.xml">
<target name="log4jcopy"/>
</ant>
</target>
</configuration>
<goals>
<goal>run</goal> <!-- means antrun:run -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Build XML for ant, log4j/ant.xml:
<project default="log4jcopy">
<target name="log4jcopy">
<echo message="Copying class files so that log4j finds them at runtime."/>
<copy verbose="true"
todir="target/work/webapp/WEB-INF/lib">
<fileset
dir="log4j"
includes="mysql-connector-java-5.1.6.jar" />
</copy>
<copy verbose="true"
todir="target/work/webapp/WEB-INF/classes/hyde/jenkins/myplugin">
<fileset
dir="target/classes/hyde/jenkins/plugins/myplugin"
includes="LogAppender*.class" />
</copy>
</target>
</project>

Related

Maven 2.2.1: [Warning] JAR will be empty - no content was marked for inclusion

Maven 2.2.1
JDK - 1.6.0_45
[WARNING] JAR will be empty - no content was marked for inclusion!
BUILD SUCCESSFUL
But build creates jar with pom.xml but no class files.
On the maven source code this exception is thrown only when source directory is not found.
The build is working for all other developers except on my workstation and one more workstation
I have tried all the solutions provided for this issue on stack overflow.
My source directory is src/java.
I also created src/main/java as source still no result.
I am calling mvn -o jar:jar && call mvn -o antrun:run
-o is becuase at this point I am testing with some old jars.
<build>
<sourceDirectory>src/java</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/src/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
<testResources>
<testResource>
<directory>${basedir}/src/test/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</testResource>
</testResources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<debug>true</debug>
<optimize>false</optimize>
<showDeprecation>true</showDeprecation>
<source>1.5</source>
<target>1.5 </target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>test*/temp/*.java</exclude>
<exclude>test*/support/*.java</exclude>
<exclude>test*/debug/*.java</exclude>
</excludes>
<includes>
<include>test*/**/AllTests.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>default-cli</id>
<phase>install</phase>
<configuration>
<target>
<copy file="${project.build.directory}/${artifactId}-${version}.jar"
todir="${user.home}/.m2/repository/${groupId}/${artifactId}/${version}" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
First follow the conventions in Maven which means your production sources code should be in src/main/java. You should also locate your resources like property files or other kind of files (like xml files) in your case to the proper location which is for production src/main/resources and for unit tests src/test/resources.
The first thing you should change is the directory structure for your project in the process in migration. That will save many hassles with configurations in Maven cause you are violating the convention over configuration paradigm.
Your unit tests code in src/test/java and follow the naming conventions for unit tests which means name your unit tests like *Test.java nothing more. You don't need to define a suite to run all the tests. If you follow the naming convention maven-surefire-plugin will do all the work for you.
Remove the antrun plugin from your pom configuration and use
mvn install
instead to install your produced jar into local repository. Based on the build life cycle you will compile, unit test and package your code into resulting jar files.
Usually in Maven there is no reason to call mvn jar:jar separately.
Apart from that all you should stop using Maven 2.2.1 cause it has defined End Of Life. Better start with Maven 3.X instead. But everything i wrote before is valid Maven 3.
I got Build Success but same error:
JAR will be empty - no content was marked for inclusion.
It was a test project and I realized that I had no "main" under "src". As soon as I corrected this, it was fixed. I am adding the wrong and right structure screenshots in the attachments:
right structure
wrong structure - missing main folder

Intellij IDEA artifact 'XXXX:war exploded' has invalid extension

Every time I make even the tiniest change to my POM Intellij removes the .war extension for my exploded artifact in the Project Structure output directory setting. This causes an error in Intellij's Run/Debug configuration:
Artifact 'XXXX:war exploded' has invalid extension.
In order to resolve the issue I must manually override the Project Structure output directory setting. Every time I make even the tiniest change to the POM I must go back to the Output directory setting and manually append ".war" to the end of the Output directory setting. This is getting very old and frustrating.
e.g. I must change this:
E:\workarea\enterp\application\target\application
to this:
E:\workarea\enterp\application\target\application.war
If I manually set the Maven WAR plugin outputDirectory configuration as follows, this does not help at all:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
<configuration>
<!-- Output directory of artifact:war exploded keeps losing the .war extension -->
<outputDirectory>${project.build.directory}.war</outputDirectory>
</configuration>
</plugin>
How can I resolve this problem?
EDIT:
Here's the complete build config:
<build>
<!-- Maven will append the version to the finalName (which is the name
given to the generated war, and hence the context root) -->
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- Compiler plugin enforces Java 1.6 compatibility and activates annotation
processors -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
<configuration>
<!-- Output directory of artifact:war exploded keeps losing the .war extension -->
<outputDirectory>${project.build.directory}/${project.artifactId}.war</outputDirectory>
<!-- Java EE 7 doesn't require web.xml, Maven needs to catch up! -->
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- The WildFly plugin deploys your war to a local WildFly container -->
<!-- To use, run: mvn package wildfly:deploy -->
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>${version.wildfly.maven.plugin}</version>
</plugin>
</plugins>
</build>
SECOND EDIT:
I discovered that one solution is to append ".war" to ${project.artifactId} in the build configuration, e.g.:
<finalName>${project.artifactId}.war</finalName>
and remove outputDirectory from the plugin configuration. So the build config should look like this:
<build>
<!--
Maven will make finalName the name of the generated war.
NOTE: Output directory of artifact:war exploded keeps losing the .war extension
http://youtrack.jetbrains.com/issue/IDEA-86484
http://youtrack.jetbrains.com/issue/IDEA-95162
The solution is to append ".war" to ${project.artifactId}, below:
-->
<finalName>${project.artifactId}.war</finalName>
<plugins>
<!-- Compiler plugin enforces Java 1.6 compatibility and activates annotation
processors -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
<configuration>
<!-- Java EE 7 doesn't require web.xml, Maven needs to catch up! -->
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- The WildFly plugin deploys your war to a local WildFly container -->
<!-- To use, run: mvn package wildfly:deploy -->
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>${version.wildfly.maven.plugin}</version>
</plugin>
</plugins>
</build>
DISCLAIMER: If you use this workaround just be aware that when you deploy an unexploded WAR artifact the file name will be named XXXX.war.war. It works -- I deployed the artifact as a WAR file in Intellij -- but it's ugly.
INFO [org.jboss.as.server.deployment] (MSC service thread 1-7) JBAS015876: Starting deployment of "XXXX.war.war" (runtime-name: "XXXX.war.war)"
If someone can tell me how to configure the Intellij project to work with Maven to select one or the other finalName values depending on whether I'm deploying a WAR file vs. exploded artifact then this question will be sufficiently answered.
<!-- Exploded artifact -->
<finalName>${project.artifactId}.war</finalName>
<!-- WAR file (unexploded) artifact -->
<finalName>${project.artifactId}</finalName>
There's a way to fix this in IntelliJ, without changing your pom.xml file(s), by adding an artifact with a reference to the exploded war (or in my case, the exploded ear) and it won't get stomped every time IntelliJ re-imports the maven pom(s). Here's how:
Stop/undeploy your current artifact deployment
Edit your run config, and in the Deployment tab, remove the current exploded war/ear artifact
Open the project's Artifacts settings and add a new artifact
Use the plus button to add a new war or (in my case) ear exploded artifact
Give it a name, then edit the Output directory to add the appropriate extension (.war or .ear)
In the Output Layout section where you see <output root>, use the plus button to add an Artifact
Select the desired exploded artifact
Edit your run config again, and in the Deployment tab, add the new workaround exploded artifact
Thanks to Nikolay Chashnikov for describing this in his comment on the bug report
Actually, you should leave the finalName attribute alone, otherwise you'll get the problems you describe. Rather, you should change the config for the maven war plugin to use the webappDirectory like this:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webappDirectory>${project.build.directory}/${project.artifactId}.${project.packaging}</webappDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
If we are talking about WAR inside EAR there is another way to resolve your problem by using correct configuration inside maven-ear-plugin. WAR pom.xml should be left as is, without any changes, but EAR pom.xml should contains something like this. (please, pay your attention to <unpack>${unpack.wars}</unpack>)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9</version>
<configuration>
<version>6</version>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<generateApplicationXml>false</generateApplicationXml>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
<modules>
<webModule>
<groupId>com.test.app</groupId>
<artifactId>test-app-war</artifactId>
<unpack>${unpack.wars}</unpack>
</webModule>
</modules>
</configuration>
</plugin>
and then you can add profiles default and debug for proper artifact assembling.
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<unpack.wars>false</unpack.wars>
</properties>
</profile>
<profile>
<id>debug</id>
<activation>
<property>
<name>debug</name>
</property>
</activation>
<properties>
<unpack.wars>true</unpack.wars>
</properties>
</profile>
</profiles>
use debug profile inside IntelliJ IDEA for expanding wars and default profile for building artifacts in command line or CI (default profile would be active if no profile were provided, so your build will works as previously).
With this solution HotSwap and resources updates works as expected.
Hope this helps.
I think it's the same as this question: IntelliJ Artifact has invalid extension
Add a .war extension to the output directory as shown in my answer: https://stackoverflow.com/a/25569266/968988

Is there a maven plugin to install the project?

I'm new with Maven, I just finished to read the Sonatype guide and I'm very satisfied by the functions that maven makes available. I created an application distribution (.zip) package and I would like to know if there is a manner to use maven as an installer.
I don't mean the installation that maven does into the local repository, what I mean is explained by the following example:
I've a folder with a jar file, an .sql script, a /lib and obviously a pom.xml file.
I would like that maven installs this project for me when I execute the "mvn" command.
So maven should:
- Copy the jar file in the ${TOMCAT_HOME}\webapps directory.
- Execute the sql script on the postgresql database
- Copy the \lib directory in c:\myLibs
- etc etc
During this process it should also make some checks (example TOMCAT_HOME is set on the system? Postgres is turned on? etc.) and ask to the user some parameter (example "The installation will reset the database do you want to continue?" or "Please insert the database password: ".
Is there a maven plugin that helps to do this? If not is there an application alike maven specialized to create "installer" ? Is it a standard, widespread application?
Thanks a lot for your help!
Try:
mvn deploy.
Add to your pom
<distributionManagement>
<repository>
<id>sonatype.internal</id>
<name>Internal Release Repository</name>
<url>http://sonatypeAddress:sonatypePort/context</url>
</repository>
</distributionManagement>
Plugins section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<configuration>
<tag>${build.tag}</tag>
<username>${scm.username}</username>
<password>${scm.password}</password>
</configuration>
</plugin>
antrun plugin - and make what you want.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<dependencies>
...
</dependencies>
<executions>
<execution>
<id>install</id>
<phase>install</phase>
<configuration>
<target>
<delete dir="mylocalization" />
<copy file="target/out/my.jar" tofile="mylocalication" />
<copy todir="mylocalization/doc">
<fileset dir="target/doc" />
</copy>
<copy todir="mylocalization/somethingMore">
<fileset dir="target/more">
<include name="a.txt" />
<include name="b*.txt" />
</fileset>
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
See also maven-wagon

Use Maven to Copy Files to WEB-INF Before WAR is Packaged

I have two servlet config files in my webapp, one for our normal environment (Heroku) and the other for WebLogic. I have a Maven profile for our WebLogic builds that should copy "servlet-context.xml.weblogic" to "servlet-context.xml". Everything appears to be working, except that the copy takes place AFTER the war file is built, so the correct servlet context doesn't get included in the package. What is the right build phase to use in the maven-antrun-plugin to get the copying done correctly?
Here is the relevant section of my POM.xml file:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<move
file="${project.build.directory}/${project.build.finalName}/WEB-INF/spring/appServlet/radio-context.xml.weblogic"
tofile="${project.build.directory}/${project.build.finalName}/WEB-INF/spring/appServlet/radio-context.xml"/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
This fails with the following error:
Failed to execute goal org.apache.maven.plugins:maven-antrun-plugin:1.3:run (default) on project radio: An Ant BuildException has occured: Warning: Could not find file C:\workspace\radio\target\radio-1.0.0-BUILD-SNAPSHOT\WEB-INF\spring\appServlet\radio-context.xml.weblogic to copy. -> [Help 1]
However, if I change the <phase> to package, the copy works, but after the war is built.
Any help would be appreciated.
As a reference, this page lists the Maven lifecycle phases.
The key phases you need to think about in your build are:
process-resources - where most of the files are placed into ${project.build.directory}
package - this is the phase where the WAR is built
BUT...
Looking at the documentation of the WAR plugin, the copying of WAR resources to ${project.build.directory}/${project.build.finalName} occurs in the war:war goal, which executes in the package phase also.
So let's take a step back. What you want to achieve is to use a different radio-context.xml file depending on your profile. Perhaps a better approach would be to configure the WAR plugin differently in your weblogic profile.
Have a separate webapp resource directory for your weblogic, put your custom radio-context.xml file in there, and only include that directory in the weblogic profile. e.g.
<project>
...
<profiles>
<profile>
<id>weblogic</id>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<webResources>
<resource>
<directory>src/main/webapp-weblogic</directory>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Try using process-resources, this copies your file before the war is built.

Installing a required Jar file and optionally a second jar file in Maven into the local repository

I have a product that contains a Jar file in its distribution and I have created a pom.xml that uses the install-file mojo to install the Jar into the local repository. So the user unpacks my zip file and types "mvn install" and everything works.
My problem is I have a second Jar file that I would also like to install using the same pom.xml, but this Jar file is optional and may or may not be present (the Jar file is downloaded separately by the user and placed in the same directory). I have tried install-file and also build-helper:attach-artifact and can't figure out how to do this within a single POM. I'm happy to have the user type some different command to install this Jar file, or have it work with "mvn install".
One possibility is to use a profile, which gets activated based on the existence of the second jar. This profile can be used to attach an additional artifact using the build helper maven plugin goal that you have referred above. Something like this...
<project>
...
<profiles>
<profile>
<id>second-jar</id>
<activation>
<file>
<exists>${basedir}/location/of/second.jar</exists>
</file>
</activation>
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>second</file>
<type>jar</type>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

Resources