AVIO Consulting

Improving Your SOA 12c Maven Build

Aug 6, 2015 | BPM

When looking at updating our Ant based build and deployment scripts for 12c I decided to try out the new Maven plugins to see if we could achieve an equal level of functionality.  Mark Nelson has a great series of posts at his blog Red Stack and others have also written about the new 12c Maven plugins, but there were still some things that I found missing compared to our existing Ant scripts.  

Below are a few things you can do to improve a basic SOA 12c Maven build easily including:

  • Extending the sar-common POM to reduce the size of project specific POM files
  • Supporting multiple environments to support deploying to both local and remote environments easily
  • Fixing composite revision issues to allow using the maven version number as the composite revision

Extending the sar-common POM

The first thing I did was look at moving common portions of the POM file to the parent POM, sar-common.  Much of what goes into the generated POM file for each project should not change and can be moved to this common extension point.

The easiest way to being making these modifications is to create a file called sar-common-12.1.3-0-0.pom in a folder and put the following starter content in it:

<project 
xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi_schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.oracle.soa</groupId>
<artifactId>sar-common</artifactId>
<version>12.1.3-0-0</version>
<packaging>pom</packaging>
<parent>
<groupId>com.oracle.maven</groupId>
<artifactId>oracle-common</artifactId>
<version>12.1.3-0-0</version>
<relativePath></relativePath>
</parent>
</project>

Now to install this POM file in your local repository, overwriting the template that is installed by default you can execute the following Maven command:

mvn install:install-file -Dfile=sar-common-12.1.3-0-0.pom -DgroupId=com.oracle.soa -DartifactId=sar-common -Dpackaging=pom -Dversion=12.1.3-0-0

You should see output similar to the following:

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-install-plugin:2.3:install-file (default-cli) @ standalone-pom ---
[INFO] Installing /home/adesjard/maven/sar-common/sar-common-12.1.3-0-0.pom to
/home/adesjard/.m2/repository/com/oracle/soa/sar-common/12.1.3-0-0/sar-common-12.1.3-0-0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.407s
[INFO] Finished at: Thu Aug 06 08:26:44 CDT 2015
[INFO] Final Memory: 7M/239M
[INFO] ------------------------------------------------------------------------

Now that you have a base template and can install it to your local repository, let’s move some of the common properties out to the parent POM so that we know they are consistent across projects.  Your sar-common POM should now look like below:

<project 
xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi_schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.oracle.soa</groupId>
<artifactId>sar-common</artifactId>
<version>12.1.3-0-0</version>
<packaging>pom</packaging>
<parent>
<groupId>com.oracle.maven</groupId>
<artifactId>oracle-common</artifactId>
<version>12.1.3-0-0</version>
<relativePath></relativePath>
</parent>
<properties>
<appHome>${project.basedir}/..</appHome>
<oracleHome>/opt/oracle/12.1.3/oracle_home/soa</oracleHome>
<serverUrl>https://www.avioconsulting.com/:8001</serverUrl>
<user>weblogic</user>
<password>oracle1234</password>

<scac.input.dir>${project.basedir}/SOA</scac.input.dir>
<scac.output.dir>${project.basedir}/target</scac.output.dir>
<scac.input>${scac.input.dir}/composite.xml</scac.input>
<scac.output>${scac.output.dir}/out.xml</scac.output>
<scac.error>${scac.output.dir}/error.txt</scac.error>
<scac.displayLevel>1</scac.displayLevel>
<scatest.result>${scac.output.dir}/testResult</scatest.result>
<composite.name>${project.artifactId}</composite.name>
<input>${composite.name}</input>
</properties>

<build>
<sourceDirectory>${project.basedir}/SOA/SCA-INF/src/</sourceDirectory>
<outputDirectory>${project.basedir}/SOA/SCA-INF/classes/</outputDirectory>
</build>
</project>

You’ll notice above that some of the properties such as oracleHome, serverUrl, user and password all use hardcoded values still.  In the next section we will move these out to a properties file.

Now your project POM file can be reduced down like the one shown below.

<?xml version="1.0" encoding="UTF-8"?>
<project xsi_schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"

xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.avioconsulting</groupId>
<artifactId>SOAProject1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>sar</packaging>

<parent>
<groupId>com.oracle.soa</groupId>
<artifactId>sar-common</artifactId>
<version>12.1.3-0-0</version>
<relativePath></relativePath>
</parent>

<properties>
<composite.partition>default</composite.partition>
<overwrite>true</overwrite>
<forceDefault>true</forceDefault>
<regenerateRulebase>false</regenerateRulebase>
<keepInstancesOnRedeploy>false</keepInstancesOnRedeploy>
<composite.revision>${project.version}</composite.revision>
</properties>

