Oracle Certification – Oracle SOA Foundation Practitioner(1Z0-451)

Just completed Oracle Service Oriented Architecture Infrastructure Implementation Certified Expert certification.

Thanks to @soacommunity for sending a free voucher (for clearing Oracle SOA Presales specialization(for partners))  for Oracle SOA Foundation Practitioner(1Z0-451) exam.

The exam did cover all the topics specified in the catalog.

In addition, these are few tips(from what I remember) I would suggest doing for newbies (Apart from going through the developers guide):

  1. Understand how Oracle SOA Suite 11g compliments SCA model and how composite.xml plays a key role in it
  2. Create a custom assertion in OWSM policy and try to attach as a client policy in any sample reference binding. (Will let you go through most of the things needed for OWSM).
  3. Create a hello world “If Then Rule” and a Decision Table and try to publish it as a standalone component as well as part of a composite.
  4. Create a composite with Human Task and try to observe the different settings that you can do at a design time and a run time.
  5. Understand the new BPEL activities introduced in SOA Suite 11g.
  6. Create a BPEL process with email activity/Human task and understand how User Messaging Service is used there to send email/notification.

If you are OPN Member, Try these:

  1. Go through the trainings mentioned in the  Guided Learning path specified by Oracle. Even if you are a seasoned SOA expert, The quiz in these trainings would trick you with theoretical terms.(Atleast I got fooled in few)
    https://competencycenter.oracle.com/opncc/full_glp.cc?group_id=13304 (Need to be a OPN Member)
  2. Try to attend OWSM trainings that are available for partners.

Good Luck !

Where did my Order Go? Tracking/Searching BPEL Instances by Business Key Fields

You might often get this question from users during support and you often be in a situation to see if the order reached JMS Producer or if it EBF failed for this order or whether it entered into SOA itself!

This post discuss about various message tracking mechanisms Oracle SOA provides and how business Key identifiers can be used in tracking SOA instances.

As SOA is getting mature, the ability to track instances in SOA is getting more and better!

The Classic Title/Name method

For the very old 10g release up to latest 11g release, we have a way of setting a title to a BPEL Instance(in 10g) and to a Composite(in 11g).

There are various blogs that talks about that.

However a thing to notice in 11g is you have two titles,

  1. Composite Instance Title:
    1. Title for a Composite Instance
    2. Stored in TITLE column of COMPOSITE_INSTANCE table.
    3. Can be set through ora:setCompositeInstanceTitle() xpath API or setCompositeInstanceTitle in Java Embedding.
    4. Searchable through Enterprise Manager using Name column in Instance Search page.
  2. BPEL Title:
    1. Title for a BPEL Instance.
    2. Stored in TITLE column of CUBE_INSTANCES table.
    3. Can be set through setTitle API in Java Embedding.
    4. Not Searchable through Enterprise Manager

Composite/BPEL Indexing

In 10.1.3.4, Oracle Introduced Indexing in BPEL through CI_INDEXES table and a text box in left side of Instance Search page:

To find the current values of the instance indexes in 10.1.3.4, Go to any Instance, Click More.

To Query from database using indexes, use the following query using CUBE_INSTANCE and CI_INDEXES tables:

SELECT *
  FROM ORABPEL.CUBE_INSTANCE t1,
  ORABPEL.CI_INDEXES t2
WHERE
  t1.CIKEY = t2.CIKEY
  AND t2.INDEX_1 = <Business Key>

You can set the index to a BPEL instance by using setIndex API in Java Embedding Activity. You can set up to 6 indexes – So 6 searchable business keys for an instance.
With 11g Composites, Oracle replicated the same set of index columns in COMPOSITE_INSTANCE table, but, the instance search in enterprise manager doesn’t have index based search yet(as of patch set 2).   But since the fields are available in database, we could write our own xpath function to set indexes like below:

