How to configure Maven profiles with different resources folders? - java

I'm trying to configure my application to have 2 build profiles: development and production. In order to do that, I created two subdirectories under the src/main/resources folder: src/main/resources/development and src/main/resources/production. Each subdirectory has its own .properties files.
<profiles>
<profile>
<id>development</id>
<build>
<resources>
<resource>
<directory>src/main/resources/development</directory>
</resource>
</resources>
</build>
</profile>
<profile>
<id>production</id>
<build>
<resources>
<resource>
<directory>src/main/resource/production</directory>
</resource>
</resources>
</build>
</profile>
</profiles>
I build the app with the command mvn install -P ${profile_here}
Maven copies the content of the folder related to the chosen profile to the WEB-INF/classes output directory, however the development and production folders are copied as well.
WEB-INF/classes
WEB-INF/classes/development
WEB-INF/classes/production
How can I solve this problem?
Thanks in advance.

The maven-war-plugin is rather limited when it comes to resources. However, you could use the maven-resources-plugin to include/exclude resources like described here: https://maven.apache.org/plugins/maven-resources-plugin/examples/include-exclude.html

Related

Copying and overwriting some resources with maven in a profile

I have two projects which are built from one maven multiproject, project A and project B. Project B recently came to live and differ only little from project A, namely it uses a couple of different configuration files. My idea was to create a profile for projectB and add additional configuration files / replace existing configuration files. I've tried several approaches on stackoverflow including copy-rename plugin and mvn dependency plugin. Part of the problem seems to be that both projects have a file with same config name.
My current/last approach was to use maven-resources-plugin in following way:
I created an additional directory: src/main/projectbresources and a projectbprofile:
<profile>
<id>projectb</id>
<activation><activeByDefault>false</activeByDefault></activation>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>copy-resources</id>
<!-- here the phase you need -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
<resources>
<resource>
<directory>src/main/projectbresources</directory>
<filtering>true</filtering>
</resource>
</resources>
<overwrite>true</overwrite>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
I have a file with same name in both src/main/resources and src/main/projectbresources however, no matter the profile I build with, always the file from src/main/resources is in the target folder. Additional files that are in projectbresources only are copied to target.
Based on your statement "Project B recently came to live and differ only little from project A, namely it uses a couple of different configuration files." I would say you don't need 2 separate projects. You can have only one project and based on activated profile choose different configurations. With this approach the configuration files for both cases can have same name but different content.
Your project structure will look like (as an example):
project root folder:
pom.xml
- src
-- main
--- resources-profileA
--- resources-profileB
Now, the pom.xml contains 2 profiles: profileA and profileB. Each profile define it's own build/resources.
<profiles>
<profile>
<id>projectA</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<resources>
<resource>
<directory>src/main/resources-profileA</directory>
</resource>
</resources>
</build>
</profile>
<profile>
<id>projectB</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<resources>
<resource>
<directory>src/main/resources-profileB</directory>
</resource>
</resources>
</build>
</profile>
</profiles>
More on that, you can make one profile active by default. This will help your dev environment to automatically use one. If you like to have a default active profile for that profile you can name the resource folder just resources (default maven name) and keep different name for second profile.
UPDATE:
To go 'easy' and only add some additional files, you can use for profile projectA the maven defaults and define onle a profile for projectB.
The project root folder become:
pom.xml
- src
-- main
--- resources
--- resources-profileB
and the pom.xml will contains only one profile inactive by default:
<profiles>
<profile>
<id>projectB</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<resources>
<resource>
<directory>src/main/resources-profileB</directory>
</resource>
</resources>
</build>
</profile>
</profiles>
How to build for the two profiles:
Build for no profile is equivalent of building for projectA:
mvn clean install
Buid for projectB profile will ignore resources in default folder and will use only resources defined in profile (src/main/resources-profileB).
mvn clean install -P projectB

how to manage a project which contains files specific to different OS?

we have a project which initially was developed to run on a linux platform, we want to customize it and use it under windows platform. It is hosted on github. Any advice on how to manage files that are shared between the two platforms but have some specificity for each one. for example configuration files that contains paths, environment variables and the like.
thanks for suggestion.
Since you have tagged maven here is the solution, use profiles to differentiate between linux and windows.
<profiles>
<profile>
<id>linux</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<envName>linux</envName>
</properties>
</profile>
<profile>
<id>windows</id>
<properties>
<envName>windows</envName>
</properties>
</profile>
</profiles>
<build>
<outputDirectory>${project.basedir}/target/classes</outputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.class</include>
</includes>
</resource>
<resource>
<targetPath>${project.basedir}/target/classes/configurations</targetPath>
<directory>${basedir}/src/main/resources/configurations/${envName}</directory>
</resource>
</resources>
<plugins>
</build>
Say suppose you have some configuration files specific to OS. and when you want to build based on the enivronment you want the file to copied to configurations directory inside class, the above code snippet copies that. For that to work you need to create 2 directories inside src/main/resoruces/configurations/linux and src/main/resources/configurations/windows. when you run maven you need to use profile like mvn package -Plinux or mvn package -Pwindows.

