Add client certificate for outgoing OSB call

Simple use case……you want to connect to a customer system over the internet. The customers system has an API but requires 2-way SSL. This means we have to send a client certificate along to make sure the SSL handshake can be completed. If your server has already a server certificate installed, it will send this one along by default but the customers system won’t accept it as it is different then what it trusts. In the next section, I will explain how to add a client certificate to an outgoing OSB call.

SSL

Let’s say I want to connect to my favourite climbing shop www.mountaingear.com as they have a nice backend api to take orders. The guys from mountaingear.com created a certificate for me to send along with the call.

First I am going to generate a keystore with a private key in it, to simulate the certificate which the third party gave to me.

keytool -genkey -keyalg RSA -alias climber -keystore keystore.jks -storepass password -validity 360 -keysize 2048

If I open the created JKS using keystore explorer I see a keypair we just created.

MyCertificate

Copy the jks to my OracleHome say ORACLE_HOME/keystores.

The next thing we have to do is to create an PrivateKeyInfrastructure Provider. Go to weblogic console and then:

  • Security Realms
  • myrealm
  • Providers
  • Credential Mapping
  • New –> Set your name here. Mine is MountainGearPKIProvider. Set the type to PKICredentialMapper. Click OK to finish.

PKIProvider

Restart the Admin server for the changes to take effect.

When the admin server has restarted we are going to configure the PrivateKeyInfrastructure Provider we just created. Go to weblogic console and then:

  • Security Realms
  • myrealm
  • Providers
  • Credential Mapping
  • MountainGearPKIProvider
  • Provider Specific –> KeystoreType = JKS, Keystore File Name = The location of your just created jks…mine is G:\Oracle\Middleware\OracleHome\keystore\MountainGear.jks, KeyStorePassphrase = password, Confirm KeyStorePassphrase = password. Click Save to finish
    • PKIProviderConfiguration

      Restart the Admin server again for the changes to take effect.

      After this, go to the SBConsole and start a new session. In a project, create a folder which will hold the ServiceKeyProvider. Mine will be in my Accounts project. Create a ServiceKeyProvider in this new folder and select using SSL Client Authentication the right certificate. Set the password, save it and activate it.

      ServiceKeyProvider

      The reason why we do this in the OSB console is that it cannot resolve the PKIProvider in JDeveloper. The only work around is to create it on the server and then export your project and import it into JDev. After you have done this, you can see your ServiceKeyProvider.

      The last step now is to make sure it is send along with a flow. The only thing we have to do, to accomplish this is to select the proxy service and go to the Security tab. Here you can select the Service Key Provider.

      ProxyService

Custom 11G XPath function not showing up in JDeveloper 12C

You can write your own XPath lib in Java to make certain things easier and re-usable. For an example see here.

From the documentation of 12C, nothing indicated that things would have been changed so I stuck in an old library and restarted JDev. When I opened the xslt mapper, I didn’t see my functions under User Defined. This made me wonder if maybe something did have changed. Last week I attended the OFM Summercamp in Lisbon and Wilfred van der Deijl mentioned that JDev caches a lot so maybe clearing the cache would solve the problem. Someone also mentioned you could use -clean as a parameter when starting JDev but to be quite thorough I just renamed the cache folder which is default under C:\Users\\AppData\Roaming\JDeveloper from 12.1.3.0.0 to 12.1.3.0.0.old. Then I started again and voilà…..there it was. Cheers Wilfred!

UserDefined

OFM 12C: An example of the Business Rule Engine with Java facts

One of the components of the Oracle SOA Suite is the Business Rule Engine. The Oracle Business Rules engine….and I quote ‘allows the externalization of specific business logic and
parameters. Business analysts can easily define, update, and manage key parameters and decision trees that are likely to change based on business evolution (for instance discount levels, credit rates, etc.) without having to involve IT and developers.

This all sounds pretty nice but I haven’t seen it implemented anywhere yet but lately I have been working for a customer which has a good case to actually use the BRE so I had time look into it. In this blog I will show you a basic way to use the BRE using a decisions table and with the use of some custom Java facts.

A simple explanation: We have persons who wants to insure themselves from a certain date with a certain type of insurance. We are going to use the BRE to determine whether they are allowed to do this. We are going to use a decision table instead of if-then-else structures and in the decision table we are going to use java facts which we created to make certain functions more easy to define.

Lets start of with a simple SOA project. I created a simple schema with a input and output.

<?xml version="1.0" encoding="windows-1252" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:rr="http://nl.redrock-it"
            targetNamespace="http://nl.redrock-it" elementFormDefault="qualified">
  <xsd:element name="breExampleRequest">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="dateOfBirth" type="xsd:date"/>
        <xsd:element name="startDate" type="xsd:date"/>
        <xsd:element name="insuranceType">
          <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:enumeration value="Basic"/>
              <xsd:enumeration value="Better"/>
              <xsd:enumeration value="Best"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="breExampleResponse">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="result" type="xsd:boolean"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

Lets add a Mediator to the composite and expose it as a web service.

createMediator

Now lets create the BRE component. Drag the Business Rule into the composite. Input a name and select the input and output where you can select the request and response we have previously defined in the insurance.xsd and press OK.

createBR

If you edit the Business Rule you have different tabs.

BRtabs

Settings has some general settings as expected. The Facts tabs hold the request and response data structures which you will be using. These should already have the breExampleRequest and breExampleResponse in there. Also the checkbox visible should have been checked as we are going to use them.

BRfacts

In the Globals tab we can define globals which we might be using. We are going to define here the AdultAge.

BRglobal

Now lets create the actual ruleset. Go to the generated RuleSet1. Rename the RuleSet1 to InsuranceRuleSet. Then add a DecisionTable.

BRruleset

When you create the DecisionTable it opens automatic. A decision table is like a matrix. You have Conditions which together with Rules result into Actions. Lets insert a Condition first.

BRCondition

Now select the InsuranceType from the breExampleRequest.

BRConditionConfig

After this we can input the possible value which will be “Basic”. Now lets attach an action to it.

BRAction

Double-click the action and the popup opens. Here we can select from the facts the breExampleResponse and select the fact its parameterized.

BRActionConfig

Now press OK. Then add a value to the action which will be the simple boolean value “true”.

BRActionValue

Now we have 1 Rule but we want 3 so we at least can see the difference which different inputs so lets create an two extra Rules with the following values:

R1R2R3

So basically this ruleset should return “true” when I pick the insurance of type “Basic” and “false” if pick the insurance of type “Better” or “Best”. Before we connect it all together we have to define the interface for the BusinessRule component on the Decision Functions tab. Here we will configure the webservice interface which we will use to call the business rule. Go to the Decisions Functions tab and double click on the already created decision function. In the next popup you can define the name, the name of the operation of the webservice and the input and output. Also make sure the ruleset is selected on the Rule Sets & Decision Functions tab.

DecisionFunction

Now connect the mediator to the business rule. As you can see the BusinessRule component as an interface to which we can connect.

connecting

Make sure you map the input and output in the mediator.

Mapping

Now that it is all hooked up together, lets deploy it and give it a spin. I use SoapUI to call the service and lets see what happens.

SoapUITest