public class SetCompositeInstanceIndex implements IXPathFunction {
 public Object call(IXPathContext context, List args) throws XPathFunctionException{
      try{
         int index_number;
         String index_value;
         if(args == null || args.size() <2){return "";}
         try{
           index_number = Integer.parseInt(args.get(0));
         }(NumberFormatException E){
            throw new XPathFunctionException(E.getMessage());
         }
         if(index_number <1 || index_number >6){
            throw new XPathFunctionException("Invalid Index Number: " + index_number);
         }
         index_value = (String)args.get(1);
         Map props = (Map)context.getVariableValue(null, null, "xpath-function-data");
         ICubeContext ctx = (ICubeContext)props.get("ICubeContext");
         long cid = Long.parseLong(CubeContextHelper.getCubeInstance(ctx).getCompositeInstanceId());
         InstanceManager mgr = CubeContextHelper.getServerManager(ctx).getCubeServiceEngine().getInstanceManager();
         CompositeInstanceBean bean = mgr.getCompositeInstanceBean(cid);
         switch(index_number){
           case 1: bean.setIndex1(index_value); break;
           case 2: bean.setIndex2(index_value); break;
           case 3: bean.setIndex3(index_value); break;
           case 4: bean.setIndex4(index_value); break;
           case 5: bean.setIndex5(index_value); break;
           case 6: bean.setIndex6(index_value); break;
         }
         mgr.persistCompositeInstanceBean(bean);
         return "";
     }catch (Exception e){
        throw new XPathFunctionException(e.getMessage());
     }
   }
}

Although the search is still not available in EM, we could use DB to easily find the instance using the below query:

SELECT *
  FROM
    DEV_SOAINFRA.COMPOSITE_INSTANCE
  WHERE
    INDEX1 = <Business Key>

Composite Sensors

11g feature – Recommended approach if you have variable number of business key to be used in the search. If you have just one business key (title would serve the purpose) and index could be used for up to 6 values (No EM based search though for now).

  1. Stored in COMPOSITE_SENSOR_VALUES table.
  2. Extensible to any number of keys as it is stored at row level as key value pairs
  3. Can be Searched through Enterprise Manager – Only within Composite Instances page, I did not find them yet in all instance search page.

To set the composite sensor value, right click the Service in the composite, select Composite Sensors – Add key – Select Expression/Variable. You can also add filter condition based on expression.

Select Expression/Variable/Properties

The fields can be searched from Enterprise Manager in Composite Instances page:

To query from the database, it is as simple as querying Composite_Sensor_value table using Sensor name and component name.

SELECT *
 FROM
   DEV_SOAINFRA.COMPOSITE_SENSOR_VALUE
 WHERE
   COMPONENT_NAME='messagetracking_client_ep'
   AND SENSOR_NAME='SearchKey1'
   AND STRING_VALUE = '12345'

Other Observations

From the observations on Composite_instance table, Oracle has also introduced a field called “TAGS” which can also be used by writing custom xpath function. However, all these would be useful if they could get them into instance search page in enterprise manager, otherwise it would be only at database level.

While all the methods listed above are intrusive and if it has to be applied to existing instances, the code change have to happen and if you have a lot of them, it would be difficult to change the existing. If you are looking from some non-intrusive ways, go through this other article by Chintan Shah here where he shared about some intrusive ways of setting title to the existing flows by using EJB Poller on Cube Instance table. (I haven’t tried yet though)

Have you been there in the same situation and what’s your solution was, Please share!

Siebel Webservice Authentication & BPEL

Siebel uses custom SOAP Headers to do authentication for inbound webservices.

The namespace used with Siebel Authentication and Session Management SOAP headers is:

xmlns="http://siebel.com/webservices"

It expects two elements as part of SOAP Header:  UsernameToken & PasswordText

More details on Siebel Authentication management can be found here.

Adding to this, While generating wsdl from Siebel, it doesn’t put SOAP headers as part of it.  It has to be inserted manually in the generated WSDL as follows:

