Showing posts with label BPEL. Show all posts
Showing posts with label BPEL. Show all posts

Monday, November 26, 2012

more notes on java embedding

I noted in the past on BPEL java embedding http://yuanmengblog.blogspot.com/2012/04/few-bpel-java-embedding-notes.html

here are some additional notes:

1. importing syntax:

I'm using BPEL 2.0 this time. This is the importing syntax I'm using now, not sure if it's BPEL 2.0 thing. For sure it's different from my previous post:

add imports right above partner links and right below name spaces.


  <import location="oracle.xml.parser.v2.XMLElement" importType="http://schemas.oracle.com/bpel/extension/java"/>      
  <import location="java.io.File" importType="http://schemas.oracle.com/bpel/extension/java"/>      

2. Two ways to get and set variables:

2.1. getting and setting string variables:
   nothing fancy, you can do straight:
    String foo = (String) getVariableData("foo");
    setVariableData("foo", "bar");

2.2. If you need to get to an Xpath in an element, then you have to do something like

XMLElement srcElem = (XMLElement) getVariableData("inputVariable", "payload", "/client:foo/client:bar");      
String bar = srcElem.getTextContent();      

remember you need to add "import" like in step 1. 

3. Gotcha's

Although it's very tempting, don't do this:
   String srcElem = (String) getVariableData("inputVariable", "payload", "/client:foo/client:bar");   
it doesn't work that way.

If you don't want to deal with the hassles of "importing" and casting, here is a recommended way to go around it. 
Using above example:
 a) create a BPEL string variable, call it "bar"
 b) inside BPEL, assign ("inputVariable", "payload", "/client:foo/client:bar") to the "bar" variable
 c) inside your java embedding, you can use get/set freely on "bar", just like in step 2.1 above.

Thursday, August 30, 2012

count() vs. countNodes() in BPEL 2.0


I have wrestled with these two since 10g . However, I still mix them up when I use them in BPEL 2.0. The function signature of count() has changed since BPEL1.1.

For the record, here is the scoop on these two functions in BPEL 2.0:

I have created a simple test BPEL based on the sample schema (at the end of this post).

I tested count() and countNodes() like below:

#1 count($outputVariable.payload/client:result)

It shows 0. Please note "result" is optional based on the XSD. Additionally, please note that if you enter an invalid path, such as “$outputVariable.payload/foo/bar”, JDev won’t compile it. So count() only allows valid xpath for the variable type, check #5 of countNodes() below to see more on this.

#2 count($inputVariable.payload/client:input)

It shows 1 as expected.

#3 ora:countNodes('outputVariable', 'payload', '/client:processResponse/client:result')

It shows 0, same as case #1. However, pay close attention to two things: first argument is the variable name as a string, not “$variable” as it appears in count(). Additionally, the 3rd argument uses the full path “/client:processResponse/client:result”. It includes “client:processResponse” section.

 #4 ora:countNodes('inputVariable', 'payload', '/client:process/client:input')

     It shows 1, just like in case #2. However, pay attention that first argument is the string name of the variable. Second argument is the “part” of the message type. Third argument needs the full path like “/client:process/client:input”. In the case of count() function, it appears that it skipped the “root” element “client:process” after payload.

#5 ora:countNodes('outputVariable', 'payload', '/client:input/test_invalid_path)

Finally, this one shows 0 as expected. The point here is to show that you can enter a path that is not defined in your XSD. This may come in handy if you have a payload that does not conform to your input schema, or you simply do not know the schema beforehand.

Here is the schema, please note that I have made "result" optional:

<?xml version="1.0" encoding="UTF-8"?> 
<schema attributeFormDefault="unqualified"
            elementFormDefault="qualified"
            targetNamespace="http://xmlns.oracle.com/cis/foo/BPELProcess1"
            xmlns="http://www.w3.org/2001/XMLSchema">
            <element name="process">
                        <complexType>
                                    <sequence>
                                                <element name="input" type="string" minOccurs="0"/>
                                    </sequence>
                        </complexType>
            </element>
            <element name="processResponse">
                        <complexType>
                                    <sequence>
                                                <element name="result" type="string" minOccurs="0"/>
                                    </sequence>
                        </complexType>
            </element>