As you can see, we get TRUE for the ‘Basic’ insurance but FALSE for the ‘Better’ and ‘Best’ option. So now we have seen how to make use of a simple decision table. In a business environment, you probably want some more complex functions in the decision table. There are possibilities to make use of functions but from what I have seen, these are quite limited and not very clear on their usages. Another option is to write functions yourself using Java. You create a jar file which contain classes with your helper functions. I will demonstrate below how this works.

First create a simple class with a helper function. I created a simple class with a static function which determines if a person is an adult on a certain date. This will look like this:

package nl.redrock.bre;

import java.util.Calendar;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 *
 * @author Hugo Hendriks
 */
public class Insurance {
    
    /**
     * Check whether the person is already an adult at the startDate
     * @param aStartDate the starting date
     * @param aBirthDate the day of birth
     * @param aAdultAge the legal age a person becomes an adult
     * @return true or false
     */
    public static boolean isAdultAtDate(XMLGregorianCalendar aStartDate, XMLGregorianCalendar aBirthDate, int aAdultAge){
     
        boolean result = false;
        
        Calendar birthdayLegalAge = aBirthDate.toGregorianCalendar();
        birthdayLegalAge.add(Calendar.YEAR, aAdultAge);
        
        if(birthdayLegalAge.before(aStartDate.toGregorianCalendar())){
            result = true;
        }
        return result;
    }
    
}

Keep in mind that xsd:date is tranformed to an XMLGregorianCalendar object. As a good practice write a JUnit test for it to check if it works as desired and build a jar. I am using maven so this would be the outcome.

Scanning for projects...

Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1
                                                                        
------------------------------------------------------------------------
Building BRE-Test 1.0
------------------------------------------------------------------------

--- maven-clean-plugin:2.5:clean (default-clean) @ BRE-Test ---
Deleting D:\Amazon EC2\SVN\trunk\java\BRE-Test\target

--- maven-resources-plugin:2.6:resources (default-resources) @ BRE-Test ---
Using 'UTF-8' encoding to copy filtered resources.
skip non existing resourceDirectory D:\Amazon EC2\SVN\trunk\java\BRE-Test\src\main\resources

--- maven-compiler-plugin:2.5.1:compile (default-compile) @ BRE-Test ---
Compiling 1 source file to D:\Amazon EC2\SVN\trunk\java\BRE-Test\target\classes

--- maven-resources-plugin:2.6:testResources (default-testResources) @ BRE-Test ---
Using 'UTF-8' encoding to copy filtered resources.
skip non existing resourceDirectory D:\Amazon EC2\SVN\trunk\java\BRE-Test\src\test\resources

--- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ BRE-Test ---
Compiling 1 source file to D:\Amazon EC2\SVN\trunk\java\BRE-Test\target\test-classes

--- maven-surefire-plugin:2.12.4:test (default-test) @ BRE-Test ---
Surefire report directory: D:\Amazon EC2\SVN\trunk\java\BRE-Test\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running nl.redrock.bre.InsuranceTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.098 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0


--- maven-jar-plugin:2.4:jar (default-jar) @ BRE-Test ---
Building jar: D:\Amazon EC2\SVN\trunk\java\BRE-Test\target\BRE-Test-1.0.jar
------------------------------------------------------------------------
BUILD SUCCESS
------------------------------------------------------------------------
Total time: 4.922 s
Finished at: 2015-01-09T12:17:07+01:00
Final Memory: 13M/126M
------------------------------------------------------------------------

Now I have a jar containing the class which I want to use but how do I get in into my designtime environment? Very simple…just drop the jar file into the \SOA\.rulesdesigner\jaxb_classes folder….in my case BreTestProject\SOA\.rulesdesigner\jaxb_classes. Now lets go back to the Business Rule component. Go to the Facts tab and the Java Fact tab below and click Add.

AddJavaFact

In the popup select Add and select the .jar file we have just copied. When selected, the tree below should display the classes. Select the Insurance class and click OK.

SelectJar

You should see the class now in the list of Java facts. Now for the magic. Go to your decision table and add a new condition. Double click it and click the calculator icon on the top right. In the popup select the method from the Functions tab and select the right input parameters from the variables tab. We also put in there the AdultAge from the Constant tab we had defined before.

JavaFactCondition

The table will look like this now.

JavaFactDT

Now compile and deploy again. Don’t forget to add the jar into the /lib directory and restart your domain. When we run our SoapUI test you will see it also takes the Java check in the decision table into account.

Down the line the business rule component can help you, by putting some business logic into your middleware layer which can be edited through the soa-composer. The Java facts work quite nicely when the IDE is stable and the decision table works as it should. Sorting certain business functionality in the decision table instead of the decision tables takes some head twisting.

Thing to take into consideration:

  • There is a memory leak in the DecisionTable IDE editor. When you open it, the table will start to eat resources and eventually crash especially when you have a lot of columns and rows. There is a patch available but will also introduce a new bug which crashes the IDE completely! Un-patching using opatch seemed to get rid of the crash and of the memory leak.
  • There are classes being generated when you define your interface. If you want to change the interface later on, you have to delete and create the classes again or else you will run into errors here.
  • The BRE component has it’s fits. Sometimes you will have strange glitches or unexplainable behavior. I think this comes to the fact that not many customers use it so it doesn’t receive much love from Oracle :)

CI using Oracle Fusion Middleware 12C: Part 2. Building a SB and SOA project using maven and the MDS

In the part 1 I have shown how to setup a simple CI environment and how to build a Service Bus project using Maven. In this part I will try to make a release pipeline which builds, deploys, tests, packages and release a whole service using Jenkins and if all successful and finally install the artifact in Nexus.

Lets start where we left of. Startup Tomcat and log into Jenkins. We need some sort of plugin to be able to run multiple actions in a sequence. Jenkins has alot of plugins but the one which I am going to use is the MultiJob one. Go to Manage Jenkins->Manage plugins, choose the available tab, check the Multijob plugin and click Install without restart.

Multijob

The multi-job plugin can chain jobs together and share variables and artifact between jobs. You can make very intricate jobs but for now I will keep it simple. I will make 1 job that will:

  1. Build the service bus component which also refers to a SharedObjects project and deploy it to my server
  2. Build the soa component which also refers to the MDS and deploy it to my server
  3. Run the matching soap ui test
  4. If succesfull, install the artifact to nexus

I have created a simple HelloService which first goes to the SB and then routes to a SOA component. The SB component makes use of a SharedObjects SB project which holds the WSDL and XSD. This project is setup so you don’t have to sync between this project and the MDS. This because the SB isn’t able yet to access the MDS. The SOA component does nothing else the return a string response. So the setup will look like this:

HelloService

So the first job we have to create is one which builds and deploys an SB project using maven. We will have to have 2 jobs as we want to deploy the SharedObjects project and we want to deploy the SB service afterwards. Lets make the SharedObject first. This is an easy one as it has no references to any other project.

Create a new Jenkins job called OSB – SharedObjects which is based on a maven project. The .pom file is very simple. This will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_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>

	<parent>
		<groupId>com.oracle.servicebus</groupId>
		<artifactId>sbar-project-common</artifactId>
		<version>12.1.3-0-0</version>
	</parent>

	<groupId>nl.cvgz</groupId>
	<artifactId>GedeeldeObjecten</artifactId>
	<version>1.0</version>
	<packaging>sbar</packaging>
	<description/>