Since these elements have its own namespace, we have start by defining custom XSD elements in the WSDL and define Message appropriately and set SOAP Headers.

Keep in mind that each element is a seperate header element and not part of any parent element.  So we defined message with two parts, each part have its own element as follows:

<!-- Define XML Element -->

<xsd:schema elementFormDefault=”qualified” attributeFormDefault=”unqualified” targetNamespace=”http://siebel.com/webservices&#8221; xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; xmlns=”http://siebel.com/webservices”&gt;
<xsd:element name=”UsernameToken” type=”xsd:string”/>
<xsd:element name=”PasswordText” type=”xsd:string”/>
</xsd:schema>

Note: Define prefix as xmlns:seblService = “http://siebel.com/webservices&#8221;

<!– Define Message Type –>

<message name=”SiebelInputHeaderMessage”>
<part name=”userName” element=”seblService:UsernameToken”/>
<part name=”passWord” element=”seblService:PasswordText”/>
</message>

<!– Define SOAP Header –>

<operation name=”<Operation Name>”>
<soap:operation soapAction=”<Action Name>”></soap:operation>
<soap:header message=”tns:SiebelInputHeaderMessage” part=”userName” use=”literal”/>
<soap:header message=”tns:SiebelInputHeaderMessage” part=”passWord” use=”literal”/>
<input>
<soap:body use=”literal”></soap:body>
</input>
<output>
<soap:body use=”literal”></soap:body>
</output>
</operation>

Now Create a partnerlink for the WSDL, Create variable for the message type “SiebelInputHeaderMessage” defined in above wsdl.

<variable name=”varSiebelInputHeader” messageType=”ns1:SiebelInputHeaderMessage”/>

Assign the values for the variables appropriately.

<copy>
<from expression=”‘TESTUSER'”/>
<to variable=”varSiebelInputHeader” part=”userName” query=”/ns3:UsernameToken”/>
</copy>
<copy>
<from expression=”‘TESTPASS”/>
<to variable=”varSiebelInputHeader” part=”passWord” query=”/ns3:PasswordText”/>
</copy>

Now set Header variable in the invoke activity of the partnerlink for the above wsdl.

<invoke name=”InvokeSiebelService” partnerLink=”CallSiebel..    bpelx:inputHeaderVariable=”varSiebelInputHeader”/>

That’s it.. Now we are ready to call Siebel inbound Services.

Attached Sample Siebel wsdl here: Account WSDL

As a side note, If something wrong with header, you may get an error like

“Inbound SOAP Message – Session Token is missing or invalid or has expired”.

Siebel doesn’t import BPEL generated wsdls automatically!!

If you ever want to invoke a BPEL process from Siebel using SOAP over http, you will need to import the WSDL generated by BPEL in Siebel.

Typically, a Siebel wsdl doesn’t have inline schemas, all xsds are stored separately and wsdl have imports of those xsds and Siebel  cannot import wsdls/xsds directly from the web.

So few tweaks has to be done before importing the BPEL wsdl into Siebel:

  1. The wsdl has to be downloaded to the local directory where you are trying to import.
  2. All the referring XSDs/wsdls has to be downloaded to local directory as well.
  3. Since all the xsds and wsdl has to be local directory, you need to edit the wsdl to change all remote references to relative local references.
  4. If a BPEL wsdl has imports in multiple <xsd:schema> sections, Place all import statements under one <xsd:schema> section.

(e.g) Change

<schema>

<import namespace=”http://example.com&#8221; schemaLocation=”http://example.com/example1.xsd”/&gt;

</schema>

<schema>

<import namespace=”http://example.com&#8221; schemaLocation=”http://example.com/example2.xsd”/&gt;

</schema>

To

<schema>

<import namespace=”http://example.com&#8221; schemaLocation=”http://example.com/example1.xsd”/&gt;

<import namespace=”http://example.com&#8221; schemaLocation=”http://example.com/example2.xsd”/&gt;

