Conditional inclusion of files in maven - java

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>

Related

Include files from a JAR in a dependent project

I'd like to synchronize log4j and logback config files across multiple projects. I have one project (Project A) that contains the log4j and logback dependencies, along with the config files.
Project A
src/test/resources
log4j2.xml
logback-test.xml
Project B has a dependency on Project A. I would like to include the log config files in Project A's JAR and have them automatically put in a specific target folder in Project B when resolving Maven dependencies for Project B.
I have tried maven-jar-plugin in Project A but it doesn't seem to work for my purpose.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<includes>
<include>src/test/resources/log4j2.xml</include>
<include>src/test/resources/logback-test.xml</include>
</includes>
</configuration>
</plugin>
Any help would be appreciated.
Thanks!
UPDATE:
While Eugene's answer was accepted, I needed to add a <resources> entry so the log config files would be included in the packaged JAR.
<build>
<resources>
<resource>
<directory>src/test/resources</directory>
<includes>
<include>log4j2.xml</include>
<include>logback-test.xml</include>
</includes>
</resource>
</resources>
</build>
Executing mvn clean compile assembly:single deploy from Project A created and deployed the JAR with the log files included.
[INFO] --- maven-remote-resources-plugin:1.7.0:bundle (default) # project-a ---
[INFO] Writing META-INF/maven/remote-resources.xml descriptor with 2 entries
Executing mvn clean compile from Project B copied the files into the output directory
[INFO] --- maven-remote-resources-plugin:1.7.0:process (default) # project-b ---
[INFO] Preparing remote bundle com.my.projects:project-a:1.0-SNAPSHOT
[INFO] Copying 2 resources from 1 bundle.
You can use Apache Maven Remote Resources Plugin
This plugin is used to retrieve JARs of resources from remote
repositories, process those resources, and incorporate them into JARs
you build with Maven.
A very common use-case is the need to package certain resources in a
consistent way across your organization. For example at Apache, it is
required that every JAR produced contains a copy of the Apache license
and a notice file that references all used software in a given project
Define in Project A which resources you want to share or better create separate project for shared resources
<build>
<plugins>
<plugin>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.7.0</version>
<executions>
<execution>
<goals>
<goal>bundle</goal>
</goals>
</execution>
</executions>
<configuration>
<resourcesDirectory>src/test/resources/</resourcesDirectory>
<includes>
<include>log4j2.xml</include>
<include>logback-test.xml</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
Maven will create resources bundle file for sharing resources
${basedir}/target/classes/META-INF/maven/remote-resources.xml
<remoteResourcesBundle xsi:schemaLocation="http://maven.apache.org/remote-resources/1.1.0 https://maven.apache.org/xsd/remote-resources-1.1.0.xsd"
xmlns="http://maven.apache.org/remote-resources/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<remoteResources>
<remoteResource>log4j2.xml</remoteResource>
<remoteResource>logback-test.xml</remoteResource>
</remoteResources>
<sourceEncoding>UTF-8</sourceEncoding>
</remoteResourcesBundle>
See documentation
Configure other modules to use the shared resources
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.7.0</version>
<configuration>
<outputDirectory>[your output directory]</outputDirectory>
<resourceBundles>
<!--The resource bundles that will be retrieved and processed. For example: org.test:shared-resources:${project.version}-->
<resourceBundle>groupId:artifactId:version[:type[:classifier]]</resourceBundle>
</resourceBundles>
</configuration>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
See documentation
Alternative solution:
Apache Maven Dependency Plugin It can copy and/or unpack artifacts from local or remote repositories to a specified location.
It was described there Maven: Extract dependency resources before test
and there Use a dependency's resources?
UPDATE:
Example how to add resources:
<project>
...
<build>
...
<resources>
<resource>
<directory>[your folder 1 here]</directory>
</resource>
<resource>
<directory>[your folder 2 here]</directory>
</resource>
</resources>
...
</build>
...
</project>
See documentation
Please don't put logging configuration files into JARs, if someone depends on your JAR, your configuration may overwrite theirs. That depends on which JAR is loaded first
If you want, like this. And package them into JAR
src/main/resources
log4j2.xml
logback.xml

Distribute plugin resource files to host project

