18

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?
hyde
  • 60,639
  • 21
  • 115
  • 176
  • A workaround I'm now using, is adding normal Java properties for a source and a destination file, and if these are present, the file is copied in `static{}` block before getting the instance of Logger. As long as this is the first `Logger.getLogger` call, the file copy is done before log4j reads the XML, and all works. But this is hardly a good solution, this is not an ideal place for such a copy... – hyde Dec 10 '12 at 12:11
  • @JohnYeary Do you have a reason to think this is maven-2 specific? – hyde Dec 12 '12 at 10:42
  • I was just going through a number of the NetBeans issues, and doing triage. I noted that you made specific mention of Maven 2, so I added an additional tag. – John Yeary Dec 12 '12 at 13:17
  • Disclaimer: I have never developed a Jenkins plugin so forgive me if I am totally out of context. From the example you give it looks Jenkins assumes the plugin to be a WAR artifact. Did you try to use a war packaging instead? – Alessandro Santini Dec 18 '12 at 07:03

4 Answers4

12

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).

Community
  • 1
  • 1
Andrew Swan
  • 13,427
  • 22
  • 69
  • 98
7

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

  • Thanks for the snippet, especially the part about profiles is invaluable. I will probably first try to do what I need with "standard plugins" so to say, without adding any extra 3rd party dependencies if possible. – hyde Dec 18 '12 at 11:45
3

You can use copy artifact plugin. As in hudson.

Rohit Kumar
  • 1,018
  • 3
  • 12
  • 23
  • Can you give link to maven "copy artifact" plugin, Google did not find one. Or did you mean http://maven.apache.org/plugins/maven-dependency-plugin/ instead? – hyde Dec 19 '12 at 08:22
  • I am not building and running under hudson/jenkins, I am building and running under NetBeans. In other words, there is no CI job (well, not related to this question), so I have no place to use that plugin. – hyde Dec 19 '12 at 08:36
  • 1
    This will help you much. http://stackoverflow.com/questions/586202/best-practices-for-copying-files-with-maven – Rohit Kumar Dec 19 '12 at 09:16
2

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>
hyde
  • 60,639
  • 21
  • 115
  • 176