Friday, July 31, 2015

SOA Suite 12c: Collect & Deploy SCA composites & Service Bus artifacts using Maven

An artifact repository has many benefits for collaboration and governance of artifacts. In this blog post I will illustrate how you can fetch SCA composites and Service Bus artifacts from an artifact repository and deploy them. The purpose of this exercise is to show that you do not need loads of custom scripts to do these simple tasks. Why re-invent a wheel when Oracle already provides it?

This example has been created for SOA Suite 12.1.3. This will not work as-is for 11g and earlier since they lack Maven support for SOA Suite artifacts. In order to start using Maven to do command-line deployments, you need to have some Oracle artifacts in your repository. See http://biemond.blogspot.nl/2014/06/maven-support-for-1213-service-bus-soa.html on how to put them there. I have used two test projects which were already in the repository. A SCA composite called HelloWorld_1.0 and a Service Bus project also called HelloWorld_1.0. In my example, the SCA composite is in the GroupId nl.amis.smeetsm.composite and the Service Bus project is in the GroupId nl.amis.smeetsm.servicebus.

SCA Composite

Quick & dirty with few dependencies

I have described getting your SCA composite out of Nexus and into an environment on http://javaoraclesoa.blogspot.nl/2015/03/deploying-soa-suite-12c-artifacts-from.html. The process described there has very few dependencies. First you manually download your jar file using the repository API and then you deploy it using a Maven command like:

mvn com.oracle.soa.plugin:oracle-soa-plugin:deploy -DsarLocation=HelloWorld-1.0.jar -Duser=weblogic -Dpassword=Welcome01 -DserverURL=http://localhost:7101 

In order for this to work, you need to have a (dummy) pom.xml file in the current directory. You cannot use the project pom file for this.

The only requisites (next to a working Maven installation) are;
  • the sar file
  • serverUrl and credentials of the server you need to deploy to
Notice that you do not even need an Oracle home location for this. In order to build the project from sources however, you do need an Oracle home.

Less quick & dirty using Maven

An alternative to the previously described method is to use a pom which has the artifact you want to deploy as a dependency. This way Maven obtains the artifact from the repository (configured in settings.xml) for you. This is also a very useful method to combine artifacts in a greater context such as for example a release. The Maven assembly plugin (which uses the configuration file unit-assembly.xml in this example) can be used to specify how to treat the downloaded artifacts. The format 'dir' specifies that the downloaded artifacts should be put in a specific directory as-is (not zipped or otherwise repackaged). Format 'zip' will (surprise!) zip the result so you can for example put it in your repository or somewhere else. The dependencySet directive indicates which dependencies should go to which directory. When combining Service Bus and SOA artifacts in a single pom, you can use this information to determine which artifact should be put in which directory and this can then be used to determine which artifact should be deployed where.

You can for example use a pom.xml file like:

 <?xml version="1.0" encoding="UTF-8"?>  
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0               http://maven.apache.org/maven-v4_0_0.xsd">  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>nl.amis.smeetsm.unit</groupId>  
      <artifactId>HelloWorld_1.0</artifactId>  
      <packaging>jar</packaging>  
      <version>1.0</version>  
      <name>HelloWorld_1.0</name>  
      <url>http://maven.apache.org</url>  
      <dependencies>  
           <dependency>  
                <groupId>nl.amis.smeetsm.composite</groupId>  
                <artifactId>HelloWorld_1.0</artifactId>  
                <version>1.0</version>  
                <type>jar</type>  
           </dependency>  
      </dependencies>  
      <build>  
           <plugins>  
                <plugin>  
                     <artifactId>maven-assembly-plugin</artifactId>  
                     <version>2.5.4</version>  
                     <configuration>  
                          <descriptors>  
                               <descriptor>unit-assembly.xml</descriptor>  
                          </descriptors>  
                     </configuration>  
                </plugin>  
           </plugins>  
      </build>  
 </project>  