I have a maven plugin that exposes a Mojo, with a goal that runs at the compile stage. The project was generated using mvn archetype:generate, and the POM contains all the standard stuff that comes with running that, very little deviation. The project includes a couple of resource files, e.g. filea.txt and fileb.txt, that are packaged up as part of the jar.
When the plugin is used in a project, I'd like the files that are included in the jar to be extracted and copied to the target\test-classes directory of the host project. I'm trying to use the plugin jar to both distribute some files + expose some functionality that can then use those files.
Is this a valid approach, and if so, are there settings I can add to the plugin POM to indicate that content from the plugin should be extracted and copied? I want to centralise this logic in the plugin, rather than having to do in the plugin host.
I feel like it's something with maven-dependency-plugin or maven-resources-plugin or build-helper-maven-plugin:attach-artifact, have tried a couple of different approaches but think I'm missing something obvious:
e.g. something like this in plugin POM?
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<outputDirectory>${basedir}/target/test-classes</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>filea.txt</include>
<include>fileb.txt</include>
</includes>
</resource>
</resources>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.6.0</version>
</plugin>
// etc etc
Google fu has let me down, keep ending up on maven resources page. Can post directory structure / more information if needed.
Cheers
First I would suggest to put resources which needs to be distributed into src/main/resources which looks like you have done ...but remove the configuration for the maven-resources-plugin and let maven do it's work. This is automatically copied into target/classes/ which in result is packaged into the resulting jar later.
If your plugin needs to get those files those can accessed as a usual resource via this.getClass().getResourcesAsStream("/...") and reading and writing them into a new location preferable into target/...

Maven war and put the version number in the jars in WEB-INF/lib

If I have a war configuration which builds a standard war file with a WEB-INF/lib directory. The jar files come out as spring-core.jar. Is it possible to include the version number that are listed in the dependency list, e.g. I want to have a war with version numbers,
WEB-INF/lib/spring-4.3.8.RElEASE.jar
Instead of:
WEB-INF/lib/spring.jar
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<outputFileNameMapping>#{artifactId}#.#{extension}#</outputFileNameMapping>
<webResources>
<resource>
<directory>WebContent</directory>
</resource>
</webResources>
</configuration>
</plugin>
The default name is whatever it's called in the repository. You may have a configuration overriding this feature (such as stripVersion from the maven-dependency-plugin).
This question describes the process of renaming a single dependency:
Renaming Maven dependency in WAR's WEB-INF/lib folder.

Exclude application.properties when generating war using spring boot and spring-boot-maven-plugin

I am developing a web application using Spring Boot, and want to generate war instead of jar.
It works very fine using the conversion from jar to war described here : http://spring.io/guides/gs/convert-jar-to-war/
But I want to exclude the application.properties from the war, because I use #PropertySource(value = "file:${OPENSHIFT_DATA_DIR}/application.properties") to get the file path on production environment.
This method works when generating my war, but in eclipse I can't run my application because application.properties not copied at all to target/classes :
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>application.properties</exclude>
</excludes>
</resource>
</resources>
</build>
This method doesn't work at all, I think that spring-boot-maven-plugin doesn't support packagingExcludes :
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<packagingExcludes>WEB-INF/classes/application.properties</packagingExcludes>
</configuration>
</plugin>
</plugins>
</build>
Have you another suggestion?
Thanks
Try using the solution below. This will work:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
If you are using the above solution , while running the project in Eclipse IDE you may get error that the properties file is not found. To get rid of this you need to add the resources folder in Run as configuration.(Run configurations... -> Classpath -> User Entries -> Advanced... -> Add Folders)
When running in Eclipse, at your Run Configuration, you need to specify the path of the propeties to Spring Boot:
--spring.config.location=${workspace_loc:/YOURPROYECTNAME}/src/main/resources/
The solution I added is to unzip my packaged war, delete the file application.properties and create a new war named ROOT.war using maven-antrun-plugin and run some ant tasks.
this is what i added to my plugins in pom.xml :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>package</id>
<phase>package</phase>
<configuration>
<target>
<unzip src="target/${artifactId}-${version}.${packaging}" dest="target/ROOT/" />
<delete file="target/ROOT/WEB-INF/classes/application.properties"/>
<zip destfile="target/ROOT.war" basedir="target/ROOT" encoding="UTF-8"/>
<delete dir="target/ROOT"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
I named my target war as ROOT.war because I am using tomcat on openshift PaaS, so I just copy my ROOT.war and push to my openshift repo. That's it
What I understand from your question is, you want to use application.properties for your development. But you dont want to use it for production.
I would suggest using Spring profiles to achieve this.
In your properties file
Create a profile for development. Put all your development properties under it.
Do not create a profile for production in your properties file.
When you are developing, set active profile to development, so that the properties are loaded from your application.properties file.
When you run it in production, set active profile to Production. Though application.properties will be loaded into your WAR, since there is no profile for production, none of the properties will be loaded.
I have done something similar using YML. I am sure there must be a way to do the same thing using .properties file too.
spring:
profiles.active: development
--
spring:
profiles: development
something:
location: USA
unit1: Test1
unit2: Test2
You could change the profile in run time using
-Dspring.profiles.active=production
Try to using this solution:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.version}</version>
<configuration>
<addResources>false</addResources>
</configuration>
</plugin>
<addResources>false</addResources> will keep properties when you run mvn spring-boot:run

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