Placeholder not being changed when deploying maven project to tomcat

I got maven project with pom.xml in which I replace placeholder in one of configuration files according to profile as follows:
<properties>
<mq-server.host>127.0.0.1</mq-server.host>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources/config</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<profiles>
<profile>
<id>staging</id>
<properties>
<mq-server.host>local.staging.com</mq-server.host>
</properties>
</profile>
</profiles>
When I build project using maven all doing fine on the other hand my project is Web project that is synchronizing with local tomcat via eclipse plugin and when I'm running project on tomcat using "play" button in eclipse, placeholder is not being changed. I wonder how I can fix it without adding special file just for developer.

Scene.getStylesheets().add() not working inside jar file

As long as I run my project directly from Eclipse, I have no problem with that:
scene.getStylesheets().add(getClass().getResource("/stylesheet.css").toExternalForm());
But as soon as I run this code inside of a jar file, the resource is not found (NullPointerException).
I tried moving the css file to my src folder and then only stylesheet.cssas path instead of /stylesheet.css, but this leads to the same problem: Works fine using Eclipse, but not from the jar.
Hint: I am using Zonskis Maven JavaFX Plugin for generating the jar.
I just wasted my (your) time writing silly maven profiles.
instead of :
scene.getStylesheets().add(getClass().getResource("/stylesheet.css").toExternalForm());
simply write :
scene.getStylesheets().add("stylesheet.css");
This is how Zonski load css files.
Of course your stylesheet.css file should be in /src/main/resources, or somewhere on the CLASSPATH.
Move your file to src/main/resources and add your css file :
scene.getStylesheets().add(getClass().getClassLoader().getResource("stylesheet.css").toExternalForm());
Well, if you want to run it from the jar, then change stylesheet.css to stylesheet.bss ( binary css), package your application :
mvn clean compile jfx:build-jar
and run your jar.
java -jar app.jar
I have a ugly hack to make this a little usable (I'm using Netbeans,amazing maven integrity):
I create a project.properties file in src/main/resources directory,
file_css= ${file_css} // by default I use *.css file.
And make it filterable, in my POM file:
...
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>com.zenjava</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version> 1.5 </version>
<configuration>
....
</configuration>
</plugin>
</plugins>
</build>
...
And create two maven profiles, one for dev, and the other for production (packaging to jar):
<profiles>
<profile>
<id>production</id>
<properties>
<file_css>stylesheet.bss</file_css>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<file_css>stylesheet.css</file_css>
</properties>
</profile>
</profiles>
So, you load your css file like this :
scene.getStylesheets().add(getClass().getClassLoader().getResource(ResourceBundle.getBundle("project").getString("file_css")).toExternalForm());
I use production profile for packaging, and dev for usual actions like compile, test, run.
Edit:
a complete example is hosted on github.

Preventing context XML from being override in Tomcat 6

I am using JNDI to read database configuration from my application's context.xml. The way I currently have this setup is to have [appname].xml in conf/Catalina/localhost. However, when I redeploy the app, this file gets overridden with an empty context file, and I have to copy the custom one back to the conf/Catalina/localhost directory. I have different database settings, etc. for my test and production servers, and so don't want to put the context file in META-INF in the WAR file, but would like to just keep it in the conf/Catalina/localhost directory. Is this possible?
Is there somewhere better to put the database configuration?
I'd also like to avoid putting the configuration in the server.xml file, although I know this is possible.
Thanks!
I would say look into using maven profiles (one for prod, one for test), and having different resource definitions for each profile. You can keep your common files in src/main/resources and then have a folder for each profile type to keep specific config files in:
src/test/resources
src/prod/resources
Then you can amend your pom to define each profile and its associated resources:
<project>
<profiles>
<profile>
<id>prod</id>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<targetPath>${project.build.outputDirectory}</targetPath>
</resource>
<resource>
<directory>src/prod/resources</directory>
<targetPath>${project.build.outputDirectory}</targetPath>
</resource>
</resources>
</build>
</profile>
<profile>
<id>test</id>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<targetPath>${project.build.outputDirectory}</targetPath>
</resource>
<resource>
<directory>src/test/resources</directory>
<targetPath>${project.build.outputDirectory}</targetPath>
</resource>
</resources>
</build>
</profile>
</profiles>
</project>
finally you can build the war using the -Pprod or -Ptest profile argument to mvn
mvn -Pprod package
Problem is that undeploy removed the webapp specific context.xml file that was installed in Catalina/localhost/.xml
If you don't want to have the file removed, you'll have to just redeploy it, not undeploy/deploy

Categories