</project>

As a maven goal we can just use the following command to build and deploy the SharedObject project to the designated server:

clean pre-integration-test -DoracleHome=${oracleHome} -DoracleServerUrl=${osbServername} -DoracleUsername=${osbUsername} -DoraclePassword=${osbPassword}

You can insert the variables from a property file as you can see. Now lets try this first job and see how it runs.

SharedObjects-jenkins

Started by user Hugo Hendriks
[EnvInject] - Loading node environment variables.
Building in workspace D:\tomcatfiles\.jenkins\jobs\OSB - GedeeldeObjecten\workspace
Cleaning local Directory GedeeldeObjecten
Checking out svn://hendriksh@u10023o/mmi/trunk/OSB/GedeeldeObjecten at revision '2015-02-18T19:18:29.973 +0100'
A         GedeeldeObjecten.jpr
A         apps
A         apps\services
A         apps\services\HelloService
A         apps\services\HelloService\1.0
A         apps\services\HelloService\1.0\HelloService.wsdl
A         apps\services\HelloService\1.0\cdm.xsd
A         apps\services\HelloService\1.0\HelloService.xsd
A         servicebus.sboverview
A         alerts
A         alerts\Log.alert
A         alerts\ErrorDestination.alert
A         pom.xml
 U        .
At revision 927
Cleaning local Directory Build
Checking out svn://hendriksh@u10023o/mmi/trunk/build at revision '2015-02-18T19:18:29.973 +0100'
A         build-env-TST.properties
A         build-env-ONT.properties
At revision 927
no change for svn://hendriksh@u10023o/mmi/trunk/OSB/GedeeldeObjecten since the previous build
no change for svn://hendriksh@u10023o/mmi/trunk/build since the previous build
[EnvInject] - Executing scripts and injecting environment variables after the SCM step.
[EnvInject] - Injecting as environment variables the properties file path 'Build/build-env-ONT.properties'
[EnvInject] - Variables injected successfully.
Parsing POMs
[GedeeldeObjecten] $ D:\ProgramFiles\Java\jdk1.7.0_71/bin/java -cp D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven31-agent-1.5.jar;D:\ProgramFiles\Apache\apache-maven-3.2.3\boot\plexus-classworlds-2.5.1.jar;D:\ProgramFiles\Apache\apache-maven-3.2.3/conf/logging jenkins.maven3.agent.Maven31Main D:\ProgramFiles\Apache\apache-maven-3.2.3 D:\ProgramFiles\Apache\Tomcat8.0\webapps\jenkins\WEB-INF\lib\remoting-2.48.jar D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven31-interceptor-1.5.jar D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven3-interceptor-commons-1.5.jar 58198
<===[JENKINS REMOTING CAPACITY]===>���channel started
Executing Maven:  -B -f D:\tomcatfiles\.jenkins\jobs\OSB - GedeeldeObjecten\workspace\GedeeldeObjecten\pom.xml clean pre-integration-test -DoracleHome=[MY-ORACLEHOME] -DoracleServerUrl=http://[MY-SERVER] -DoracleUsername=[MY-USER] -DoraclePassword=[MY-PASSWORD]
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building GedeeldeObjecten 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ GedeeldeObjecten ---
[INFO] 
[INFO] --- oracle-servicebus-plugin:12.1.3-0-0:package (default-package) @ GedeeldeObjecten ---
[INFO] 
[INFO] --- oracle-servicebus-plugin:12.1.3-0-0:deploy (default-deploy) @ GedeeldeObjecten ---
[INFO] Service Bus Archive deployed using session Service_Bus_Maven-GedeeldeObjecten-1424283534524.
Diagnostic XML Bean debug log file created: C:\Windows\TEMP\xmlbeandebug7850265000274769465.log
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:37 min
[INFO] Finished at: 2015-02-18T19:21:15+01:00
[INFO] Final Memory: 22M/362M
[INFO] ------------------------------------------------------------------------
[JENKINS] Archiving D:\tomcatfiles\.jenkins\jobs\OSB - GedeeldeObjecten\workspace\GedeeldeObjecten\pom.xml to nl.cvgz/GedeeldeObjecten/1.0/GedeeldeObjecten-1.0.pom
[JENKINS] Archiving D:\tomcatfiles\.jenkins\jobs\OSB - GedeeldeObjecten\workspace\GedeeldeObjecten\.data\maven\sbconfig.sbar to nl.cvgz/GedeeldeObjecten/1.0/GedeeldeObjecten-1.0.sbar
D:/tomcatfiles/.jenkins/jobs/OSB - GedeeldeObjecten/workspace/GedeeldeObjecten/pom.xml is not inside D:/tomcatfiles/.jenkins/jobs/OSB - GedeeldeObjecten/workspace/GedeeldeObjecten/GedeeldeObjecten/; will archive in a separate pass
D:/tomcatfiles/.jenkins/jobs/OSB - GedeeldeObjecten/workspace/GedeeldeObjecten/.data/maven/sbconfig.sbar is not inside D:/tomcatfiles/.jenkins/jobs/OSB - GedeeldeObjecten/workspace/GedeeldeObjecten/GedeeldeObjecten/; will archive in a separate pass

channel stopped
Finished: SUCCESS

As you can see….success!

The next bit will be to make a job which deploys the HelloService SB component. This job will actually be quite the same as the previous one except for the fact that it references the SharedObjects project. If you run the normal maven build, it will complain that it can’t find the shared resources. The way to solve this, is to also checkout the SharedObject project during the build in your workspace. This way it can find the project compile time.

Started by user Hugo Hendriks
[EnvInject] - Loading node environment variables.
Building in workspace D:\tomcatfiles\.jenkins\jobs\OSB - Service\workspace
Cleaning local Directory HelloService_v1.0
Checking out svn://hendriksh@u10023o/mmi/trunk/OSB/HelloService_v1.0 at revision '2015-02-18T19:31:12.398 +0100'
A         pom.xml
A         Business
A         Business\HelloService.bix
A         LogPipeline.pipeline
A         HelloPipeline.pipeline
A         Proxy
A         HelloService_v1.0.jpr
A         ValidatePipeline.pipeline
A         HelloService.proxy
A         servicebus.sboverview
At revision 927
Cleaning local Directory GedeeldeObjecten
Checking out svn://hendriksh@u10023o/mmi/trunk/OSB/GedeeldeObjecten at revision '2015-02-18T19:31:12.398 +0100'
A         GedeeldeObjecten.jpr
A         apps
A         apps\services
A         apps\services\HelloService
A         apps\services\HelloService\1.0
A         apps\services\HelloService\1.0\HelloService.wsdl
A         apps\services\HelloService\1.0\cdm.xsd
A         apps\services\HelloService\1.0\HelloService.xsd
A         servicebus.sboverview
A         alerts
A         alerts\Log.alert
A         alerts\ErrorDestination.alert
A         pom.xml
 U        .