With a unit-assembly.xml file like

  <assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"  
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">  
      <id>unit</id>  
      <formats>  
           <format>dir</format>  
      </formats>  
      <dependencySets>  
           <dependencySet>  
                <outputDirectory>/unit/composite</outputDirectory>  
                <includes>  
                     <include>nl.amis.smeetsm.composite:*</include>  
                </includes>  
           </dependencySet>  
      </dependencySets>  
 </assembly>  

Using this method you also need the following in your settings.xml file so it can find the repository. In this example I have used a local Nexus repository.

 <mirror>  
      <id>nexus</id>  
      <name>Internal Nexus Mirror</name>  
      <url>http://localhost:8081/nexus/content/groups/public/</url>  
      <mirrorOf>*</mirrorOf>  
 </mirror>   

And then in order to obtain the jar from the repository

mvn assembly:single

And deploy it the same as described above only with a slightly longer location of the sar file.

mvn com.oracle.soa.plugin:oracle-soa-plugin:deploy -DsarLocation=target/HelloWorld_1.0-1.0-unit/HelloWorld_1.0-1.0/unit/composite/HelloWorld_1.0-1.0.jar -Duser=weblogic -Dpassword=Welcome01 -DserverURL=http://localhost:7101  

Thus what you need here (next to a working Maven installation) is;
  • a settings.xml file containing a reference to the repository (you might be able to avoid this by providing it command-line)
  • a specific pom with the artifact you want to deploy specified as dependency
  • serverUrl and credentials of the server you want to deploy to
Service Bus

For the Service Bus in general the methods used to get artifacts in and out of an artifact repository are very similar to the SCA composites.

Getting the Service Bus sbar from an artifact repository to an environment does require the projects pom file since you cannot specify an sbar file directly in a deploy command. The command to do the actual deployment also differs from deploying a SCA composite. You do require an Oracle home for this.

mvn pre-integration-test -DoracleHome=/home/maarten/Oracle/Middleware1213/Oracle_Home -DoracleUsername=weblogic -DoraclePassword=Welcome01 -DoracleServerUrl=http://localhost:7101

You can also use a method similar to the one described for the SCA composites. Mind though that you need the project pom file also as a dependency.

 <?xml version="1.0" encoding="UTF-8"?>  
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0               http://maven.apache.org/maven-v4_0_0.xsd">  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>nl.amis.smeetsm.unit</groupId>  
      <artifactId>HelloWorld_1.0</artifactId>  
      <packaging>jar</packaging>  
      <version>1.0</version>  
      <name>HelloWorld_1.0</name>  
      <url>http://maven.apache.org</url>  
      <dependencies>  
           <dependency>  
                <groupId>nl.amis.smeetsm.servicebus</groupId>  
                <artifactId>HelloWorld_1.0</artifactId>  
                <version>1.0</version>  
                <type>sbar</type>  
           </dependency>  
           <dependency>  
                <groupId>nl.amis.smeetsm.servicebus</groupId>  
                <artifactId>HelloWorld_1.0</artifactId>  
                <version>1.0</version>  
                <type>pom</type>  
           </dependency>  
      </dependencies>  
      <build>  
           <plugins>  
                <plugin>  
                     <artifactId>maven-assembly-plugin</artifactId>  
                     <version>2.5.4</version>  
                     <configuration>  
                          <descriptors>  
                               <descriptor>unit-assembly.xml</descriptor>  
                          </descriptors>  
                     </configuration>  
                </plugin>  
           </plugins>  
      </build>  
 </project>  

And a unit-assembly.xml like;

  <assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"  
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">  
      <id>unit</id>  
      <formats>  
           <format>dir</format>  
      </formats>  
      <dependencySets>  
           <dependencySet>  
                <outputDirectory>/unit/servicebus</outputDirectory>  
                <includes>  
                     <include>nl.amis.smeetsm.servicebus:*</include>  
                </includes>  
           </dependencySet>  
      </dependencySets>  
 </assembly>  

Thus what you need here (next to a working Maven installation) is;
  • an Oracle home location
  • a settings.xml file containing a reference to the repository (you might be able to avoid this by providing it command-line)
  • a specific pom with the artifact specified as dependency (this will fetch the sbar and pom file)
  • serverUrl and credentials of the server you want to deploy to
