tags:

views:

2087

answers:

6

I have a web app in maven, with the default directory structure. No problem there. The default directory structure has some files, property files that point to my localhost db.

currently i create an ant script to create different war files, one for production, one for development, using these commands

ant deploy-dev ant deploy-prod and deploy-sit ant deploy-uat

so basically they create a war file and then update the war file by pluging in the properties file

is there something like that in maven?

different war created depending on the configuration.

if so, how do i do that.

i tried

mvn war

it just creates a war

+1  A: 

There's this article about it on maven 2 using build profiles. It looks like it just delegates to ant anyways via the antrun plugin so you might even be able to get away with re-using your existing build.xml files.

seth
+1  A: 

I think that Maven WAR overlays could be your answer.

Stephen C
+3  A: 

If you want to delete ant from your process, I would look at using build profiles with filters.

In this scenario, plug your properties files into the src/main/resources tree structure. Then parameterize the properties file with filter properties like this:

jdbc.url=${filtered.jdbc.property}

Then inside src/main/filters create filter files based upon profiles. so you could have dev-filters.properties sit-filters.properties, etc. These contain:

filtered.jdbc.property=jdbc url here

Then you setup build profiles for each region where you set an env property pointing to the particular region your building. You can then setup the resources filter to use ${env}-filters.properties for each build. Additionally, you can setup the war plugin to add the env property to your artifact so that you actually store 4 different artifacts in your repository under a different classifier.

You then simply build the app with each profile. You have to call the build for each profile, but it does work well.

Example of some settings in the POM:

<build>
  <filters>
    <filter>src/main/filters/filter-${env}-application.properties</filter>
  </filters>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
  <plugins>
    <plugin>
      <artifactId>maven-war-plugin</artifactId>
      <version>2.1-beta-1</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>war</goal>
          </goals>
          <configuration>
            <classifier>${env}</classifier>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

<profiles>
  <profile>
    <id>LOCAL</id>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
      <env>LOCAL</env>
    </properties>
  </profile>
  <profile>
    <id>DEV</id>
    <properties>
      <env>DEV</env>
    </properties>
  </profile>
  <profile>
    <id>UAT</id>
    <properties>
      <env>UAT</env>
    </properties>
  </profile>
  <profile>
    <id>PROD</id>
    <properties>
      <env>PROD</env>
    </properties>
  </profile>
</profiles>

Also, props to this blog post which is where I originally found the steps to accomplish this.

Mike Cornell
This works, but I think it is much better to have one artefactdeploy everywhere, like Antony Stubbs suggests. In larger software projects you'll have many environments where you deploy the stuff (production, testing, development environment, each developermachine), and to build different WARs for each of those is a pain.
hstoerr
Well, it depends. Building a different war for each region is simple using Hudson. I just copy the configuration, create a new nightly build and change the profile it builds with. These builds are deployed to Nexus, which means if anyone wants it, they can pull from Nexus or look at Hudson to see what it does. If you're not using a CI system, I can see how it might be a pain.I find the risk to be very low as all I'm changing are properties files...Everything else is a jar that's been tested in a different Maven project.
Mike Cornell
+2  A: 

FYI best practice is to not have to rebuild your artifact for different environments - as that does not lead to re-produceable builds, and other things could potentially change when rebuilding. I.e. using resource-filtering, as suggested above, only works when re-building your project.

When you graduate an artifact from dev to test or acceptance test to production - you do not want to have to rebuild.

What you want to do, is actually have your configuration dynamic, dependent on run-time variables. I.e. different spring setups or properties files for differenent environemnts e.g: d

db-dev.properties
db-test.properties
db-prod.properties

Then you can switch between these configurations using run-time variables and Spring's PropertyPlaceholderConfigurer.

You can also actually use diferent spring configuration files as well, as I've done in the past, for more complex setups.

I also suggest you leave your 'default' setup as production - so that if you deploy to production, you don't need to worry if you forget to set the environment variable.

Antony Stubbs
A: 

This spells it out pretty well, uses the build profiles as @seth mentioned-

http://maven.apache.org/guides/mini/guide-building-for-different-environments.html

chrismarx
+1  A: 

I have handled this using Spring's PropertyPlaceholderConfigurer and including property files on the classpath and one on the filesystem:

<context:property-placeholder 
    location="classpath*:META-INF/spring/*.properties,file:myapp*.properties"/>

If there is a myapp*.properties file in the current directory when the app starts (or tests are run etc.) it will override properties from files baked into the war/ear/whatever.

David Tinker