<build>
<plugins>
<plugin>
<groupId>com.oracle.soa.plugin</groupId>
<artifactId>oracle-soa-plugin</artifactId>
<version>12.1.3-0-0</version>
<configuration>
<compositeName>${composite.name}</compositeName>
<compositeRevision>${composite.revision}</compositeRevision>
<revision>${composite.revision}</revision>
<composite>${scac.input}</composite>
<scacInputDir>${scac.input.dir}</scacInputDir>
<sarLocation>${scac.output.dir}/sca_${composite.name}_rev${composite.revision}.jar</sarLocation>
<serverUrl>${serverUrl}</serverUrl>
<input>${composite.name}</input>
</configuration>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.oracle.adf.library</groupId>
<artifactId>SOA-Designtime</artifactId>
<version>12.1.3-0-0</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle.adf.library</groupId>
<artifactId>SOA-Runtime</artifactId>
<version>12.1.3-0-0</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle.adf.library</groupId>
<artifactId>BPEL-Runtime</artifactId>
<version>12.1.3-0-0</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle.adf.library</groupId>
<artifactId>Mediator-Runtime</artifactId>
<version>12.1.3-0-0</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle.adf.library</groupId>
<artifactId>MDS-Runtime</artifactId>
<version>12.1.3-0-0</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle.adf.library</groupId>
<artifactId>BC4J-Service-Runtime</artifactId>
<version>12.1.3-0-0</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

Supporting Multiple Environments

Now that we have our common parent POM that we can extend, we will add support for deploying to multiple different environments.  With these changes you will now be able to maintain configurations for each environment such as a local VM, DEV, TEST and PROD and choose which to deploy and run tests on. 

First we need to capture a property that indicates which environment we will deploy to.  We will use the maven-enforcer plugin to require that a system property called env is passed on the command line.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>enforce-property</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>env</property>
<message>----------------------------------------
You must pass a value for the 'env' property!
Example: mvn -Denv=dev
----------------------------------------
</message>
</requireProperty>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>

Using this newly captured property we will now put our environment specific properties files in our application directory, inside a folder called env as show below:

Inside this properties file we will put the following:

soa.host=localhost
soa.port=8001
soa.deploy.url=http://${soa.host}:${soa.port}
soa.server=soa_server1
oracle.middleware.home=/opt/oracle/12.1.3/oracle_home
oracle.home=${oracle.middleware.home}/soa
weblogic.user=weblogic
weblogic.password=oracle1234

java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
java.naming.provider.url=t3://${soa.host}:${soa.port}/soa-infra
java.naming.security.principal=${weblogic.user}
java.naming.security.credentials=${weblogic.password}
dedicated.connection=true
dedicated.rmicontext=true

Now we will add the following plugins to our sar-common POM.  We will use the maven-resources-plugin to copy the properties file to a temporary location, replacing the tokens in the process and then use the properties-maven-plugin to load the properties file as project properties.  Finally we will use the maven-clean-plugin to remove the temporary directory before each build.

...
<plugins>
...
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>copy-project-properties</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.basedir}/tmp</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/../env</directory>
<includes>
<include>*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
</execution>
</executions>
<configuration>
<files>
<file>${project.basedir}/tmp/${env}.properties</file>
</files>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.6.1</version>
<configuration>
<filesets>
<fileset>
<directory>${project.basedir}/tmp</directory>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
...
</plugins>
<filters>
<filter>${project.basedir}/../env/${env}.properties</filter>
</filters>
...

 

We can now deploy to any environment that has a matching properties file easily using the following command:

mvn pre-integration-test -Denv=dev

The final step to supporting multiple environments is to support per environment configuration plans for our composites as well.  Instead of trying to maintain a separate configuration plan for each environment we will maintain a single configuration plan template, which we can then use in combination with our properties files to create the final configuration plan at deployment time.

To start we will generate a configuration plan from JDeveloper called configPlan.xml.  This will be placed in the SOAProject1 directory in our example, it is not placed within the SOA directory inside of the project.  We can then modify this configuration plan to use tokens in the same format as our projects file, such as ${soa.host}.  We can reference any of the properties in our properties file or in our Maven POM.

Next we will add another execution of the maven-resources-plugin to copy this file into our SOA directory before packaging the SAR file and replace the tokens in the process.

<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>copy-config-plan</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.basedir}/SOA</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>configPlan.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>

You now will have a fully working build that can both target different SOA environments and apply an environment specific configuration plan while only having to maintain one.

 

Fixing Composite Revision Issues

While testing the new sar-common build I found that the composite.revision property and the compositeRevision configuration on the SOA plugin were not working properly.  No matter what they were set to, even a hard coded value, the deployed composite was always version 1.0 even though the SAR file name contained the correct revision.  After additional testing and research on My Oracle Support I found that this is a known bug (20553998) which was reported against 12.1.3.0.2 and is not yet resolved.  In order to work around this issue I used the maven-replacer-plugin to update the revision in the composite.xml in the prepare-package phase of the build.  You can see in the below section from the sar-common POM how this is done:

<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.3</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<ignoreMissingFile>true</ignoreMissingFile>
<file>${scac.input}</file>
<xpath>//composite/@revision</xpath>
<token>^.*$</token>
<value>${composite.revision}</value>
</configuration>
</plugin> 

These enhancements to the standard POM files will give you a much cleaner and more configurable build process.