Deploy many artifacts

In order to obtain large amounts of artifacts from Nexus and deploy them, it is relatively easy to create a shell script, for example something like the one below. The script below uses the structure created by the above described method to deploy artifacts. It has a part which first downloads a ZIP, unzips it and then loops through deployable artifacts and deploys them. The script depends on a ZIP in the artifact repository with the specified structure. In order to put the unit in Nexus,  replace 'dir' with 'zip' in the assembly file and deploy the unit. You are creating a copy of the artifact though so you should probably use the pom and assembly directly for creating the unit of artifacts and loop over them without the step in between of creating a separate ZIP of the assembly.

The local directory should contain a dummypom.xml for the SCA deployment. The script creates a tmp directory, downloads the artifact, extracts it, loops over its contents, creates a deploy shell script and execute it. Separating assembly (deploy_unit.sh) and actual deployment (deploy_script.sh) is advised. This allows you to rerun the deployment or continue from a certain point where it might have failed. The assembly can be handed to someone else (operations?) to do the deployment.

dummypom.xml:

 <?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="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>nl.amis.smeetsm</groupId>  
      <artifactId>DummyPom</artifactId>  
      <version>1.0</version>  
 </project>  

deploy_unit.sh

The script has a single parameter. The URL of the unit to be installed. This can be a reference to an artifact in a repository (if you have your unit as a separate artifact in the repository). The script is easily updated to use a local file or structure as described above.

 #!/bin/sh  
   
 servicebus_hostname=localhost  
 servicebus_port=7101  
 servicebus_username=weblogic  
 servicebus_password=Welcome01  
 servicebus_oraclehome=/home/maarten/Oracle/Middleware1213/Oracle_Home/  
 composite_hostname=localhost  
 composite_port=7101  
 composite_username=weblogic  
 composite_password=Welcome01  
   
 if [ -d "tmp" ]; then  
  rm -rf tmp  
 fi  
 mkdir tmp  
 cp dummypom.xml tmp/pom.xml  
 cd tmp  
   
 #first fetch the unit ZIP file  
 wget $1  
 for f in *.zip  
 do  
  echo "Unzipping $f"  
  unzip $f  
 done  
   
 #deploy composites  
 for D in `find . -type d -name composite`  
 do  
  echo "Processing directory $D"  
  for f in `ls $D/*.jar`  
  do  
   echo "Deploying $f"  
   URL="http://$composite_hostname:$composite_port"  
   echo "URL: $URL"  
   echo mvn com.oracle.soa.plugin:oracle-soa-plugin:deploy -DsarLocation=$f -Duser=$composite_username -Dpassword=$composite_password -DserverURL=$URL >> deploy_script.sh  
  done  
 done  
   
 #deploy servicebus  
 for D in `find . -type d -name servicebus`  
 do  
  echo "Processing directory $D"  
  for f in `ls $D/*.pom`  
  do  
   echo "Deploying $f"  
   URL="http://$composite_hostname:$composite_port"  
   echo "URL: $URL"  
   echo mvn -f $f pre-integration-test -DoracleHome=$servicebus_oraclehome -DoracleUsername=$servicebus_username -DoraclePassword=$servicebus_password -DoracleServerUrl=$URL >> deploy_script.sh  
  done  
 done  
   
 ./deploy_script.sh  
   
 cd ..  
 rm -rf tmp  

For this example I created a very basic script. It does require a Maven installation, a settings.xml telling where the repository is and an Oracle home location (Service Bus requires it). Also it has some liabilities, for example in the commands used to find the deployable artifacts. It does give an idea though on how you can easily deploy large amounts of composites using relatively little code by leveraging Maven commands. It also illustrates the difference between SCA composite and Service Bus deployments.

Finally

You can easily combine the assembly files and pom files for the SCA composites and the Service Bus to create a release containing both. Deploying them is also easy using a single command. I also illustrated how you can easily loop over several artifacts using a shell script. I have not touched the usage of configuration plans and how to efficiently group related artifacts in your artifact repository. Those will be the topic of a next blog post.