</schema>

Sunday, August 26, 2012

Search and Replace in Composite Configuration Plan File

SOA 11g provides a configuration plan file for composite deployment. A common use is to search and replace hosts and ports depends on the platform (dev, test, qa, prod) you are deploying to. The question is when do those search / replacement take place?

If you wonder why do I ask this seemingly obscured question, let's take another look at it.

Suppose you do development on server "soaDEV.mybusiness.com", and SOA runs on port 8001. Then you need to migrate your work to "soaPRD.mybusiness.com", and SOA runs on port 80 over there.

So your plan file may contain something like:

  <search>soaDEV.mybusiness.com:8011</search>
  <replace>soaPRD.mybusiness.com:80</replace>

When you click on "Deploy" and pick your configuration plan file, a common misconception is that "soaDEV.mybusiness.com:8001" will be magically replaced, and "soaDEV.mybusiness.com" is almost irrelevant. However, if you shut down "soaDEV" server, you will notice that JDEV will fail the compilation.


When you click "Deploy" in JDev, it's actually a two-step process. First Jdev generates the jar (sar) file. Then it uploads (deploys) the jar to the SOA server (you can actually do these two steps manually. First compile / generate the jar file. Then go to EM console to deploy the composite.)

The search / replacement only takes place during the 2nd stage. When SOA server receives the composite jar file, it does a second compilation using BPEL Compiler. So when JDEV compiles the BPEL source code, it still requires your original "soaDEV.mybusiness.com" to be up and running. It still needs to reference the WSDL from port 8001on "soaDEV".

Now we know the facts, I still have this question that bugs me all the time. Why can't (won't) JDEV do search and replacement before the compilation? I don't truly know the answer. I'm sure there is a fundamental answer to this question.

I always have this eerie feeling that 9 months after you have finished your production deployment, you still need to keep your soaDEV server running in order to support your soaPRD environment. Because Jdev needs to reference soaDEV in order to compile. What about the potential inconsistency between soaDEV and soaPRD 9 months after or even longer?


Wednesday, August 22, 2012

BPEL Wait, it's synch vs. asynch?

In BPEL process if you use "wait", the result may depend on if it's synch or asynch. I found it out the hard way. I suspect it's documented somewhere by Oracle. I just haven't found it.

Synch: if you use "wait" for 3 seconds in a synch BPEL, you'll get a time out exception. I don't know why it does that. If you wait for 1 or 2 seconds, it simply ignores the wait. That's because the server uses "MinBPELWait" as the threshhold, the default is 2 sec.

Asych: works without any problem.

If you are too deep into your "synch" BPEL process, and doesn't want to start allover, just go to your WSDL, take out the "output" in your operation. Then go to your BPEL, take out the last reply. That converts your synch into "one-way", essentially it's almost the same as "asynch", you just don't have the callback operation.

Additionally, you can go clean out the synch response message etc. Or you can add callback in the WSDL to make it asynch.


Saturday, August 18, 2012

"Pure SQL" problem with JCA Adapter


I have wasted nearly a day chasing down a ghost problem with SOA Jca DB adapter. I thought I'll make a note of it here.

The database is SQLServer,we use SQLservre JDBC4.0 driver. I use "pure SQL" query for the adapter as following:

