I'm working with a Java/Maven project.
My version of Maven is "Apache Maven 2.2.1 (rdebian-10)".
I need to define some custom configuration when building the project. I'm used to C projects when you configure the project with various configuration flags (configure --this --that) and then the builds proceeds accordingly to the parameters defined/found by the configure script.
I need to emulate this feature with a Java/Maven project, a configuration system would be OK but also isolating the user specific parameters in a given file should be fine as well. For example I would like to be able to define per-user specific configurations in a file included by pom.xml (for example custom.pom.xml). For example in my project I need to specify the path where the program will write temporary files and such.
My question is, is it possible to isolate the per-user specific configuration in a file included by pom.xml, and/or what is the custom way to deal with this problem with Maven projects?
Right now I'm committing a pom.xml.template file, which needs to be renamed to pom.xml and edited with the user-specific parameters, but this is awkward because when the Maven requirement changes (e.g. if a new dependency is added) the developer must update his pom.xml file. This is the relevant snippet from my pom.xml.template file:
<profiles>
<profile>
<id>production</id>
<properties>
<database.url>jdbc:postgresql://localhost:5432/myProject</database.url>
<database.user>myProject</database.user>
<database.password>myProjectPassword</database.password>
<repository_path>my/project/repo/path</repository_path>
<external_tool_bin_path>/absolute/path/to/tool/</external_tool_bin_path>
<external_scripts_path>/path/to/scripts/</external_scripts_path>
<tmpdir>tmp</tmpdir>
</properties>
<build>
<finalName>myProject</finalName>
</build>
</profile>
[...]
External tool and scripts are located in per-user specific paths (depending on system/installation).
Another way would be to use distinct profiles for each developer, which is awkward in a different way (since I don't want to hardcode user profiles in the committed pom.xml file).
Alternatively I could write a configure script but this looks overkill, and not very portable, unless I want to require the user to rely on MinGW or similar.
Thanks in advance.
I suggest you use maven profiles, and the per user configuration, keep as environment variables which are referenced from the pom's profiles as ${env.PARAMETER}.
You will have to instruct the users to set their environment as needed.
This way, you can enjoy both features and not have user specific values in source control.
I hope this helps.
Related
currently I am using the Maven Resource plugin in a project in order to set some properties dependent on a specific Maven Build Profile (e.g. database settings for dev / productive environments). This works quite well.
However I want to set some "complex" structure dependent on the specified profile. In a specific Spring XML file I've got the following lines of XML to add some members to a distributed Hazelcast data-structure.
<hz:join>
<hz:tcp-ip>
<hz:member>192.168.178.37</hz:member>
</hz:tcp-ip>
</hz:join>
Depending on a specific Maven Profile and (maybe) with the help of the Maven Resource Plugin, I like to add dynamically more <hz:member> tags in this section.
For example: The dev profile has 4 members and the productive 12. I don't want to change this part every time I build a specific profile (and vice-versa).
So is there a possibility to do this via Maven Resource filtering? Or are there any other ideas to dynamically add those member tags depending on Maven profile at build time?
I am new to maven and read bit about profiles at this and other resources
What i understood we use profile if we want to do override some default values or do some specific stuff.
In my legacy project i can see below profile where i just see overriding app.mode property. But i do not see using this property
further any where in build. I am sure what special being done here?
<profiles>
<profile>
<id>dev</id>
<properties>
<app.mode>dev</app.mode>
</properties>
</profile>
</profiles>
Maven profiles can be configured however you want them to be. Here are some use cases:
a) The project has several developers. For political and religious reasons, some of the developers are using Windows and some are using Linux. The team develops two profiles, one for Linux and one for Windows, setting project root paths, temporary folder paths, support program paths. These variables are injected into the dependency-calculation process, and subordinate processes that need this information. These profile settings are put into the settings.xml file for each programmer.
b) One of the developers is on loan to the project for a week. She doesn't want to reconfigure her computer for the project standard directory layout, etc., so she creates her own settings.xml that allows her to work in her own root directory.
c) The project uses a continuous integration server, such Hudson or Jenkins. The CI needs to have its own database for integration testing, so it would perhaps have modes like "devtest" and "prodtest" and "fulltest", depending on the requirements.
The profile would be activated if you pass -Pdev on the command line to Maven.
mvn -Pdev
See http://maven.apache.org/guides/introduction/introduction-to-profiles.html.
What this profile does is change the setting of the property app.mode from whatever it was before to dev. You will want to search your pom file (and the poms of any modules) for uses of $[app.mode} to see what's happening -- if anything.
Maven properties do not pass into Spring automatically, but it's not uncommon to find configuration in to re-export them as system properties to make them visible to Spring. This typically happens in the configuration for surefire and failsafe, but it's explicit, you'll still see ${app.mode} in a pom somewhere.
If the property being set there isn't used anywhere else in the build (did you check any sub-modules?) then the answer to your question is "In this case it does nothing."
However, in general, setting a property like that will make it available later in the build in case you needed it for something. If I had to guess, I'd say that this is the result of either an incomplete cleanup of code, or premature optimization.
I think your expectation is correct. Its used to pass on app.mode parameter to spring. See
How can I use maven profile Id value in spring bean files?
http://spring.io/blog/2011/02/11/spring-framework-3-1-m1-released/
I'd like to have a plugin configuration that will not exist inside the pom.xml file (and also in any project files).
What I want to do is to have a plugin that will be used only by me on my workstation. Specifically, I want to deploy my project onto the Tomcat 7 container and for this I want to use Apache Tomcat Maven Plugin, but since different developers may want to use different servers or entire ways of deployment I don't want to put this configuration into the pom.xml.
Is it possible in Maven to have such global/user-specific plugin configuration?
There are several workarounds that I can think of.
in the pom.xml a specific set for where you define your way of deployment.
ex: mvn goal -P{PROFILE_NAME}
you can just put the plugin normally in pom.xml and just don't push the changes on the repository, so it won't be available for other developers.
But the assumption seems kind of wrong, if you many developers want to work on the same project they should use the same container for deployment for persistence or if you really want to do it like this, I think the cleanest way would be for every developer to use maven profiles. And in your local settings.xml (USER_HOME/.m2/settings.xml)
just set the profile as default:
(...)
<activeProfiles>
<activeProfile>{YOUR_USER_PROFILE}</activeProfile>
</activeProfiles>
(...)
so you don't need to always specify at command line when running mvn your user profile.
In most Java projects (Maven, Spring) I work on, I have the following requirements:
The packaged jar needs to run in multiple environments e.g. dev, beta, prod
The jar must not be rebuilt for each environment
Each environment requires different configuration properties
In development, I need to be able to easily switch between different environments in order to ensure that each environment is configured correctly, before deployment
So far, I have accomplished this by putting all configuration properties into separate properties files, one per environment. I then have Spring load in these files from the classpath. Then I simply alter the classpath at runtime to load in the needed properties.
This approach has worked well when I was using Eclipse since it is easy to setup multiple run configurations and alter the classpath for each one. Once this is done, switching environments is a matter of choosing the relevant run configuration.
Unfortunately, this is much harder to accomplish in IntelliJ because runtime dependencies can only be added to a module's configuration (as documented in this answer). If I try to set the classpath in the run configuration itself then this overrides all of modules dependencies, preventing the application from running at all (as documented here). Therefore, to switch environment, I must re-edit the modules dependencies every time.
Is there an easier way of achieving this with IntelliJ?
If not, is that because my configuration requirements, or my solutions to them, are unusual? In which case, is there a better way?
Previous Approaches
I have already tried and rejected a number of approaches:
Maven Profiles - These require rebuilding my jar whenever I want to switch environment. Apart from being annoying and dangerous, this seems entirely inappropriate for runtime configuration (but ideal for buildtime configuration). This seems like a great way to risk getting a broken build into production as you aren't testing against the same jar that actually gets deployed. Yuck!
Spring Profiles - These look much more appropriate but appear to require all configuration to be deployed with the jar and distinguished by filename e.g. dev.properties, prod.properties. You can then select which one you want by passing a variable at runtime. This is much better but I don't want my prod.properties to find their way into version control, nor get deployed with the jar itself. Therefore, it still seems necessary to modify the classpath in order to include them which I can't easily do in IntelliJ
When I ran in similar problems, I started loading my properties with a helper class. The helper class will look for a System property that contains either the environment or the absolute/classpath-relative path to load the properties from.
That way, the code is always the same and I don't have to change the project's configuration. I just use different launch configs that set different properties.
The main drawback here of course that test / dev configs leak into prod. With Maven, the simple solution is to move those into a new module and set the scope for it to provided. That way, the module will be visible inside of Maven but it won't be included during WAR packaging, etc.
I do something similar to what #AaronDigulla does but I overlay the properties. That is I first load all the properties from property files in the classpath (using Spring). Then I search for specific variable name and value (in the following order):
in servlet init parameters
then in system properties
finally then environment variables
This variable name and value contains the path of property files that will override/overlay the properties loaded from the classpath. Also each property loaded will perform the same type of resolution (that is system properties, environment variables and servlet init parameters override the properties from the property file).
Now all developers are pushed to use the default configuration that is in the classpath (ie use the same username/password for their database). Those that have different settings can use the above 3 different ways to override.
You can use the same bootstrapping configuration code that I use which will load all property files in classpath*:META-INF/spring/*.properties first then it will load all property files with the file/classpath URL set in the property/environment/init parameter variable called MyConfigParameter (if set).
Then finally after the property files are loaded it will set the Spring profiles by pulling the property/environment/init parameter called MyConfig.profiles (comma separated).
So in production you might set the environment variable MyConfigParameter=file://etc/myapp/*.properties.
Then in one of those property files you might set MyConfig.profiles=production,postgres which will set the Spring profile production and postgres.
Your Maven profiles for releasing/building on your build machine can obviously adjust the MyConfigParameter in the environment using System Properties. However you will have to tell surefire unit testing specifically about this property (especially if forking):
<!-- Surefire setup -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<printSummary>false</printSummary>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<systemPropertyVariables>
<MyConfigParameter>${MyConfigParameter}</MyConfigParameter>
</systemPropertyVariables>
</configuration>
</plugin>
<!-- Profile to change MyConfigParameter -->
<profiles>
<profile>
<id>release</id>
<activation>
<property>
<name>env</name>
<value>release</value>
</property>
</activation>
<properties>
<MyConfigParameter>file://etc/MyApp/*.properties</MyConfigParameter>
</properties>
</profile>
</profiles>
This question is not really about best practices or architecture, but about how to specifically configure Hudson and Maven to accomplish what I want. I'm a bit lost.
I have a Java application which uses SWT, and I need to build copies for different platforms. For now, all I need is Linux i386 and Linux amd64, but in the future, I need to add Windows x86/x64 as well, so I want to make sure I set it up "right" the first time around.
My application has all of the dependencies and other information listed in the Project pom.xml, including the different SWT jars to grab depending on OS, arch, and family.
My question is, how do I do builds for both linux i386 and linux amd64 with a minimal amount of configuration duplication? Right now I'm doing the following:
Project specifies all dependencies in pom.xml, and this project is set to build in Hudson and deploy the resulting .jar to Nexus
Builder-linux-i386 runs after Project and specifies any JNI files for i386 and uses the de.tarent maven-pkg-plugin to grab the project jar from Nexus and assemble it along with all dependencies into a single 'fat' jar file, and then into a .deb file for installation.
Builder-linux-amd64 does the same, but for amd64 files
I have been trying to specify which dependencies to use in the Builder projects by adding -P profilename to their Hudson projects, where profilename is a profile named in the Project pom. Maven doesn't seem to like this and prints that it is not activating that profile. It only uses the default profile from Project's pom.
What is the correct way to set this up? I want to have all of my dependencies specified in my Project pom, and have a Hudson project which compiles the jar for that project and deploy it to Nexus, and then independent projects which grab that jar and assemble it along with platform-specific files for release. I don't want to build the entire original project repeatedly, and I don't want to have a ton of duplicated configuration info or copy-pasted poms.
I have it working for unix-amd64 only because that's what the build machine is, so Maven targets that architecture. Also, I feel like the setup isn't as clean as it could be. Advice?
You have an syntax error. It needs to be -Pprofilename. It works for me this way.
Edit
Since the profile is read. There might be an syntax error in your profile configuration. I found a profile in one of projects, that I integrate into our CI environment. It defines some dependencies, it might help you.
<profile>
<id>junit</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>false</skip>
<testNGArtifactName>none:none</testNGArtifactName>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
Profiles should work in the way you desciped it (you could post an other question about this).
But at (least for web applications) there is an other way: Try to use classifier instead of profiles to build for different environments. -- You can have a look at this blog: http://blog.jayway.com/2010/01/21/one-artifact-with-multiple-configurations-in-maven/
The purpuse of this solution is, that you are able to build (if you want (controlled by an profile)) for all environments at once.
The builder projects do not see the profiles from the main Project because it is not actually a parent. I cannot define it as a in the builder projects because my projects are not set up that way, and I'm building using variables like ${SVN_REVISION}, which maven does not like.
I have given up and instead copy-pasted the profiles into the 'builder' projects. This isn't the prettiest but for now it works.