At revision 927
Cleaning local Directory Build
Checking out svn://hendriksh@u10023o/mmi/trunk/build at revision '2015-02-18T19:31:12.398 +0100'
A         build-env-TST.properties
A         build-env-ONT.properties
At revision 927
Cleaning local Directory Customization
Checking out svn://hendriksh@u10023o/mmi/trunk/OSB/Customization at revision '2015-02-18T19:31:12.398 +0100'
A         all_BS_ACC.xml
A         all_BS_TST.xml
A         all_BS_ONT.xml
At revision 927
no revision recorded for svn://hendriksh@u10023o/mmi/trunk/OSB/HelloService_v1.0 in the previous build
no change for svn://hendriksh@u10023o/mmi/trunk/build since the previous build
no change for svn://hendriksh@u10023o/mmi/trunk/OSB/Customization since the previous build
[EnvInject] - Injecting environment variables from a build step.
[EnvInject] - Injecting as environment variables the properties file path 'Build/build-env-ONT.properties'
[EnvInject] - Variables injected successfully.
Parsing POMs
Modules changed, recalculating dependency graph
[HelloService_v1.0] $ D:\ProgramFiles\Java\jdk1.7.0_71/bin/java -cp D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven31-agent-1.5.jar;D:\ProgramFiles\Apache\apache-maven-3.2.3\boot\plexus-classworlds-2.5.1.jar;D:\ProgramFiles\Apache\apache-maven-3.2.3/conf/logging jenkins.maven3.agent.Maven31Main D:\ProgramFiles\Apache\apache-maven-3.2.3 D:\ProgramFiles\Apache\Tomcat8.0\webapps\jenkins\WEB-INF\lib\remoting-2.48.jar D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven31-interceptor-1.5.jar D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven3-interceptor-commons-1.5.jar 58247
<===[JENKINS REMOTING CAPACITY]===>���channel started
Executing Maven:  -B -f D:\tomcatfiles\.jenkins\jobs\OSB - Service\workspace\HelloService_v1.0\pom.xml clean pre-integration-test -DoracleHome=[MY-ORACLEHOME] -DoracleServerUrl={MY-SERVER} -DoracleUsername=[MY-USER] -DoraclePassword=[MY-PASSWORD]
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building HelloService 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ HelloService ---
[INFO] 
[INFO] --- oracle-servicebus-plugin:12.1.3-0-0:package (default-package) @ HelloService ---
[INFO] 
[INFO] --- oracle-servicebus-plugin:12.1.3-0-0:deploy (default-deploy) @ HelloService ---
[INFO] Service Bus Archive deployed using session Service_Bus_Maven-HelloService-1424284297240.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 34.955 s
[INFO] Finished at: 2015-02-18T19:31:56+01:00
[INFO] Final Memory: 23M/226M
[INFO] ------------------------------------------------------------------------
Waiting for Jenkins to finish collecting data
[JENKINS] Archiving D:\tomcatfiles\.jenkins\jobs\OSB - Service\workspace\HelloService_v1.0\pom.xml to nl.cvgz/HelloService/1.0/HelloService-1.0.pom
[JENKINS] Archiving D:\tomcatfiles\.jenkins\jobs\OSB - Service\workspace\HelloService_v1.0\.data\maven\sbconfig.sbar to nl.cvgz/HelloService/1.0/HelloService-1.0.sbar
channel stopped
Finished: SUCCESS

Also success! So we now have 2 separate jobs:

      OSB – SharedObjects = which builds and deploys your SharedObject project.
      OSB – Service = which builds and deploys your HelloService project.

The next thing is to do the same for the SOA component. I actually want a SOA – MDS jenkins job which zips and deploys the MDS but it seems Oracle doesn’t support the deployment of the MDS through maven yet. I have heard rumors though that you can zip it and deploy it using the normal maven plugins. I am able to zip the apps directory but I haven’t been able to deploy it yet so if anyone knows how to do this….let me know :)

The last job is a SOA – Service job which builds and deploys the SOA component. When you create a SOA project you get a pom with it. To make this work with the MDS you do have to tweak it here and there. The problem is that the MDS reference is made through the application which references the adf-config.xml. Lets start of with the adf-config.xml which is located in .adf\META-INF. You should make a MDS like this:

<adf-mds-config xmlns="http://xmlns.oracle.com/adf/mds/config">
    <mds-config xmlns="http://xmlns.oracle.com/mds/config">
      <persistence-config>
        <metadata-namespaces>
          <namespace path="/apps" metadata-store-usage="mstore-usage_apps"/>
        </metadata-namespaces>
        <metadata-store-usages>
          <metadata-store-usage id="mstore-usage_apps">
            <metadata-store class-name="oracle.mds.persistence.stores.file.FileMetadataStore">
              <property name="metadata-path" value="${soamds.apps.home}" />
            </metadata-store>
          </metadata-store-usage>
        </metadata-store-usages>
      </persistence-config>
    </mds-config>
  </adf-mds-config>

As you can see we made the metadata-path for the /apps settable using a variable soamds.apps.home. So now you can set the directory of your apps of your application which holds the soa project. Now for the last bit….the .pom file of you soa project. As I said, you will have to tweak some settings here as it doesn’t completely work out of the box. You should make the following adjustments:

<?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">
         <!--
           This POM was automatically generated during SOA project creation.           
           This POM relates to this SOA Composite, i.e. the one in this same directory.
           There is another POM in the SOA Application directory which handles
           the whole SOA Application, which may contain additional projects. 
        -->
    <modelVersion>4.0.0</modelVersion>
    <groupId>VGZ-SOA-Application</groupId>
    <artifactId>HelloService</artifactId>
    <version>1.0</version>
    <packaging>sar</packaging>
    
    <!--
           The parent points to the common SOA parent POM.  That is a special POM that is
           shipped by Oracle as a point of customization (only). You can add default values
           for properties like serverUrl, etc. to the SOA common parent POM, so that you
           do not have to specify them over and over in every project POM.
    --> 
    <parent>
        <groupId>com.oracle.soa</groupId>
        <artifactId>sar-common</artifactId>
        <version>12.1.3-0-0</version>
    </parent>
    
    <properties>
        <!-- These parameters are used by the compile goal -->
        <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>
        <!-- These parameters are used by the deploy and undeploy goals --> 
        <composite.name>${project.artifactId}</composite.name>
        <composite.revision>${project.version}</composite.revision>
        <composite.partition>default</composite.partition>        
        <serverUrl>${oracleServerUrl}</serverUrl>        
        <user>${oracleUsername}</user>
        <password>${oraclePassword}</password>
        <overwrite>true</overwrite>
        <forceDefault>true</forceDefault>
        <regenerateRulebase>false</regenerateRulebase>
        <keepInstancesOnRedeploy>false</keepInstancesOnRedeploy>
        
        <!-- These parameters are used by the test goal 
         if you are using the sca-test (test) goal, you need to uncomment the following
             line and point it to your jndi.properties file. --> 
             
        <!--<jndi.properties.input>UNDEFINED</jndi.properties.input>-->
        <scatest.result>${scac.output.dir}/testResult</scatest.result>
        <!--  input is the name of the composite to run test suties against -->
        <input>${project.artifactId}</input>
        
        <!--<scac.ant.buildfile>${env.MW_HOME}/soa/bin/ant-sca-compile.xml</scac.ant.buildfile>
        <sca.ant.testfile>${env.MW_HOME}/soa/bin/ant-sca-test.xml</sca.ant.testfile>
        -->
        
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>com.oracle.soa.plugin</groupId>
                <artifactId>oracle-soa-plugin</artifactId>
                <version>12.1.3-0-0</version>
                <configuration>
                    <compositeName>${project.artifactId}</compositeName>
                    <composite>${scac.input}</composite>
                    <sarLocation>${scac.output.dir}/sca_${project.artifactId}_rev${composite.revision}.jar</sarLocation>
                    <serverUrl>${serverUrl}</serverUrl>
                    <appHome>../../../</appHome>
                    <!-- Note: compositeRevision is needed to package, revision is needed to undeploy -->
                    <compositeRevision>${project.version}</compositeRevision>
                    <revision>${composite.revision}</revision>
					<scacInputDir>${scac.input.dir}</scacInputDir>
					<user>${user}</user>
                    <password>${password}</password>                    
                    <input>${input}</input> 
                </configuration>
                 <!-- extensions=true is needed to use the custom sar packaging type -->
                <extensions>true</extensions>
            </plugin>
        </plugins>
    </build>