SELECT top 1 A.TNDR_CTL_ID, B.ACCOUNTING_DT
FROM PS_CI_TNDR_CTL A
,PS_CI_DEP_CTL B
WHERE A.TNDR_SOURCE_CD = #source
AND A.DEP_CTL_ID = B.DEP_CTL_ID
AND B.ACCOUNTING_DT <= convert(datetime,#date)
and A.TNDR_CTL_ST_FLG = '10' order by B.ACCOUNTING_DT desc


However, when I ran the BPEL test, it generated a nonsense error: 

oracle.sysman.emSDK.webservices.wsdlapi.SoapTestException: Client received SOAP Fault from server : Exception occured when binding was invoked. Exception occured during invocation of JCA binding: "JCA Binding execute of Reference operation 'getTenderCtrlId' failed due to: Pure SQL Exception. Pure SQL Execute of SELECT top 1 A.TNDR_CTL_ID, B.ACCOUNTING_DT FROM PS_CI_TNDR_CTL A ,PS_CI_DEP_CTL B WHERE A.TNDR_SOURCE_CD = ? AND A.DEP_CTL_ID = B.DEP_CTL_ID AND B.ACCOUNTING_DT <= convert(datetime,?) and A.TNDR_CTL_ST_FLG = '10' order by B.ACCOUNTING_DT desc failed. Caused by java.sql.SQLException: [FMWGEN][SQLServer JDBC Driver][SQLServer]Warning: Fatal error 823 occurred at Aug 17 2012 4:29PM

I initially thought this was an issue of multiple input parameters. So I stripped my query to the minimum as:

SELECT 
A.TNDR_CTL_ID, B.ACCOUNTING_DT 
FROM 
PS_CI_TNDR_CTL A , PS_CI_DEP_CTL B


and I still get that out of range error. That's when I tested the inner join and found a working query.


The query below is logically equivalent to the original version, except this one uses "inner join". And this one works. 

SELECT top 1 PS_CI_TNDR_CTL.TNDR_CTL_ID,
  PS_CI_DEP_CTL.ACCOUNTING_DT
FROM PS_CI_TNDR_CTL
INNER JOIN PS_CI_DEP_CTL
ON PS_CI_TNDR_CTL.DEP_CTL_ID        = PS_CI_DEP_CTL.DEP_CTL_ID
AND PS_CI_DEP_CTL.ACCOUNTING_DT    <= CONVERT(DATETIME,#dt)
WHERE PS_CI_TNDR_CTL.TNDR_SOURCE_CD = #source
AND PS_CI_TNDR_CTL.TNDR_CTL_ST_FLG  = '10'
ORDER BY PS_CI_DEP_CTL.ACCOUNTING_DT DESC

Beats me!


Tuesday, April 24, 2012

A Few BPEL Java Embedding Notes

1. Error: SCAC-50012
    check \SCA-INF\classes\scac.log file to find more details.

    Common issues:

    #1.1) check that you added the proper import at the top of .bpel file
     
     for example (right after <:process ...> element, and before partner links   
     <bpelx:exec import="java.util.*"/>
    <bpelx:exec import="java.lang.*"/>
    <bpelx:exec import="java.math.*"/>
    <bpelx:exec import="org.w3c.dom.Element"/>
    <bpelx:exec import="oracle.xml.parser.v2.*"/>   
    <bpelx:exec import="com.foo.bar.*"/>
    <bpelx:exec import="com.collaxa.cube.ws.wsif.providers.java.*"/>

     #1.2) check your syntax carefully. When in doubt, comment out as much as you can.

2. incorparte your own special classes and jars
    create your class jar file, place it under "SCA-INF/lib" folder

3. get/set your variables
    For simple string variables, it's straight forward. If you need to process the XML payloads, use forms like this:
 oracle.xml.parser.v2.XMLElement targetElem =
    (oracle.xml.parser.v2.XMLElement) getVariableData("myVarName", "payload",  "/ns3:foo/ns3:bar/ns3:car");  where "ns3" is defined precisely as it appears at the top of your .bpel file.

you can manipulate this element with functions, here are a few common functions: "getParentNode, getTextContent, cloneNode, setTextContent, insertBefore" etc.

4. if you need to debug, add some log entries using "addAuditTrailEntry".

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.