</schema>

If you have faced any other scenario and have some tips in this area, please respond. Thanks

Conditional Dequeue – MQ Adapter

Just a quick tip in MQ Adapter in 10G:

When we use JMS Adapter or AQ Adapter, It’s almost straight forward in the wizard that you can dequeue the message based on Correlation Id which will be prompted as part of the wizard. In AQ Adapter, you can even write SQL where condition while dequeue the message.

But in case of MQ Adapter, the wizard doesn’t show (Atleast till 10.1.3.4) anything to filter upon dequeue.

However you can edit the dequeue WSDL and pass any of the below mentioned paramaters for JCA Operation to conditionally dequeue the message.

FilterByMsgId – This property sets the message filter option based on the
messageId. This property is not mandatory. The value provided for this
property must be a hexadecimal-encoded value for some messageId.

FilterByCorrelId – This property sets the message filter option based on
the correlationId. This property is not mandatory. The value provided
for this property must be a hexadecimal-encoded value for some
correlationId.

FilterByGroupId – This property sets the message filter option based on
groupId. This property is not mandatory. The value provided for this
property must be a hexadecimal-encoded value for some groupId.

Ref: http://www.oracle.com/technology/products/ias/bpel/pdf/10133technotes.pdf

Oracle SOA Suite(10.1.3.x) Installation with ORACLE XE

Nothing new in this article, just a simple screencast and steps on ORACLE SOA Suite installtion with ORACLE XE in windows,  a quick reference for beginners. For detailed steps, please refer ORACLE SOA Suite installation guide.

Downloads:

  1. ORACLE Express Edition
  2. ORACLE Soa Suite 10.1.3.1

 

Step 1: Install Database

Install Oracle Express Edition. 

View Screencast here

Make sure that Oracle Express Edition is installed successfully in your machine. You can do this by logging into the database using system user id.

Step 2: Setup Prerequisites in Database

Oracle SOA Suite requires following three schemas to be present in Database before installation.

  1. ORABPEL
  2. ORAESB
  3. ORAWSM

ORACLE SOA Suite installation comes up with a script called irca which is present in 

<soa_downloded>/install/soa_schemas/irca 

Before running irca script, make sure that correct ORACLE_HOME and JAVA_HOME is set.

Running the irca script creates the above mentioned three schemas.

View Screencast here

Step 3: Install SOA Suite

After clicking the setup in the installaton directory, follow the steps as mentioned in the below screencast.

View Screencast here


Merge Statement: Finding Insert/Update Count with DML Error Logging

This example shows how to find insert/update count in the merge statement using DML Error Logging feature.

-- Create required test tables.

CREATE TABLE inp_tbl(col1 NUMBER, col2 VARCHAR2(30));
CREATE TABLE out_tbl(col1 NUMBER, col2 VARCHAR2(20));

-- Create DML Error Log Table
BEGIN
   DBMS_ERRLOG.create_error_log ('out_tbl', 'err_log_out_tbl');
END;
/

-- Insert test data
INSERT INTO inp_tbl
     VALUES (1, 'Test Data with Error(>10 char)');
INSERT INTO inp_tbl
     VALUES (2, 'Correct Data');
INSERT INTO inp_tbl
     VALUES (3, 'Correct Data');
COMMIT ;

-- Create Package Specification to merge the data.
CREATE OR REPLACE PACKAGE pkg_merge IS
   g_rows_inserted    NUMBER := 0;
   g_rows_updated     NUMBER := 0;
   g_rows_errored     NUMBER := 0;
   g_rows_processed   NUMBER := 0; 

   FUNCTION increment_merge_insert
      RETURN PLS_INTEGER;
   PROCEDURE merge_data (p_comment_str VARCHAR2);
END;
/
SHOW ERRORS 

