Parametrize webapp using Jenkins, Maven and JVM parameters - java

Two objectives:
I want to use parametrized jenkins builds to build a war file and set some properties during the build in the war file.
I also want to be able to refine those properties on the server, where the war file is deployed.
Number 1 is to set properties that fit to the target environment, Number 2 is to be able to quickly change them without having to rebuild the whole application again.
Choosing a maven profile is not flexible enough in this case.
An example would be a port number, that is different for every build, but can spontaneously be changed by the system administrator of the system where the file is deployed.
My idea was to use the maven-resource-filtering plugin to add the build parameters on build into property files. Then on startup of the webapp on the glassfish/tomcat to also look at the set JVM variables.
Am I thinking in the right direction?

After some research the solution for me looks as followed,
for a given parameter "test":
To objective 1.: Use command line parameters when executing maven build, e.g use:
install -Dtest=OnBuildValue
Then use the maven resources plugin, that replaces strings like test=${test} in property files, through the given parameter on build. Add:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven.resources.version}</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
...
<build>
...
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/parameters.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
....
</build>
To objective 2.: To be able to change the parameter "test" in the container, without having to rebuild the war file, add a JVM parameter -DTEST=ContainerValue.
Now we need some logic:
private static String getBuildParameter(String paramName)
throws IOException {
Resource resource = new ClassPathResource(
"/META-INF/spring/parameters.properties");
Properties props = PropertiesLoaderUtils.loadProperties(resource);
return props.getProperty(paramName);
}
public static String getParameter(final String paramName,
final String defaultValue, final String logMessage) {
String value = System.getProperty(paramName);
if (value!=null) {
Logger.getLogger(ParameterManager.class.getName()).log(
Level.WARNING,
"Parameter: " + paramName + ": " + value
+ " found in JVM parameters.");
return value;
}
try {
value = getBuildParameter(paramName.toLowerCase());
} catch (IOException e) {
// catch, log exception...
}
if (value!=null) {
Logger.getLogger(ParameterManager.class.getName()).log(
Level.WARNING,
"Parameter: " + paramName + ": " + value
+ " found in parameters set on build time.");
return value;
}
Logger.getLogger(ParameterManager.class.getName()).log(
Level.WARNING,
"Parameter: " + paramName + ": " + defaultValue
+ " as default parameter. " + logMessage);
return defaultValue;
}
The methods are static because I use them to initialize constants like this:
public static final String TEST_STRING;
static {
TEST_STRING = getParameter("TEST", "default value",
"The default is set, please ensure, that this is intended!");
}
Those constants can then be read from everywhere inside your project. How you call this logic, or if you can implement it differently is up to you. I'm sure there are nicer ways, and I would be glad to hear about your implementation, but this works for me.
Note to 1.:
If you use Eclipse you can define the maven parameters under Run->Run configurations-> Goals.
BUT if you use the glassfish tools (m2e plugin) to deploy your project to your glassfish, it will not use the run configuration. You then have to create the file .m2/settings.xml looking like this:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd>
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors/>
<proxies/>
<profiles>
<profile>
<id>m2e</id>
<activation>
<property>
<name>m2e.version</name>
</property>
</activation>
<properties>
<test>xmlparameter</test>
</properties>
</profile>
</profiles>
<activeProfiles/>
</settings>

Related

Maven Filtering parameters in file

I have been looking over the maven war plugin and how to configure it. Here is my situation. I have a web application that is distributed to several production facilities. There are two files, in this web app, that are customized for each facility. These are /js/config.js and /META-INF/context.xml.
I have my project in a typical maven structure:
/src
|--/main
|--webapp
|--/js
|--config.js
|--properties
|--plant.properties
|--/META-INF
|--context.xml
I've left out non-essential directories for brevity.
The config.js has been altered to contain "parameter" I want substituted:
var Config {
...
system_title: '${plant_name} - Audit System',
...
}
The relevant portion of my pom is:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<filters>
src/main/webapp/js/properties/fayetteville.properties
</filters>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<directory>src/main/webapp/js</directory>
<filtering>true</filtering>
<exclude>**/properties</exclude>
</resource>
</webResources>
</configuration>
</plugin>
When I run "mvn clean package", I would expect to see ${plant_name} replaced with what is in my properties file. In this case, my properties file contains a single key-value pair:
plant_name=Austin
But I am not seeing the substitution. The resulting config.js in the target folder still contains ${plant_name} as does the config.js in the resulting war file.
I really don't want to use profiles if possible. Eventually, I want the build process to use a list of properties files to do this for all plants.
From my research, including a number of SO questions and answers, I feel I have things configured correctly.
What might I be doing wrong?

Netbeans Platform: InstalledFileLocator