</project>

You should add

<appHome>../../../</appHome>

to you plugin. This will have to point to the place where your application is located and thus where your .adf/META-INF/adf-config.xml is also. In my case, that is 3 folders up when I do a checkout of my svn. You also have to fix ${project.version} as it will by default generates a 1.0-SNAPSHOT version but it will look for a 1.0 to deploy.

After you have done all this lets create a Jenkins job called SOA – Service and run the following maven command:

clean pre-integration-test -DoracleServerUrl=${soaServername} -DoracleUsername=${soaUsername} -DoraclePassword=${soaPassword}

Don’t forget to set soamds.apps.home=${workspace}\GedeeldeObjecten as environment variable and to also checkout the application.jws including .adf/META-INF/adf-config.xml. Now lets give the job a spin:

Started by user Hugo Hendriks
[EnvInject] - Loading node environment variables.
Building in workspace D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace
Cleaning local Directory .
Checking out svn://hendriksh@u10023o/mmi/trunk/services at revision '2015-02-18T20:23:09.684 +0100'
A         VGZ-SOA-Application.jws
 U        .
At revision 927
Cleaning local Directory .adf
Checking out svn://hendriksh@u10023o/mmi/trunk/services/.adf at revision '2015-02-18T20:23:09.684 +0100'
A         META-INF
A         META-INF\adf-config.xml
At revision 927
Cleaning local Directory GedeeldeObjecten/apps
Checking out svn://hendriksh@u10023o/mmi/trunk/OSB/GedeeldeObjecten/apps at revision '2015-02-18T20:23:09.684 +0100'
A         services\HelloService
A         services\HelloService\1.0
A         services\HelloService\1.0\HelloService.xsd
A         services\HelloService\1.0\HelloService.wsdl
A         services\HelloService\1.0\cdm.xsd
 U        .
At revision 927
Cleaning local Directory HelloService_v1.0/soa/HelloService_v1.0
Checking out svn://hendriksh@u10023o/mmi/trunk/services/HelloService_v1.0/soa/HelloService_v1.0 at revision '2015-02-18T20:23:09.684 +0100'
A         HelloService_v1.0.jpr
A         SOA
A         SOA\composite.xml
A         SOA\Schemas
A         SOA\Events
A         SOA\Mediators
A         SOA\Mediators\HelloMediator.mplan
A         SOA\measurements.xml
A         SOA\Transformations
A         SOA\WSDLs
A         SOA\testsuites
A         SOA\testsuites\fileList.xml
A         pom.xml
 U        .
At revision 927
Cleaning local Directory Build
Checking out svn://hendriksh@u10023o/mmi/trunk/build at revision '2015-02-18T20:23:09.684 +0100'
A         build-env-TST.properties
A         build-env-ONT.properties
At revision 927
no change for svn://hendriksh@u10023o/mmi/trunk/services/.adf since the previous build
no revision recorded for svn://hendriksh@u10023o/mmi/trunk/services/HelloService_v1.0/soa/HelloService_v1.0 in the previous build
no change for svn://hendriksh@u10023o/mmi/trunk/build since the previous build
[EnvInject] - Injecting environment variables from a build step.
[EnvInject] - Injecting as environment variables the properties file path 'Build/build-env-ONT.properties'
[EnvInject] - Variables injected successfully.
[EnvInject] - Injecting as environment variables the properties content 
soamds.apps.home=${workspace}\GedeeldeObjecten

