Friday, December 16, 2011

A couple minor XML parsing tricks with SOA/OSB

Mostly for my own memory before I forget them, don't want to re-learn these little things every 6 months.

1. sometimes you just need to ship a full XML payload to somewhere, but at the shipping point (where you need to hand it off) you don't really care about the actual structure (schema). For example, publishing various messages to a queue. You can define a simple input schema that takes a string.

...<element name="in" type="string"/>...

In BPEL editor, when you need to transform some source variable (say "src") with a structured schema, e.g.
<src>
  <foo>..
    <bar>...</bar>
     <car>...</car>
</foo>
</src>
your initial XSLT edit comes up that you can only drag one value from the "src" to the target "in" element.

Well, go ahead map that. Then open XSLT in source view, just type in your entire mapping like:

<in>
   <src>
    <foo>
      <bar> map bar's value</bar>
     <car> car's value</car>
    </foo>
  </src>
</in>

now you can map a full complex XML payload under "in". The only drawback is that you can't use the map editor to do this (it won't even open), because it doesn't know what to do with it (you are stuffing an entire XML structure inside one string element).

This is almost like an assignment operation in a "typeless" programing language.

2. Along the same line, you can stick an array of element into "in". That's what I actually did. But initially, I created a real "array" type, like:
<element name="srcList">
....
    <element name="srcElems" type="src" maxOccurs="unbounded"/>
...
</element>
I first mapped the incoming payload (from another structure) into this, then I assign (append) the resulting array into "in". It's unnecessary. Just go ahead stick the mapping from the source into an array of "src" direct into "in". Saves the trouble of creating an intermediate type.

