maven-ear-plugin project property lookup fails - java

I have created simple ear project with filters. I want to use different settings for each environment, those settings should be passed to generated application.xml file in the form of env-entries. The generation of ear package is done with maven-ear-plugin as shown below:
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9</version>
<configuration>
<generateApplicationXml>true</generateApplicationXml>
<version>6</version>
<envEntries>
<env-entry>
<env-entry-name>customProperty</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>${custom.property}</env-entry-value>
</env-entry>
</envEntries>
<applicationName>${custom.property}</applicationName>
</configuration>
</plugin>
To do that I had to use another plugin properties-maven-plugin. It successfully reads properties from file and sets them as maven project properties, so I can insert them in pom.xml file using ${}. It works for most of the pom.xml elements (i.e. <applicationName>, unfortunately it is not successfully looked up when I place it inside env-entry element, where I need it. Below is generated application.xml.
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" version="6">
<application-name>default property</application-name>
<display-name>test</display-name>
<env-entry>
<env-entry-name>customProperty</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>${custom.property}</env-entry-value>
</env-entry>
</application>
It's probably a bug which should be issued at Maven Ear Plugin, but I don't have an account there. I'm also attaching archived maven project, if somebody would like to check that himself: test.zip.
Edit
I've managed to overcome this problem using maven-resource-plugin and filter application.xml file after it's created as user #skegg99 proposed. Since I cannot replace this file I had to copy it to META-INF directory. I does not look pretty, I know, but it solves the case for now. Here is additional markup for maven-resource-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<outputDirectory>${basedir}/target/${project.artifactId}-${project.version}/META-INF</outputDirectory>
<filters>
<filter>src/main/filters/${env}.properties</filter>
</filters>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
and also here:
<resources>
<resource>
<directory>${basedir}/target</directory>
<filtering>true</filtering>
<includes>
<include>application.xml</include>
</includes>
</resource>
</resources>
Whole project configuration can be downloaded from here.

With the current setup you have this may well be impossible.
I just took a brief look into the code where it states that the env entries are load through the PlexusConfiguration.
Without diving too deep into that code as well, I can't see that this part handles the entries any more special than "read XML, put into List".

Related

How to use pom.xml property in junit test class

I have declare a property in pom.xml
<PROPERTY_KEY>d:/../.../abc.properties</PROPERTY_KEY>
and then used
<plugin>
<configuration>
<replacements>
<replacement>
<token>APP_PROPERTY</token>
<value>${PROPERTY_KEY}</value>
....
</plugin>
and have used APP_PROPERTY in my dispatcher-servlet.xml and in controller classes as well. It's working fine as in this case control comes through web.xml and this web.xml has an entry for my dispatcher-servlet.xml.
But when I want to use this same APP_PROPERTY in my JUNI test class, it is not getting resolved.
I have to create a new dispatcher-servlet-test.xml file (and put it under /src/main/resources folder) as my actual dispatcher-servlet.xml is not working from JUnit test class. Now my JUnit test class is able to pick dispatcher-servlet-test.xml. But, it is not able to resolve properties (APP_PROPERTY) that I have defined in my pom.xml.
I'm using SpringJUnit4ClassRunner.class in my test class.
What should I do to get these property resolved?
Resources for tests need to live under src/test/resources, you should move your dispatcher-servlet-test.xml there. Once moved, it's likely not being filtered as a resource, the stanza you want is something like:
<build>
<resources>
<resource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/dispatcher-servlet-test.xml</include>
</includes>
</resource>
You may already have a similar stanza in your POM, or if you're working on a larger project the parent pom.xml may have a stanza declaring:
<filtering>true</filtering>

Why keys are not merged with "WEB-INF/classes/META-INF/MANIFEST.MF" using maven-war-plugin?

I am building an application and then merging some custom keys in the MANIFEST.MF file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifestEntries>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Build-Revision>${buildNumber}</Build-Revision>
</manifestEntries>
</archive>
</configuration>
</plugin>
I have 2 profiles, the production profile uses the following resource config:
<resources>
<resource>
<!-- "all" is used for all profiles, "development" and "production" -->
<directory>src/main/resources/all</directory>
</resource>
<resource>
<!-- "prod" is just used for "production" -->
<directory>src/main/resources/prod</directory>
</resource>
</resources>
A default MANIFEST.MF is located at src/main/resources/all/META-INF/MANIFEST.MF, which should be used as a base.
What do I expect?
I expect that the MANIFEST.MF is available at myproject.war/WEB-INF/classes/META-INF/MANIFEST.MF with "Build-Time" and "Build-Revision" updated according to the values provided. Then I will be able to access the MANIFEST.MF file at runtime to retrieve the "Build-Revision" key and handle caching stuff.
What happens instead?
What happens instead is that the MANIFEST.MF is created inside myproject.war/META-INF/MANIFEST.MF with the values updated, and in the WEB-INF location there is just a copy of the MANIFEST.MF without any key updated.
Why does WEB-INF/classes/META-INF/MANIFEST.MF is not updated through maven-war-plugin?
(I figured it out, it was my ignorance of how maven handles src/main/resources and the manifest file)
Maven creates a proper MANIFEST.MF file inside META-INF/ and uses it as the default convention path for a manifest, there is no need to create another one inside the src/main/resources folder, the default should be in the root.
If you remove the MANIFEST from src/main/resources (which would be copied to WEB-INF/classes/META-INF/MANIFEST.MF) you will have only one and will be able to access the META-INF/MANIFEST.MF from the application using:
request.getServletContext().getResourceAsStream( "/META-INF/MANIFEST.MF" );

Conditional inclusion of files in maven

I have a JEE6 web application project.The project structure is according to maven convention.
Now I have introduced additional web.xml files for this project.
So they are now stored in WEB-INF as below:
WEB-INF/
|__ A/web.xml
|__ B/web.xml
What is the maven way to build a war to include proper xml depending upon the property.
I know the how to add custom properties in maven.But I cannot find how to configure the maven plugin such that during the war file building it chooses the appropriate file.
Any hints/suggestions/maven best practices in such cases are most welcome.
Thanks!!
maven war plugin could be configured to add and filter some external resources. See http://maven.apache.org/plugins/maven-war-plugin/examples/adding-filtering-webresources.html.
So I would make 2 maven profiles with 2 war plugin configuration like this :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<webResources>
<resource>
<!-- this is relative to the pom.xml directory -->
<directory>src/main/webapp/WEB-INF/__A</directory>
<includes>
<include>web.xml</include>
</includes>
<targetPath>WEB-INF</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
<!-- repeat for your second profile -->
BUT I think a better solution (and if your project permits it) would be to keep only one web.xml file with some filtered properties inside. In this case, you should just configure your war plugin to enable some filtering like this :
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
</plugin>

Refer to Maven project paths from Java

I need to programmatically gather some paths inside a Maven project, in particular to refer to the project artifact.
Using
URL MyClass.class.getClassLoader().getResource(String name)
works for a path relative to the target/classes folder of the project, but since the artifact sits in the target folder it is not possible to reference it. A path like
System.getProperty("user.dir") + "/target"
does not convince me at all at least for the fact that the target folder name, while standard, is not safely portable.
Is there a Maven-aware library solution that exploits a relative path?
MavenProperties can be written to a manifest file using the maven archiver which is used by the maven war plugin or the maven jar plugin.
If you have a web app, then you can pass some information to the web.xml file, too.
This is an example of one of my projects:
from pom.xml:
------------------------------------------------
<properties>
<maven.build.timestamp.format>dd.MM.yyyy' 'HH:mm:ss</maven.build.timestamp.format>
<build-version>${env.SVN_REVISION}</build-version>
<build-date>${maven.build.timestamp}</build-date>
</properties>
.
.
.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<webResources>
<webResource>
<directory>${basedir}/src/main/webapp/WEB-INF</directory>
<includes>
<include>web.xml</include>
</includes>
<targetPath>WEB-INF</targetPath>
<filtering>true</filtering>
</webResource>
</webResources>
from web.xml:
------------------------------------------------
<context-param>
<param-name>BUILD_VERSION</param-name>
<param-value>${build-version}</param-value>
</context-param>
<context-param>
<param-name>BUILD_DATE</param-name>
<param-value>${build-date}</param-value>
</context-param>

If using maven, usually you put log4j.properties under java or resources?

Where should I put the log4j.properties file when using the conventional Maven directories?
src/main/resources is the "standard placement" for this.
Update: The above answers the question, but its not the best solution. Check out the other answers and the comments on this ... you would probably not shipping your own logging properties with the jar but instead leave it to the client (for example app-server, stage environment, etc) to configure the desired logging. Thus, putting it in src/test/resources is my preferred solution.
Note: Speaking of leaving the concrete log config to the client/user, you should consider replacing log4j with slf4j in your app.
Just putting it in src/main/resources will bundle it inside the artifact. E.g. if your artifact is a JAR, you will have the log4j.properties file inside it, losing its initial point of making logging configurable.
I usually put it in src/main/resources, and set it to be output to target like so:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<targetPath>${project.build.directory}</targetPath>
<includes>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
</build>
Additionally, in order for log4j to actually see it, you have to add the output directory to the class path.
If your artifact is an executable JAR, you probably used the maven-assembly-plugin to create it. Inside that plugin, you can add the current folder of the JAR to the class path by adding a Class-Path manifest entry like so:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.your-package.Main</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Now the log4j.properties file will be right next to your JAR file, independently configurable.
To run your application directly from Eclipse, add the resources directory to your classpath in your run configuration: Run->Run Configurations...->Java Application->New select the Classpath tab, select Advanced and browse to your src/resources directory.
Some "data mining" accounts for that src/main/resources is the typical place.
Results on Google Code Search:
src/main/resources/log4j.properties: 4877
src/main/java/log4j.properties: 215
The resources used for initializing the project are preferably put in src/main/resources folder. To enable loading of these resources during the build, one can simply add entries in the pom.xml in maven project as a build resource
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
Other .properties files can also be kept in this folder used for initialization.
Filtering is set true if you want to have some variables in the properties files of resources folder and populate them from the profile filters properties files, which are kept in src/main/filters which is set as profiles but it is a different use case altogether. For now, you can ignore them.
This is a great resource maven resource plugins, it's useful, just browse through other sections too.
When putting resource files in another location is not the best solution you can use:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<build>
For example when resources files (e.g. jaxb.properties) goes deep inside packages along with Java classes.
If your log4j.properties or log4j.xml file not found under src/main/resources use this PropertyConfigurator.configure("log4j.xml");
PropertyConfigurator.configure("log4j.xml");
Logger logger = LoggerFactory.getLogger(MyClass.class);
logger.error(message);
Add the below code from the resources tags in your pom.xml inside build tags.
so it means resources tags must be inside of build tags in your pom.xml
<build>
<resources>
<resource>
<directory>src/main/java/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<build/>

Categories