I added a resource for a module as follows:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>nbm-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<moduleType>eager</moduleType>
<nbmResources>
<nbmResource>
<directory>${basedir}/resources</directory>
<targetPath>resources</targetPath>
<includes>
<include>*.db</include>
</includes>
<excludes>
<exclude>*trace*</exclude>
</excludes>
</nbmResource>
</nbmResources>
</configuration>
</plugin>
The file shows in the Netbeans application at: target/app name/app name/resources/card_manager.mv.db. That looks fine.
Now I'm trying to get that file location as follows:
File db = InstalledFileLocator.getDefault().locate("card_manager.mv.db",
"module.codename.base", false);
But db is always null. Any idea?
Try this code...
File file = InstalledFileLocator.getDefault().locate("myfile", null, false);
if (file == null)
{
file = new File(Places.getUserDirectory() + File. separator + "myfile");
}
Or have you tried resources/card_manager.mv.db? I'm sure the application path (app name) and cluster name (second app name) is excluded from locate() but I believe you have to include resources/ path.
Modify your pom so that the card_manager.mv.db is copied to the classes folder rather than the resources folder and fetch the file from your classloader.

Getting maven project version and artifact ID from pom while running in Eclipse

I was looking up how to get the application name(artifact id) and version from maven pom or manifest when I came across this question Get Maven artifact version at runtime.
The above works for me when I package the project but I can't seem to get anything to work when I try to run the program using eclipse. I tried using the .properties method when building since I assumed that is not package dependent but I am still not getting a result. If anyone has an idea or solution to this problem it would be greatly appreciated.
My last attempt is below. This uses the manifest when packaged(which works) and trying to get the .properties file when running in eclipse.
String appVersion = getClass().getPackage().getImplementationVersion();
if(appVersion == null || "".equals(appVersion)) {
appVersion = Glob.getString(appVersion);
if(appVersion == null || "".equals(appVersion)) {
System.exit(0);
}
}
Create a property file
src/main/resources/project.properties
with the below content
version=${project.version}
artifactId=${project.artifactId}
Now turn on maven resource filtering
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
so that this file is processed into
target/classes/project.properties
with some content similar to this
version=1.5
artifactId=my-artifact
Now you can read this property file to get what you want and this should work every time.
final Properties properties = new Properties();
properties.load(this.getClassLoader().getResourceAsStream("project.properties"));
System.out.println(properties.getProperty("version"));
System.out.println(properties.getProperty("artifactId"));
An easy solution with maven 4 is now to add a VersionUtil static method in your package:
package my.domain.package;
public class VersionUtil {
public static String getApplicationVersion(){
String version = VersionUtil.class.getPackage().getImplementationVersion();
return (version == null)? "unable to reach": version;
}
}
The thing is you need this ´mave-war-plugin´ in the project's pom, saying you want to add addDefaultImplementationEntries:
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
...
Then call the VersionUtil.getApplicationVersion() from some place in your code.

maven 3.2.3 fails to import resources correctly

I have a project that uses maven profiles to set a properties file so I can use different properties for different environments.
With maven version 3.2.1 (default version bundled with Eclipse Luna) this all works swimmingly. However, I downloaded the latest version of maven, 3.2.3, and when I set that as my maven version, it all blows up. The values are read as empty strings.
Should I submit a Maven bug for this? I couldn't find anything in the release notes for 3.2.2 or 3.2.3 that looked like it should've caused this.
Here's the profile:
<profile>
<id>dev</id>
<build>
<resources>
<resource>
<directory>src/main/config/local</directory>
</resource>
</resources>
</build>
</profile>
Then I use Spring to add the file to the classpath:
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
PropertySourcesPlaceholderConfigurer props = new PropertySourcesPlaceholderConfigurer();
props.setLocations(new Resource[] { new ClassPathResource("service.properties") });
return props;
}
And eventually import its values:
#Value(value = "${db.username}")
private String DB_USERNAME;
I encountered some simliar problems, when upgrading. For me it was resolved by not only declearing the directory, but as well providing an excplicit
<includes>
<include>myFile.properties</include>
</includes>
It seems like everything that is not explicitly included is implicitly excluded.
I dunno if this is a bug or a feature :)

How to switch conf tomcat with maven

I have ,in a java high envirgure project using Maven, to add integrations test. To do that, I must add a new test's database (minimalist true copy of the database). Until then it's good.
By against the problem is that I have two differents configurations in my file:
\web\target\tomcat\conf\context.xml
So I always put a ressource in a comment.
exemple of ressource :
<Resource
auth = "jdbc / soarepo"
driverClassName = "oracle.jdbc.driver.OracleDriver"
logAbandoned = "true"
maxActive = "32"
maxIdle = "32"
maxWait = "10000"
name = "jdbc / soarepo"
password = "..."
username = "..."
removeAbandoned = "true"
removeAbandonedTimeout = "60"
type = "javax.sql.DataSource"
url = "jdbc: oracle: thin: # ..."
/>
Q: How do I switch from one to another ressource with Maven?
I already use a profile for integration tests. So I have to change what resources when the profile is called ?
If you are using the Maven Tomcat Plugin to run your web application, you can specify the path of a custom server-dependent deployment descriptor, context.xml, using the contextFile property:
<profiles>
<profile>
<id>integration-tests</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<contextFile>/path/to/context/file</contextFile>
</configuration>
</plugin>
</plugins>
</build>
</profile>
.. Other profiles ..
</profiles>

Categories