3. Finally, when I get my "in" variable sent into OSB (with varies XML elements), I have a requirement to strip off all namespaces (change namespace is the same thing).
If I do assignment like this:
    $body/jms2:Publish/in/*
the result variable will retain all the namespaces from whatever contained in that "*". It may look something like:
<src xmlns:a="a.com" xmlns="blah.com" xmlns:b="bar.com">
  <foo xmlns="">...</foo> </src>
It may even come out more weird than this anyway.

The cheap way (without doing full fledge XSLT with schemas) is like:
<src>
  <foo>
    <bar>{$body/jms2:Publish/in/evt:foo/evt:bar/text()}</bar>
     <car>{$body/jms2:Publish/in/evt:foo/evt:car/text()}</car>
  </foo>
</src>

4. for next one, i should do a java callout, it has been a while, i should document the detailed steps

Wednesday, November 23, 2011

Eclipse: Failed to load the JNI shared library ... vm.dll

I managed to install OSB 11.1.1.4 with OEPE 11.1.16 (oepe-helios-all-in-one-11.1.1.6.1.201010012100-win32.zip) on win7 64-bit. My default JDK is 64-bit. When I fire up Eclipse, I'm getting this "Failed to load the JNI shared library ... vm.dll" error.

Solution is to install JDK 32-bit, then update eclipse.ini to point to your 32-bit JDK. here is the snippet of the .ini file. Keep in mind "-vm option needs to split on 2 lines, and appears before vmargs" (see http://wiki.eclipse.org/Eclipse.ini)
...
--launcher.defaultAction
openFile
-vm
c:\progra~2\java\jdk1.6.0_27\bin\javaw.exe
-vmargs
-Xms256m
-Xmx768m
....

OSB 11.1.1.4 install error: Specified oepe location is not a valid location

I'm re-installing SOA suite 11.1.1.4.

The OSB I have is 11.1.1.4. (ofm_osb_generic_11.1.1.4.0_disk1_1of1.zip)

While installing OSB I encountered this "specified oepe location is not a valid location". However, the location I point to is the matching version 11.1.1.4 OEPE (oepe-galileo-all-in-one-11.1.1.4.0.201001281326-win32).

After struggling for a long time, I downloaded oepe-helios-all-in-one-11.1.1.6.1.201010012100-win32.zip, that did the trick.

I am not sure you see the irony, the matching verion OEPE doesn't work with OSB. I had to use a higher version OEPE 11.1.1.6. oh, well :-(

Jdeveloper extension update

I always ran into issues when updating jdeveloper extensions after a fresh install. The standard steps are: Jdeveloper -> help ->  check for udpates, then select the extensions you need.

Although I don't have proxy, but a popup always asks me to use this proxy "emeacache.uk.oracle.com", I uncheck proxy, the update ended up doing nothing.

It didn't help, their "official" extension center (http://www.oracle.com/ocom/groups/public/@otn/documents/webcontent/131167.xml) doesn't even have the SOA composite editor :(

Well, for today, this is how it is "working" for me: like I said, I do not use proxy from my network to internet, but after numerous failed attempts, i finally logged onto a VPN. It beats me that within the VPN, the update actually worked! Go figure! I'm logging it here, in case, I have to go through the same thing in 6 month again...

Thursday, October 20, 2011

AIA Requester Process Fail to Deploy on Server Restart - Abstract WSDL Issue

I have seen many posts on this issue. People offered different solutions. Here is how I figured out my solution.

When an EBS is generated based on WSDL from Oracle MDS, it's very likely that your EBS will not have a locally associated WSDL or XSD (I figure if you choose to copy WSDL to local project folder, if that's an option in JDeveloper wizard, you may get a local duplicate of the WSDL from MDS).

After EBS is deployed, now you create a Web Service call to this EBS in your Requester process. However, since the EBS doesn't have an associated abstract WSDL on the deployment server (unlike other typical BPEL process), so your JDeveloper will treat the call as an external web service call, therefore, generate a "xxxRef.WSDL" for your EBS call. Also JDeveloper inserted two a few concrete WSDL references in the project. And two of these places really mattered for me, in order for my Requester process to auto deploy on server restart.

Here are the two places I had to change to make it work.

1.In composite WSDL I had to make this change (the high lighted wsdlLocation used to point to concrete WSDL)

    <reference ui:wsdlLocation="oramds:/apps/AIAMetaData/AIAComponents/EnterpriseBusinessServiceLibrary/Industry/Utilities/EBO/MeterReading/V1/UtilitiesMeterReadingEBSV1.wsdl" name="UtilitiesMeterReadingEBS">
        <interface.wsdl interface="http://xmlns.oracle.com/EnterpriseServices/Core/MeterReading/V1#wsdl.interface(UtilitiesMeterReadingEBS)" xmlns:ns="http://xmlns.oracle.com/sca/1.0"/>
        <binding.ws port="http://xmlns.oracle.com/EnterpriseServices/Core/MeterReading/V1#wsdl.endpoint(CreateMeterReadingEBS/UtilitiesMeterReadingEBS_pt)" location="http://soadev.example.com:7001/soa-infra/services/Foo/CreateMeterReadingEBS/CreateMeterReadingEBS?WSDL" xmlns:ns="http://xmlns.oracle.com/sca/1.0"/>

2. Inside "xxxRef.WSDL" where location used to point to concrete WSDL:

    <import namespace="http://xmlns.oracle.com/EnterpriseServices/Core/MeterReading/V1"
    location="oramds:/apps/AIAMetaData/AIAComponents/EnterpriseBusinessServiceLibrary/Industry/Utilities/EBO/MeterReading/V1/UtilitiesMeterReadingEBSV1.wsdl"/>


That's about it. Redeploy, and it worked for me.

Monday, October 17, 2011

implement BPEL with existing WSDL

It is generally straight forward to create a BPEL process (composite) with an existing WSDL. When the wizard prompts to select "synch/asynch" etc, move down the list and select existing WSDL. Notice that JDeveloper generates a wrapper WSDL for the existing WSDL.
If you view the WSDL of your deployed composite, you will see an "import" section in your WSDL that references the real WSDL.
A WSDL generally has one or more bindings defined, and one or more end points (service section) defined. The end points URL is likely not the same as your composite end points URL, since the existing WSDL obviously came from somewhere else. If you leave the endpoints unchanged, then it may potentially leads to big time confusion.

The reason is this. Even though the endpoints are incorrect, you can still deploy your composite, and if you test your composite from the "em" console, it actually works. However, if you try to invoke the composite web service from an external client, such as SOAP UI, a Java client or even from a browser (not the "em" console), then you will see your web service call will fail, because the endpoint URL is incorrect.

There are two ways to deal with this problem.

1) after deploying your composite, you can find out the true URL of your composite from the "em" console. You can update your WSDL with the correct URL.

2) the above solution ends up with hard coded endpoint URL, that's not ideal. The preferred way is to let SOA server decide the URL for you dynamically. To do that, go to the WSDL, comment out (or delete) the entire "Binding" and "Service" section. Now SOA server will treat the existing WSDL just like an abstract WSDL and fill in the binding and service section dynamically for you.

Saturday, October 15, 2011

Deployment Plan File not Taking Effect?

I suppose there can be many reasons that the deployment file plan does not work properly.

I ran into a perticular situtation where my deployment plan file won't take effect, so all my replacement strings have no effect. It baffled me for a long time. I accidentally figured out the reason today.

In my particular case, I have an AIA EBS process, which uses mediator to route services. So there is no XSD and no WSDL for the project. So the generated plan file has this section at the bottom:
   <wsdlAndSchema name="">
      <searchReplace>
         <search/>
         <replace/>
      </searchReplace>
   </wsdlAndSchema>
I think the empty "name" attribute renders the plan file invalid, therefore it won't take effect. I simply changed it to 
   <wsdlAndSchema name="NONE">
that did the trick for me. With that change, my plan file worked without problem.

Wednesday, October 12, 2011

oracle.tip.adapter.file.outbound.FileReadInteractionSpec class not found

For more information about file adapter, please refer to this document:
Oracle® Fusion Middleware
User's Guide for Technology Adapters
11g Release 1 (11.1.1)
E10231-02

A few weeks ago, I encountered this class not found error on "oracle.tip.adapter.file.outbound.FileReadInteractionSpec" while using JCA file adapter in SOA 11.1.1.5.

It turned out that Oracle just decided to move their class around a bit :(

I fixed my issue by editing the .jca file:

        <interaction-spec className="oracle.tip.adapter.file.outbound.FileIoInteractionSpec">
        <!--interaction-spec className="oracle.tip.adapter.file.outbound.FileReadInteractionSpec"-->
            <property name="SourcePhysicalDirectory" value="foo1"/>
            <property name="SourceFileName" value="bar1"/>
            <property name="TargetPhysicalDirectory" value="foo2"/>
            <property name="TargetFileName" value="bar2"/>
            <property name="Type" value="COPY"/>
        </interaction-spec>
Look closely, you can see they change the class to "oracle.tip.adapter.file.outbound.FileIoInteractionSpec".

Additionally, you can choose which of these parameters are used as defined here, or overwritten dynamically by the BPEL variables. The following example shows how to replace 3 parameters at run time, but using "TargetDirectory" from jca, although jca internally references it as "TargetPhysicalDirectory" (I guess that's called undocummented Oracle feature :)

         <invoke name="InvokeCopyFile" bpelx:invokeAsDetail="no"
                  inputVariable="Invoke_FileMove_InputVariable"
                  outputVariable="Invoke_FileMove_OutputVariable"
                  partnerLink="JcaCopyFile" portType="ns2:FileMove_ptt"
                  operation="FileMove">
            <bpelx:inputProperty name="jca.file.SourceDirectory"
                                 variable="sourceDirectory"/>
            <bpelx:inputProperty name="jca.file.SourceFileName"
                                 variable="sourceFileName"/>
          <!-- ### do not assign target directory, pick up from jca directly, so it can be ###
            <bpelx:inputProperty name="jca.file.TargetDirectory"
                                 variable="targetDirectory"/>
                                 -->
            <bpelx:inputProperty name="jca.file.TargetFileName"
                                 variable="targetFileName"/>
          </invoke>

2013-02-20 update:
with jdev 11.1.1.6 and bpel 2.0, here is the syntax:

        <invoke name="InvokeMoveOperation"
                partnerLink="moveFile2Error" portType="ns3:FileMove_ptt"
                operation="FileMove"
                inputVariable="InvokeMoveOperation_FileMove_InputVariable"
                outputVariable="InvokeMoveOperation_FileMove_OutputVariable"
                bpelx:invokeAsDetail="no">
          <bpelx:toProperties>
            <bpelx:toProperty name="jca.file.SourceDirectory" variable="sourceDirectory"/>
            <bpelx:toProperty name="jca.file.SourceFileName" variable="filename"/>
            <bpelx:toProperty name="jca.file.TargetDirectory" variable="targetDirectory"/>
             <bpelx:toProperty name="jca.file.TargetFileName" variable="filename"/>
          </bpelx:toProperties>
        
                </invoke>             

Thursday, September 15, 2011

dateTime duration with XSLT in SOA 11g

This tiny post reminds me the exact reason why I started this blog. I want to collect the things I learned using SOA.

It took me a long time to figure out this tidbit with XSLT before, but I just spent half a day to re-figure it out again. 

In my XSLT I need to calculate the duration based on two dateTime fields. So I used this expression:
    <xsl:variable name="dur">
      <xsl:value-of select="xsd:dateTime($endDt)-xsd:dateTime($stDt)"/>
    </xsl:variable>

However, with JDEV 11g, the default XSLT stylesheet version is "1.0". The above expression doesn't work with "1.0". I have to change the version to "2.0". That's all. With that, "dur" will have a value like "PT2H5M". Then you can maniplate it.

Now I have recorded it here, so I don't have spend another 5 hours to "re-discover" it next time.

Tuesday, September 13, 2011

Tweaking auto-generated XSLT may result in "Element not found" error

I have a JDEV generated XSLT like below.

<?xml version="1.0" encoding="UTF-8" ?>
<?oracle-xsl-mapper
  <!-- SPECIFICATION OF MAP SOURCES AND TARGETS, DO NOT MODIFY. -->
  <mapSources>
    <source type="WSDL">
      <schema location="../BPELProcess1.wsdl"/>
      <rootElement name="process" namespace="http://xmlns.oracle.com/test/testImdXform/BPELProcess1"/>
    </source>
  </mapSources>
  <mapTargets>
    <target type="XSD">
      <schema location="../xsd/D1_InitialLoadIMD.xsd"/>
      <rootElement name="D1-InitialLoadIMD" namespace="http://oracle.com/D1-InitialLoadIMD.xsd"/>
    </target>
  </mapTargets>
  <!-- GENERATED BY ORACLE XSL MAPPER 11.1.1.5.0(build 110418.1550.0174) AT [TUE SEP 13 15:55:59 MST 2011]. -->
?>
<xsl:stylesheet version="1.0"
...
xmlns:ns1="http://oracle.com/D1-InitialLoadIMD.xsd"
...>
  <xsl:template match="/">
    <ns1:D1-InitialLoadIMD>
      <ns1:version>
        <xsl:value-of select="/client:process/client:input"/>
      </ns1:version>
    </ns1:D1-InitialLoadIMD>
  </xsl:template>
</xsl:stylesheet>

Looking at the file, it is very tempting to replace "ns1" with default namespace, i.e. xmlns="http://oracle.com/D1-InitialLoadIMD.xsd", then get rid of "ns1" from the file.

The result may look clean.

<xsl:stylesheet version="1.0"
...
xmlns="http://oracle.com/D1-InitialLoadIMD.xsd"
...>
  <xsl:template match="/">
    <D1-InitialLoadIMD>
      <version>
        <xsl:value-of select="/client:process/client:input"/>
      </version>
    </D1-InitialLoadIMD>
  </xsl:template>
</xsl:stylesheet>

However, this is a fatal attraction. Even though the content should be technically equivalent, but I got an  "Line Number:(13) : Error: "D1-InitialLoadIMD" Element not Found in Target Schema".

It cost me a few hours to sort it out. The morale of the story, be careful when you mess up the namespace with the auto-generated XSLT.

Wednesday, August 31, 2011

Replace / rename namespace in OSB

I have an input schema without a name space, like <a><b><c>blah</c></b></a>.

I need to convert it into <a xmlns="http://x.y.com/z"><b><c>blah</c></b></a>. Beware this is equavilant to <foo:a xmlns:foo="http://x.y.com/z"><foo:b><foo:c>blah</foo:c><./foo:b></foo:a>

I have tried various ways, including use "fn-bea:serialize($arg-items)" and "contact()", just couldn't make it work. I found my solution by browsing online. then trial and error.

First of all, you can always use XSLT to transalte to new namespace. But I want to use the built-in activites to do it.

My answer is to use "rename" activity.

In my case, I put in

XPath: ".//*"
In Variable: myVar (which contains the source XML)
localname: (leave it empty)
Namespace: http://x.y.com/z"

This will take care of all elements of <b> and down. So you I have to do another rename, just for <a> (If you are wondering, I actually tried XPath: "//*". It didn't work).

So for the 2nd rename:
XPath: "."
In Variable: myVar (which contains the source XML)
localname: (leave it empty)
Namespace: http://x.y.com/z"

I'm quite sure you can do (or leave xpath as ".")
XPath: "./a"
In Variable: myVar (which contains the source XML)
localname: a
Namespace: http://x.y.com/z"

Monday, August 29, 2011

An Oracle standard DB install issue with OracleMTSRecoveryService

I got too busy with work, lots things happened that I should post it here. Let me start with a small one.

During Oracle 11g DB (standard version) install, I run into an error, "Error in starting the service. The service OracleMTSRecoveryService was not found".

If I check the service panel, i can see this:

I ignored it a few times. Then I decided to take a closer look and found a work around. here is my solution.
When this error box pops up, keep it there. Fire up regedit go to "computer\hkey_local_machine\system\controlset001\service\OracleMTSRecoveryService". Double click on ImagePath, then change the path to where your Oracle is actually installed.

In my case, the ImagePath has a value of
C:\Oracle\product\11.2.0\dbhome_1\bin\omtsreco.exe "OracleMTSRecoveryService"
I had to change it to:
C:\app\myaccount\product\11.2.0\dbhome_1\bin\omtsreco.exe "OracleMTSRecoveryService"

then click on "retry". that solved my problem.

You may need to look around to see where your DB is actually installed. By defatul, it is installed under "c:\app\yourAcctName".

Tuesday, June 7, 2011

Download and install workflow-001-DemoCommunitySeedApp.zip

Just bought Getting Started with Oracle BPM Suite 11gR1 - a hands-on tutorial. Quite disappointed with the install instructions!

First of all, the download links are all broken. I managed to get the demo file from here
https://soasamples.samplecode.oracle.com/files/documents/660/881/workflow-001-DemoCommunitySeedApp.zip

Then when I tried to follow the README and to install it, I have to do the following for my local install:

1. edit setAntEnv.bat,
set JAVA_HOME=C:\Oracle\Middleware\jdk1.6.0_25
set MW_HOME=C:\oracle\Middleware
2. ant seedDemoUsers -Dbea.home=C:/Oracle/Middleware/  -Doracle.home=C:/Oracle/Middleware/Oracle_SOA1 -Dtarget=soa_server1 -Dadmin.url=t3://localhost:7001 -Dserver.url=http:///localhost:8001 -Dadmin.name=weblogic -Dadmin.pwd=welcome1
Basically, MW_HOME is "C:/Oracle/Middleware/Oracle_SOA1" and BEA_HOME is "C:/Oracle/Middleware" for me.

Just between 1 and 2, mw_home suddenly means different things. Go figure.

Tuesday, April 5, 2011

Base64 Code Snippets for OSB and BPEL

This post applies to SOA suite 11.1.1.3.

I need to decode a base64 payload in my OSB proxy service. Here is a native solution that I came up with:

1. The java source:
//import org.apache.xerces.impl.dv.util.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import java.util.*;
public class MyBase64
{
  public static String decode(String x)
  {

 try {
 String path = "file:///"+System.getenv("ALSB_HOME") + "/../modules/com.bea.core.apache.xercesImpl_2.8.1.jar";
  URL[] urls = new URL[] { new URL(path) };
  ClassLoader loader = new URLClassLoader(urls);
  Class<?> cls = loader.loadClass("org.apache.xerces.impl.dv.util.Base64");
  Method theMethod = cls.getMethod("decode", String.class);

  return new String( (byte[])theMethod.invoke(null, x));
 }
 catch(Exception e)
 {
  e.printStackTrace();
  return "decode failed";
 }

  }
  public static void main(String args[])
  {
   System.out.println(decode("Zm9vIGJhciBhbmQgY2FyIHRyeSBhZ2Fpbg=="));
 }
}

2. complie java source (you need to add C:\Oracle\Middleware\modules\com.bea.core.apache.xercesImpl_2.8.1.jar to your compiler classpath, your path maybe different)
3. jar it up
4. add jar to your osb project. (In your project, choose "Create Resource", select "JAR" under "Utility")
4. use in your java callout


Here is a BPEL snippet to encode base64

    <bpelx:exec name="base64EncodeTemp" version="1.5" language="java">
      <![CDATA[     
        String sTemp = (String)getVariableData("temp");   
        addAuditTrailEntry("Covert Temp to Byte Array  : \n" + sTemp);
        byte[] bTemp = new byte[sTemp.length() / 2]; 
        for (int i = 0; i < bTemp.length; i++) { 
          bTemp[i] = (byte) Integer.parseInt(sTemp.substring(i*2, (i*2)+2), 16); 
       } 
       sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();   
       String encodedTemp = encoder.encodeBuffer(bTemp);   
       setVariableData("temp", encodedTemp);]]>
    </bpelx:exec>

Monday, April 4, 2011

OSB complains JCA class cannot be found

Recently I experienced some problems with OSB complaining about JCA class cannot be found. My SOA suite version is 11.1.1.3.
As I work on OSB JCA DB adapters, all of a sudden I see errors like the following:
Invalid JCA transport endpoint configuration, exception: javax.resource.ResourceException: Cannot locate Java class oracle.tip.adapter.db.DBWriteInteractionSpec
Invalid JCA transport endpoint configuration, exception: javax.resource.ResourceException: Cannot locate Java class oracle.tip.adapter.db.DBActivationSpec
This initially gives me the impression that someone touched the startup script that messed up the classpath. So I modified the startup script to hard code the jar files in the classpath. That didn’t really solve the problem.
After sifting through log files and comparing config.xml, I noticed that my OSB server is missing from the DB adapter deployment target list.
  <app-deployment>
    <name>DbAdapter</name>
    <target>AdminServer,osb_server1,soa_server1</target>
  </app-deployment>

You can either edit your config.xml file to add it back in. Or go to weblogic console -> deployments  -> DbAdapter -> Targets and make sure “osb_server1” is checked.
I think there is a bug that can cause this to happen. I don’t have an exact way to reproduce it. As you work on OSB JCA adapter services, this error may creep up on you.