CREATE OR REPLACE PACKAGE BODY pkg_merge
IS
   FUNCTION increment_merge_insert
      RETURN PLS_INTEGER IS
   BEGIN
      g_rows_inserted := NVL (g_rows_inserted, 0) + 1;
      RETURN 0;
   END; 

   PROCEDURE merge_data (p_comment_str VARCHAR2)  IS
      l_insert_errors   NUMBER := 0;
      l_update_errors   NUMBER := 0;
      l_rows_merged     NUMBER := 0;
   BEGIN
      g_rows_inserted := 0;
      g_rows_updated := 0;
      g_rows_processed := 0;

      MERGE INTO out_tbl
         USING (SELECT col1, col2
                  FROM inp_tbl) inp_tbl
         ON (out_tbl.col1 = inp_tbl.col1)
         WHEN MATCHED THEN
            UPDATE
               SET col2 = inp_tbl.col2
         WHEN NOT MATCHED THEN
            INSERT (col1, col2)
            VALUES ((CASE increment_merge_insert ()
                        WHEN 0
                           THEN inp_tbl.col1
                     END
                    ),
                    inp_tbl.col2)
      LOG ERRORS
       INTO err_log_out_tbl(p_comment_str)
       REJECT LIMIT UNLIMITED;

      l_rows_merged := NVL (l_rows_merged, 0) + SQL%ROWCOUNT; 

      SELECT SUM (CASE
                     WHEN ora_err_rowid$ IS NOT NULL
                        THEN 1
                     ELSE 0
                  END),
             SUM (CASE
                     WHEN ora_err_rowid$ IS NULL
                        THEN 1
                     ELSE 0
                  END)
        INTO l_update_errors,
             l_insert_errors
        FROM err_log_out_tbl
       WHERE ora_err_tag$ = p_comment_str;
      g_rows_processed :=
                     NVL (l_rows_merged, 0) + l_insert_errors
                     + l_update_errors;

      DBMS_OUTPUT.put_line ('Total Rows Processed : ' || g_rows_processed);
      DBMS_OUTPUT.put_line ('Total Merge Count    : ' || l_rows_merged);
      DBMS_OUTPUT.put_line (   'Merge Insert Count   : '
                            || (g_rows_inserted - l_insert_errors)
                           );
      DBMS_OUTPUT.put_line ('Insert Errors        : ' || l_insert_errors);
      DBMS_OUTPUT.put_line ('Update Errors        : ' || l_update_errors);
      DBMS_OUTPUT.put_line ('Final Insert Count   : '
                            || (g_rows_inserted - (2 * l_insert_errors))
                           );
      DBMS_OUTPUT.put_line ('Final Update Count   : '
                            || (  l_rows_merged
                                - (g_rows_inserted - (2 * l_insert_errors))
                               )
                           );
      DBMS_OUTPUT.put_line (   'Final Error Count    : '
                            || (l_insert_errors + l_update_errors)
                           );
   END;
END;
/
SHOW ERRORS

--Call the merge package

SET serveroutput on
BEGIN
   pkg_merge.merge_data ('Test Run');
END; 

-- Check output.
SELECT *
  FROM out_tbl;
SELECT *
  FROM err_log_out_tbl;

-- Cleanup tables
DROP TABLE inp_tbl;
DROP TABLE out_tbl;
DROP TABLE err_log_out_tbl;

Sending SOAP Request through HTTP in PLSQL.

I was getting few queries about calling a webservice in PLSQL using HTTP protocol. We can use UTL_HTTP package to do it. Below is the example that calls SOAP service from PLSQL.

<code>

SET serveroutput on
DECLARE
   -- SOAP REQUESTS/RESPONSE
   soap_req_msg    VARCHAR2 (2000);
   soap_resp_msg   VARCHAR2 (2000);

   -- HTTP REQUEST/RESPONSE
   http_req        UTL_HTTP.req;
   http_resp       UTL_HTTP.resp;