[EnvInject] - Variables injected successfully.
Parsing POMs
Modules changed, recalculating dependency graph
[HelloService_v1.0] $ D:\ProgramFiles\Java\jdk1.7.0_71/bin/java -cp D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven31-agent-1.5.jar;D:\ProgramFiles\Apache\apache-maven-3.2.3\boot\plexus-classworlds-2.5.1.jar;D:\ProgramFiles\Apache\apache-maven-3.2.3/conf/logging jenkins.maven3.agent.Maven31Main D:\ProgramFiles\Apache\apache-maven-3.2.3 D:\ProgramFiles\Apache\Tomcat8.0\webapps\jenkins\WEB-INF\lib\remoting-2.48.jar D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven31-interceptor-1.5.jar D:\tomcatfiles\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven3-interceptor-commons-1.5.jar 58351
<===[JENKINS REMOTING CAPACITY]===>���channel started
Executing Maven:  -B -f D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\pom.xml clean pre-integration-test -DoracleServerUrl=[MY-SERVER] -DoracleUsername=[MY-USER] -DoraclePassword=[MY-PASSWORD]
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building HelloService 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ HelloService ---
[INFO] 
[INFO] --- maven-resources-plugin:2.7:resources (default-resources) @ HelloService ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\src\main\resources
[INFO] 
[INFO] --- oracle-soa-plugin:12.1.3-0-0:compile (default-compile) @ HelloService ---
[INFO] ------------------------------------------------------------------------
[INFO] ORACLE SOA MAVEN PLUGIN - COMPILE
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] ABOUT TO RUN oracle.soa.scac.ValidateComposite...
[INFO] compile: Executing: [cmd:[D:\ProgramFiles\Java\jdk1.7.0_71\bin\java, -Djava.protocol.handler.pkgs=oracle.mds.net.protocol|oracle.fabric.common.classloaderurl.handler|oracle.fabric.common.uddiurl.handler, oracle.soa.scac.ValidateComposite, D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\SOA//composite.xml, -level=1, -appHome=../../../]]
[INFO] Process being executed, waiting for completion.
[INFO] [exec] 2015-02-18 20:23:35.950/4.421 Oracle Coherence 12.1.3.0.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/D:/ProgramFiles/Apache/apache-maven-repository/com/oracle/coherence/coherence/12.1.3-0-0/coherence-12.1.3-0-0.jar!/tangosol-coherence.xml"
[INFO] [exec] 2015-02-18 20:23:36.091/4.562 Oracle Coherence 12.1.3.0.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/D:/ProgramFiles/Apache/apache-maven-repository/com/oracle/coherence/coherence/12.1.3-0-0/coherence-12.1.3-0-0.jar!/tangosol-coherence-override-dev.xml"
[INFO] [exec] 2015-02-18 20:23:36.091/4.562 Oracle Coherence 12.1.3.0.0 <D5> (thread=main, member=n/a): Optional configuration override "/tangosol-coherence-override.xml" is not specified
[INFO] [exec] 2015-02-18 20:23:36.107/4.578 Oracle Coherence 12.1.3.0.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
[INFO] [exec] 2015-02-18 20:23:36.107/4.578 Oracle Coherence 12.1.3.0.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
[INFO] [exec] 2015-02-18 20:23:36.107/4.578 Oracle Coherence 12.1.3.0.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified
[INFO] [exec] 
[INFO] [exec] Oracle Coherence Version 12.1.3.0.0 Build 52031
[INFO] [exec]  Grid Edition: Development mode
[INFO] [exec] Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
[INFO] [exec] 
[INFO] [exec] 2015-02-18 20:23:36.247/4.718 Oracle Coherence GE 12.1.3.0.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.DefaultConfigurableCacheFactory
[INFO] [exec] Feb 18, 2015 8:23:37 PM oracle.fabric.common.wsdl.SchemaManager isIncrementalBuildSupported
[INFO] [exec] INFO: XMLSchema incremental build enabled.
[INFO] [exec] Mediators/HelloMediator.mplan: warning: Assigning property/constant "concat("Hallo ", $in.payload/tns:HelloRequest/tns:Naam)" to element "$out.payload/tns:HelloResponse/tns:begroeting". Please make sure target is single leaf node, otherwise non-leaf node will contain only string value which may generate non-valid xml as per the xsd.
[INFO] compile: [cmd:[D:\ProgramFiles\Java\jdk1.7.0_71\bin\java, -Djava.protocol.handler.pkgs=oracle.mds.net.protocol|oracle.fabric.common.classloaderurl.handler|oracle.fabric.common.uddiurl.handler, oracle.soa.scac.ValidateComposite, D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\SOA//composite.xml, -level=1, -appHome=../../../]] exit code=0
[INFO] SOA COMPILE DONE
[INFO] 
[INFO] --- maven-resources-plugin:2.7:testResources (default-testResources) @ HelloService ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\src\test\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.2:testCompile (default-testCompile) @ HelloService ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ HelloService ---
[INFO] No tests to run.
[JENKINS] Recording test results
[INFO] 
[INFO] --- oracle-soa-plugin:12.1.3-0-0:sar (default-sar) @ HelloService ---
[INFO] Building sar: D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\target\sca_HelloService_rev1.0.jar
[INFO] 
[INFO] --- oracle-soa-plugin:12.1.3-0-0:deploy (default-deploy) @ HelloService ---
[INFO] ------------------------------------------------------------------------
[INFO] ORACLE SOA MAVEN PLUGIN - DEPLOY COMPOSITE
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] setting user/password..., user=weblogic
Processing sar=D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0/target/sca_HelloService_rev1.0.jar
Adding sar file - D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\target\sca_HelloService_rev1.0.jar
INFO: Creating HTTP connection to host:[MY-SERVER], port:[MY-PORT]
INFO: Received HTTP response from the server, response code=200
---->Deploying composite success.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 21.328 s
[INFO] Finished at: 2015-02-18T20:23:41+01:00
[INFO] Final Memory: 27M/356M
[INFO] ------------------------------------------------------------------------
Waiting for Jenkins to finish collecting data
[JENKINS] Archiving D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\pom.xml to VGZ-SOA-Application/HelloService/1.0/HelloService-1.0.pom
[JENKINS] Archiving D:\tomcatfiles\.jenkins\jobs\SOA - Service\workspace\HelloService_v1.0\soa\HelloService_v1.0\target\sca_HelloService_rev1.0.jar to VGZ-SOA-Application/HelloService/1.0/HelloService-1.0.jar
channel stopped
Archiving artifacts
Finished: SUCCESS

Perfect! As a final we can make a job to run a unit test against the just deployed server. I already made a description of how to do this here.

Now for the multijob. This will be a Release-Service job which calls all of the above step in a specific order. In the end you can use the CopyArtifact plugin to copy all of the generated artifacts into the Release-Service job. You can then zip these. I’m using the promote plugin to authorize the upload of the zip into Nexus. So the job looks like this now:

Release-Service

The stars on the left side will tell you that these where builds which where promoted and ended up in Nexus. I’m using a windows batch command to upload the zip to Nexus like this:

mvn deploy:deploy-file -Durl=[MY-SERVER] -DrepositoryId=local-nexus -DgroupId=nl.cvgz.mmi.services -DartifactId=%servicenaamkort% -Dversion=%serviceversie% -Dpackaging=zip -Dfile=target/%servicenaam%.zip

And finally they will end up in Nexus then. A zip which will contain:

  • OSB/SharedObject.sbar
  • OSB/Service.sbar
  • OSB/Customizations. Directory with customizations files for DTAP
  • SOA/MDS.zip
  • SOA/Service.jar

Nexus

So this could possibly be a way to automatically build, deploy, test, package and release a whole service using Jenkins. Some issues which I haven’t solved yet:

  • It seems adding a customization file during the deploy of the SB component gives an error. Could be a bug though.
  • Deploying the MDS.zip to the soa server through maven. If you know how to do this….drop me a line please

Creating a template in Oracle Service Bus 12C

In this article I will show how to use the new templating functionality in Oracle Service Bus 12C. When building a lot of services through different projects, you will always duplicate certain functionality such as Logging, Validation etc… All conform your current development rules and guidelines of the project. This means tedious copying and pasting of certain pieces of code and the old OEPE IDE isn’t always precise with that. 12C has a nice feature now which gives you the opportunity to template certain pieces of code and re-use them in other projects. Lets see how that works.

I am using the project I created in my previous post. You can download a zip containing the project at the bottom so you can start from there. The conversionrate service is still very plain. As I would like to follow the VETRO pattern, I would like to add validation. So lets add a validation pipeline to the flow. Drag the Pipeline icon from the resource pallet onto the Piplelines/Split Joins lane. Choose a name and choose next. Select our own WDSL located in the wsdl folder and unselect Expose as a Proxy Service option as we already have a proxy.

validationPipeline

Next delete the wire between the proxy and the ConversionRateServicePipeline and connect the proxy to the new ValidationPipeline and the ValidationPipeline to the ConversionRateServicePipeline.

pipeline

Now lets implement the validation. Double click the ValidationPipeline. As you can see it has already set the routing to the ConversionRateServicePipeline for you. Lets add a ValidationPipelinePairNode and a request and response stage as you would normally do and add the validations steps.

validatePipelinePair

Next deploy and run a SoapUI test with an invalid enumeration type. You should get the following result:

validationFault

But we want some custom reply instead of a SoapFault so lets make that happen. We add an errorhandler to our Pipeline and catch the specific OSB-382505 error which is a validation fault. In that case we transform the Fault into a neat message for the client. The Replace would look like this.

<sch:Messages>
{
  for $message in $fault/ctx:details/con1:ValidationFailureDetail/con1:message
  return
    <sch:Message>
      <sch:Code>E-001</sch:Code>
      <sch:Description>{data($message/text())}</sch:Description>
    </sch:Message>
}
</sch:Messages>

Don’t forget to add the namespace with the value http://www.bea.com/wli/sb/stages/transform/config and the namespace with value http://www.redrock-it.nl/conversionrate/service/schema. Now, if you save and deploy and use SoapUI to make an invalid call, you will see the following result.

validationFaultProper

Now for the template creation part. We will want to re-use the ValidationPipeline in other services so what we do we click New->Pipeline Template. We give the template a name and select a location. Unfortunately it seems we cannot create it in a directory outside the project so lets just choose a template directory we just created. Select next and select for any SOAP and click finish and voila……we have a template for validation.

createTemplate

But how do we use it? Very simple. When you add a new Pipeline to the Pipelines/Split Join lane, you can choose a template at the bottom of the dialog. Choose the template you just created and voila….you have a completely filled Pipeline ready to go.

usingTemplate

Building a simple service using Oracle Service Bus 12C

Oracle released their new 12C edition of Oracle Fusion Middleware so lets have a look at some of the changes. We are going to make a simple Service Bus project which will take two currencies as input and will return the exchange rate. I installed locally Weblogic 12C and created a base domain. For a brief description how to install SOA Suite 12C see here. After you have installed weblogic, lets start up JDeveloper.

JDeveloper12C

JDeveloper looks a bit more slick then before which I like. Ok, lets start. Choose File->New->From Gallery or press Control-N. Type in Service Bus and choose Service Bus Application with Service Bus Project (Applications).

Project selection

Choose an application name with package prefix and project name. I will name mine RedRockServiceBusApplication with prefix nl.redrock and ExampleSBProject. Press Finish and there you go….a new Service Bus application with project.

project layout

As you can see, the project now comes with a POM file which will be used for building the project using Maven. The project does not have any predefined folders so lets create a proxy and business folder for the proxy and business services. Now select the ExampleSBProject.sboverview which opens an editor which looks like the 11G SOA composite editor with a Proxy Service lane on the left, an External Services lane on the right and a Pipelines/Split Join lane in the middle. First lets create a pipeline by dragging a pipline onto the middle lane from the components area. Name it examplePipeline and press Next. In the next screen choose select the WSDL radiobutton and press the Browse WSDLs button on the right of it.

SelectWSDL

From here you can choose a WSDL which you want to use as base for your proxy service. I had an old WSDL lying around from an example project so I select this using the Filesystem tab. After the selection you will have an option where to import the WSDL to. I create a new folder wsdl in which to import the WSDL. In the next screen you can see JDeveloper being smart. It sees that the WSDL uses a XSD which he also want to import for you. As you can see, he will import the schema into the Schemas folder.

Import XSD

Press finish and keep the checkbox Expose as a Proxy Service checked. You can also choose in which folder you want JDeveloper to create the Proxy service. As we have a proxy folder, select that and press finish.

ProxyLocation

Now we have a pipeline with an proxy service. Now we just need a business service which we are going to invoke. Drag the HTTP icon from the Components tab onto the right External Services lane. A new popup opens where you can name the business service and choose its location. Choose the business folder we created before. In the next screen you can choose the WSDL. Like we did before for the proxy service, select the WSDL radio button and press the Browse WSDLs button on the right of it. I am using a public service located at http://www.webservicex.com/CurrencyConvertor.asmx?wsdl. I also added the WSDL’s and XSD’s I have used to this post so you can re-create this example. Select the WSDL and choose a folder where to import it. I created a folder thirdparty. Don’t forget to set the port to CurrencyConvertorSoap12.

ImportBusinessWSDL

Click Finish and the Next. Here you can choose the transport. Choose http and http://www.webservicex.com/CurrencyConvertor.asmx as endpoint and press Finish. Now connect our examplePipeline to our just created business service using the arrow block. Now your osb project should look something like this:

OsbLayout

Now it is time to edit the pipeline. Double click the example pipeline and an editor opens which you are used of the old Eclipse OSB IDE. You can see a RouteNode1 and a Routing has already been inserted when you connected the pipeline with the business service. The services takes two input parameters in the form of two currencies which we have to transform to the business service. As it is the first simple service I will just do the two replace actions to transform the input and output. First the input. Drag the Replace icon from the Components pallet to the request action lane. In the properties you can now edit it. I know what the request to the business service will have to look like so I replace the body using a simple Expression instead of using a xquery or XSLT. Don’t forget to add the web namespace(http://www.webserviceX.NET/) in the third tab down below and the sch namespace(http://www.redrock-it.nl/conversionrate/service/schema). This will look like this.

RequestTransform

Now lets do this also for the reply flow. Drag the Replace icon from the Components pallet to the response action lane. This will look like this:

ResponseTransform

So now our very simple service is done and can be deployed. You can use the integrated WLS or one you installed seperately. I am using a seperate instance. Deply the service. After this is successfully done you can access the WSDL at the following address: http://localhost:7001/ExampleSBProject/proxy/examplePipelineProxyService?wsdl. As I need this service for a next post I will test the service using SoapUI. I create a new project using the WSDL and test the service which should give below result:

test

So this is an example of a simple service using SOA Suite 12C. Here is a link to the complete project zip:

Synchronous BPEL process with a wait activity fails with a timeout

Recently we had a timing issue in our project. We were processing certain events and one event got processed before another one which caused a problem. A quick fix seemed possible by adding a Wait activity in our BPEL process which got processed too quickly. We added the Wait and set it to 2 seconds. We deployed it, ran our unit test again but it seemed to ignore the 2 seconds Wait activity even though it showed up in the Enterprise Managers trace. We then had a better look at the Oracle documentation and the Wait activity seemed to have some special rules to it.

When specifying a time period for waiting, note the following:

  • Wait times cannot be guaranteed if they are scheduled with other events that require processing. Due to this additional processing, the actual wait time can be greater than the wait time specified in the BPEL process.
  • Wait times of less than two seconds are ignored by the server. Wait times above two seconds, but less than one minute, may not get executed in the exact, specified time. However, wait times in minutes do execute in the specified time.
  • The default value of 2 seconds for wait times is specified with the MinBPELWait property in the System MBean Browser of Oracle Enterprise Manager Fusion Middleware Control Console. You can set this property to any value and the wait delay is bypassed for any waits less than MinBPELWait.

So the 2 seconds didn’t work as the documentation pointed out. Next we tried setting it to 3 seconds. After deploying the composite again and running the unit tests, we ran into a timeout error.

[2012-11-20T02:12:38.781-04:30] [soa_server1] [TRACE] [] [oracle.soa.bpel.engine.delivery] [tid: [ACTIVE].ExecuteThread: '19' for
queue: 'weblogic.kernel.Default (self-tuning)'] [userId: <anonymous>] [ecid: b1ee8223c4e185ca:5044d24d:13b1807f7e8:-8000-
0000000000000672,0:2] [SRC_CLASS: DeliveryHandler] [WEBSERVICE_PORT.name: BPELProcess1_pt] [APP: soa-infra] [composite_name:
WaitTestProject3] [J2EE_MODULE.name: fabric] [SRC_METHOD: initialRequestAnyType] [WEBSERVICE.name: bpelprocess1_client_ep]
[J2EE_APP.name: soa-infra] [[
com.oracle.bpel.client.delivery.ReceiveTimeOutException: Waiting for response has timed out. The conversation id is null. Please
check the process instance for detail.
at com.collaxa.cube.engine.delivery.DeliveryHandler.initialRequestAnyType(DeliveryHandler.java:656)
at com.collaxa.cube.engine.delivery.DeliveryHandler.initialRequest(DeliveryHandler.java:562)
at com.collaxa.cube.engine.delivery.DeliveryHandler.request(DeliveryHandler.java:235)
at com.collaxa.cube.engine.ejb.impl.CubeDeliveryBean.request(CubeDeliveryBean.java:494)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)

After some looking around, a colleague of mine came up with a reference to an Oracle support document 1507094.1. This document states that the Wait activity works well with an asynchronous BPEL process but not with a synchronous BPEL process where a transaction is required. The Wait activity involves a dehydration. Dehydration will persist the process and continue the process in a new thread. When the BPEL process is transaction required, the persist will not be complete until the BPEL process completes and transaction commits.

One of the solutions is possible:

  • Remove the following line from the synchronous BPEL process component:
    <property name="bpel.config.transaction" type="xs:string" many="false">required</property>
    

OR

  • Change bpel.config.transaction to “requiredNew”
    <property name="bpel.config.transaction" type="xs:string" many="false">requiredNew</property>
    

Creating a custom XPath function for the XSLT mapper in the SOA Suite

Sometimes the default XSLT-mapper in the SOA Suite just is not enough. You want a little bit more or you want something that is re-usable for other components. The answer lies in writing your own XPath function.

The first thing we need is to create a jar file which contains our functionality. Say we want a function which creates a displayname based on a few parameters. We will use Maven to create our jar. Start of with your basic maven structure and your default pom file.

Project
-src
   -main
      -java
      -resources
   -test
      -java
      -resources
-pom.xml

Your pom.xml wil be as basic as can be

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>nl.redrock</groupId>
	<artifactId>CustomXPath</artifactId>
	<version>1.0</version>
	<name>CustomXPath</name>
	<description>This jar contains classes which can be used for custom xpath</description>

	<dependencies>
 		<!-- Test dependencies -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		<dependency>
	<dependencies>
</project>

As you can see, we will use junit test to test my classes. Now lets build our functionality. Create a class NameCompiler in src/main/java

package nl.redrock.utils;


/**
 * XSLT Specific Mapper function.
 * 
 * Function is registered in a file with the naming convention
 * ext-mapper-xpath-functions-config.xml
 */
public class NameCompiler {

	/**
	 * This function is used to determine the lastname of a person based on its
	 * preference and partner details
	 * 
	 * @param aNameCode
	 *            the code (1=own, 2=partner, 3 partner-own,
	 *            4=own-partner)
	 * @param aPrefix
	 *            the person prefix
	 * @param aLastname
	 *            the lastname
	 * @param aPartnerPrefix
	 *            the partner prefix
	 * @param aPartnerLastname
	 *            the partner lastname
	 * @return the lastname based on the namecode
	 */
	public static String compileLastname(int aNameCode, String aPrefix,
			String aLastname, String aPartnerPrefix, String aPartnerLastname) {
		String result = null;
		switch (aNameCode) {
		/** Voorkeurnaamcode is eigen */
		case 1:
			result = aLastname;
			break;
		/** Voorkeurnaamcode is partner */
		case 2:
			result = aPartnerLastname;
			break;
		/** Voorkeurnaamcode is partner */
		case 3:
			if (aPrefix != null && aPrefix.length() > 0) {
				result = aPartnerLastname + " - " + aPrefix + " " + aLastname;
			} else {
				result = aPartnerLastname + " - " + aLastname;
			}
			break;
		/** Voorkeurnaamcode is partner */
		case 4:
			if (aPartnerPrefix != null && aPartnerPrefix.length() > 0) {
				result = aLastname + " - " + aPartnerPrefix + " "
						+ aPartnerLastname;
			} else {
				result = aLastname + " - " + aPartnerLastname;
			}
			break;
		default:
			result = "Onbekende naamvoorkeurscode!";
			break;
		}
		return result;
	}
}

Important here is that:

  • The method is public and static

Before you wrote this class, you will off course have written the junit tests as a good Test Driven programmer does ;-)

The next thing we need to do is to add ad file which maps the XPath to this class. This file is named ext-mapper-xpath-functions-config.xml and is located in the src/main/resource/META-INF folder and looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<soa-xpath-functions xmlns="http://xmlns.oracle.com/soa/config/xpath" xmlns:roc="http://www.oracle.com/XSL/Transform/java/nl.redrock.utils.NameCompiler">
	<function name="roc:compileLastname">
		<className>nl.redrock.utils.NameCompiler</className>
		<return type="string"/>
		<params>
			<param name="naamcode" type="number"/>
			<param name="voorvoegsel" type="string"/>
			<param name="achternaam" type="string"/>
			<param name="partnervoorvoegsel" type="string"/>
			<param name="partnerachternaam" type="string"/>
		</params>
		<desc/>
		<detail>
			<![CDATA[Deze functie stelt de officiele achternaam samen obv voorkeursnaamcode.]]>
		</detail>
	</function>
</soa-xpath-functions>

Important here is that:

  • The namespace starts with ‘http://www.oracle.com/XSL/Transform/java/’ followed by the package name

This is basically it. Run mvn clean package to build the final .jar file. Check if the class is packaged and that the ext-mapper-xpath-functions-config.xml is located in the META-INF directory.

The only thing left to do is to add the jar to JDeveloper so we can make use if it. This can be done by opening Tools->Preferences and going to the SOA tab

and adding the just created jar file. You will need to restart you JDeveloper for the changes to take effect. When you have restarted, you will see the custom XPath under Component Palette->User Defined

In the XSLT files this will look like this:

<gen:Achternaam>
    <xsl:value-of select="roc:compileLastname($naamcode,$voorvoegsel,$achternaam,$partnervoorvoegsel,$partnerachternaam)"/>
</gen:Achternaam>

Don’t forget to add the namespace which should match the one you have defined in the ext-mapper-xpath-functions-config.xml.

Now that this is done, how do we make it work on the server? The only thing you have to do is to copy the jar file to /Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1/ folder and run the ant script. This will rebuild the registry classpath entries. After this, you will need to restart the server.

When the server is restarted check to see if it works……

For a good reference document see here

Using JDeveloper to deploy to weblogic over SSL

When you start working with the SOA Suite 11G the server has a default keystore set. Connecting to this setup over HTTPS usually doesn’t give any problem as the CA’s used are generally trusted by default by the JDK used. One of the things you maybe are going to encounter when you equip your server with a genuin certificate with CA’s in the chain which are not trusted by default, is that the deployment using JDeveloper is not going to work anymore. This is because the SSL handshake will cause an error as JDeveloper doesn’t trust the server. How to solve this……
Continue reading