BEGIN
   --
   -- Create SOAP request via HTTP
   --
   soap_req_msg :=
      '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:myschema="http://HelloEjb"> <soapenv:Header/>
  <soapenv:Body>
  <myschema:in0><myschema:message>Test Message</myschema:message></myschema:in0>
  </soapenv:Body></soapenv:Envelope>';

   http_req :=
      UTL_HTTP.begin_request
                         ('http://localhost:8080/HelloBeanService/HelloBean',
                          'POST',
                          'HTTP/1.1'
                         );
   UTL_HTTP.set_header (http_req, 'Content-Type', 'text/xml');
   UTL_HTTP.set_header (http_req, 'Content-Length', LENGTH (soap_req_msg));
   UTL_HTTP.set_header (http_req, 'SOAPAction', '');
   UTL_HTTP.write_text (http_req, soap_req_msg);

  --
   -- Invoke Request and get Response.
   --
   http_resp := UTL_HTTP.get_response (http_req);
   UTL_HTTP.read_text (http_resp, soap_resp_msg);
   UTL_HTTP.end_response (http_resp);
   DBMS_OUTPUT.put_line ('Output: ' || soap_resp_msg);
END;
/

</code>

Manage Database Builds

Database Build Structure

In Database programming, you will be dealing with lot of database objects and it is important to maintain the proper build structure.

  • It keeps code organized.
  • Group related code together
  • Makes DBA life easier in applying the build in production database especially in isolated environments.

In the ideal build scenario, the following directory structure has to be followed.

Database Build Directory Structure

users

All the users & roles related statements (create, update, delete) should be in this folder.

tables

All the table related statements should be in this folder. It should also contain statements that provide comments to table and columns. Triggers should go on this. For each table, separate sql script should be provided and a master script for creating all tables should be provided.

views

All the views related statements should be in this folder. For each view, separate SQL script should be provided and a master script should be provided for creating all the views.

sequences

All the sequence related statements should be in this folder. For each sequence, separate SQL script should be provided and a master script should be provided for creating all the sequences.

synonyms

All the synonyms related statements should be in this folder. More than one synonym can be placed in a single script.

types

All the persistent Object types and Table types related statements should be in this folder. For each type, separate SQL script should be provided. Object Type and a related table type can be combined into a same sql script.

grants

All the grants for various objects to various users/roles should be in this folder. For each schema, separate SQL script should be provided.

data_seed

All the initial seed operations (ONLY DML) should be in this folder. For each table seeding, separate sql should be provided.

plsql

All the plsql packages should be in this folder. For each package, there should be two files, one for specification and one for body. All the anonymous function/procedures should be in separate sql files (Idealy there should not be any anonymous functions)

The sample database build is here.

Load XML File into table using DBMS_LOB package

This example shows how to load xml data from external files to XMLTYPE column using DBMS_LOB & BFILE.

CREATE OR REPLACE DIRECTORY te_xml_dir AS 'c:\test_xml\';
CREATE OR REPLACE PROCEDURE load_xml (p_dir       IN  VARCHAR2,
                                      p_filename  IN  VARCHAR2,
				      p_desc      IN  VARCHAR2) AS
  l_bfile  BFILE := BFILENAME(p_dir, p_filename);
  l_clob   CLOB;
BEGIN
  DBMS_LOB.createtemporary (l_clob, TRUE);

  DBMS_LOB.fileopen(l_bfile, DBMS_LOB.file_readonly);
  DBMS_LOB.loadfromfile(l_clob, l_bfile, DBMS_LOB.getlength(l_bfile));
  DBMS_LOB.fileclose(l_bfile);

  INSERT INTO finl_stmt_test (
    id1,
	DESCRIPTION,
    xml
  )
  VALUES (
    test_seq.nextval,
	P_DESC,
    XMLTYPE.createXML(l_clob)
  );
  COMMIT;

  DBMS_LOB.freetemporary (l_clob);
END;
/
SHOW ERRORS;

exec load_xml('TE_XML_DIR','stmt1.xml');
  • Join 10 other subscribers
  • Tweets