Showing posts with label SDO. Show all posts
Showing posts with label SDO. Show all posts

Wednesday, August 3, 2011

How to Simply Convert SDO to DOM Element and Vice-versa

In previous post, I demonstrated how to marshall POJOs to SDO. In this post, I will show how to convert SDOs to DOM Elements without parsing them to or from String.


The key is the following methods from the commonj.sdo.helper.XSDHelper:
  • void save(XMLDocument xmlDocument, javax.xml.transform.Result outputResult, java.lang.Object options); -- wherein, we can instantiate a DOM node and wrap it with a javax.xml.transform.dom.DOMResult;
  • XMLDocument load(javax.xml.transform.Source inputSource, java.lang.String locationURI, java.lang.Object options); -- wherein we can wrap a given DOM element with javax.xml.transform.dom.DOMSource;

Below is a client I add on the sample application from previous post:
package soadev.sdojaxbsample.clients;

import commonj.sdo.DataObject;
import commonj.sdo.Type;
import commonj.sdo.helper.XMLDocument;
import javax.xml.bind.JAXBContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import oracle.bpel.services.common.util.XMLUtil;
import org.eclipse.persistence.sdo.helper.jaxb.JAXBHelperContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import soadev.hrservice.model.Job;

public class SDOToElementClient {
    public static void main(String[] args) {
        SDOToElementClient client = new SDOToElementClient();
        try {
            client.testConvertSdoToDomElementAndViceVersa();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void testConvertSdoToDomElementAndViceVersa()throws Exception{
        System.out.println("----Start testConvertSdoToDomElementAndViceVersa----");
        JAXBContext jaxbContext = JAXBContext.newInstance(Job.class);
        JAXBHelperContext jaxbHelperContext = new JAXBHelperContext(jaxbContext);  
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/JobSDO.xsd"), "soadev/hrservice/model");
        DataObject sdo = createSampleSDO(jaxbHelperContext);
        System.out.println("Created sample SDO: " + sdo);
        XMLDocument xmlDocument =
              jaxbHelperContext.getXMLHelper().createDocument(sdo, sdo.getType().getURI(), "jobSDO");
        DocumentBuilder docBuilder =
            DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document = docBuilder.newDocument();
        jaxbHelperContext.getXMLHelper().save(xmlDocument, new DOMResult(document), null);
        Element element = document.getDocumentElement();
        System.out.println("SDO converted to DOM element: " + element);
        System.out.println(XMLUtil.toString(element));
        System.out.println(">>> Converting element to SDO...");
        XMLDocument xmlDocFromElement = 
              jaxbHelperContext.getXMLHelper().load(new DOMSource(element), null, null);
        DataObject sdoFromElement = xmlDocFromElement.getRootObject();
        System.out.println("DOM element converted to SDO: " + sdoFromElement);
        System.out.println(sdoFromElement.get("jobId"));
        System.out.println(sdoFromElement.get("jobTitle"));
        System.out.println(sdoFromElement.get("maxSalary"));
        System.out.println(sdoFromElement.get("minSalary"));
        System.out.println("----End testConvertSdoToDomElementAndViceVersa----");
    }

    private DataObject createSampleSDO(JAXBHelperContext jaxbHelperContext) {
        Type jobType = jaxbHelperContext.getType(Job.class);
        DataObject jobSDO = jaxbHelperContext.getDataFactory().create(jobType);
        jobSDO.set("jobId", "SOADEV");
        jobSDO.set("jobTitle", "SOA Developer");
        jobSDO.set("maxSalary", 20000L);
        jobSDO.set("minSalary", 18000L);
        return jobSDO;
    }
}

Run Output...
C:\Oracle\11g\jdk160_24\bin\javaw.exe -client -classpath ...
----Start testConvertSdoToDomElementAndViceVersa----
Created sample SDO: soadev.hrservice.model.JobSDOImpl@1372656
SDO converted to DOM element: oracle.xml.parser.v2.XMLElement@1fa6d18
<ns0:jobSDO xmlns:ns0="/soadev.hrservice.model/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <jobId>SOADEV</jobId>
   <jobTitle>SOA Developer</jobTitle>
   <maxSalary>20000</maxSalary>
   <minSalary>18000</minSalary>
</ns0:jobSDO>

>>> Converting element to SDO...
DOM element converted to SDO: soadev.hrservice.model.JobSDOImpl@1ee148b
SOADEV
SOA Developer
20000
18000
----End testConvertSdoToDomElementAndViceVersa----
Process exited with exit code 0.

Wednesday, October 13, 2010

Looking Up SOAServiceInvokerBean from a Different JVM

I am writing this up before I will forget and hit this again...
javax.naming.CommunicationException [Root exception is java.rmi.UnmarshalException: failed to unmarshal class java.lang.Object; nested exception is: 
 java.lang.ClassNotFoundException: oracle.integration.platform.blocks.sdox.ejb.api.SOAServiceInvokerBean]
 at weblogic.jndi.internal.ExceptionTranslator.toNamingException(ExceptionTranslator.java:74)
....
Caused by: java.rmi.UnmarshalException: failed to unmarshal class java.lang.Object; nested exception is: 
 java.lang.ClassNotFoundException: oracle.integration.platform.blocks.sdox.ejb.api.SOAServiceInvokerBean
 at weblogic.rjvm.ResponseImpl.unmarshalReturn(ResponseImpl.java:244)
 at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348)
...
Caused by: java.lang.ClassNotFoundException: oracle.integration.platform.blocks.sdox.ejb.api.SOAServiceInvokerBean
 at weblogic.application.internal.AppClassLoaderManagerImpl.loadApplicationClass(AppClassLoaderManagerImpl.java:135)
 at weblogic.common.internal.ProxyClassResolver.resolveProxyClass(ProxyClassResolver.java:68)

I normally do not encounter this error when I look up the SOAServiceInvokerBean inside a simple java client, but when I tried to look this up inside one of my backing bean then I start hitting it again.

The following is an excerpt from the Developer's Guide for Oracle SOA Suite
36.4 Designing an SDO-Based Enterprise JavaBeans Client to Invoke Oracle SOA Suite To invoke an SDO - Enterprise JavaBeans service from Enterprise JavaBeans, you must use the client library. Follow these guidelines to design an Enterprise JavaBeans client.
  • Look up the SOAServiceInvokerBean from the JNDI tree.
  • Get an instance of SOAServiceFactory and ask the factory to return a proxy for the Enterprise JavaBeans service interface.
  • You can include a client side Enterprise JavaBeans invocation library (fabric-ejbClient.jar or the fabric-runtime.jar file located in the Oracle JDeveloper home directory or Oracle WebLogic Server) in the Enterprise JavaBeans client application. For example, the fabric-runtime.jar file can be located in the JDev_Home\jdeveloper\soa\modules\oracle.soa.fabric_11.1.1 directory.
If the Enterprise JavaBeans application is running in a different JVM than Oracle SOA Suite, the Enterprise JavaBeans application must reference the ejbClient library.

It says that to invoke the SOAServiceInvokerBean from a different JVM then you need to have the "fabric-ejbClient.jar" in your classpath, but "fabric-ejbClient.jar" is nowhere to be found. Searching on the same directory suggested above, we can find a "fabric-client.jar", and yes you are right that it can serve the purpose.

In summary, to look up and invoke the SOAServiceInvokerBean from a different JVM, you must reference the "fabric-client.jar" located in JDev_Home\jdeveloper\soa\modules\oracle.soa.fabric_11.1.1 directory.

Cheers!

Thursday, September 30, 2010

SDO: Implementing a HashMap like Service Data Objects

Introduction

I envisioned to create a Generic ADF Human Task Form to support all of our human task (workflow) activities, and in the solution that I thought of, I need an SDO HashMap.

For those who are not familiar, the ADF Human Task Form are remotely deployed bounded task flows (BTFs) that are being accessed by the Oracle BPM woklist app in showing the details of a listed task. The remotely deployed BTFs can support multiple human task as long as they have have identical payload elements. I will describe some more details in subsequent posts.

Problem Description

I need some sort of HashMap like SDO because I need to pass a parameterMap from a human task payload into the dynamic region inside my envisioned Generic ADF Human Task Form, but there is no such HashMap equivalent in SDO or in XML Schema. This post provides an implemented schema and classes to support a HashMap like SDO in Oracle SOA Suite 11g BPEL processes.

Artifacts

To create the SDO HashMap we need to have the following artifacts:
  1. MyMapSDO.xsd - Contains the definition of "MyMapSDO" and "MyEntrySDO" complex types to hold the list of entries and the key-value pairs respectively.
  2. MyEntrySDO.java - Java representation of the MyEntrySDO complex type.
  3. MyMapSDO.java - Java representation of the MyMapSDO complex type.
  4. MyEntrySDOImpl.java - implementation
  5. MyMapSDOImpl.java
  6. SimpleWrapperUtils.java - this class handles wrapping of simple types like string, integer, long , etc. to dataobjects as described in my previous post.
  • Below is the concrete "MyMapSDO.xsd" schema that contains both complex types:
    <?xml version="1.0" encoding="windows-1252" ?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns="http://soadev.blogspot.com/map"
                targetNamespace="http://soadev.blogspot.com/map"
                xmlns:sdoJava="commonj.sdo/java" sdoJava:package="soadev.sdo.sdohashmap.model">
       <xsd:import namespace="commonj.sdo/java"/>
       <xsd:complexType name="MyMapSDO">
          <xsd:sequence>
             <xsd:element name="entry" type="MyEntrySDO" minOccurs="0"
                          maxOccurs="unbounded"/>
          </xsd:sequence>
       </xsd:complexType>
       <xsd:complexType name="MyEntrySDO">
          <xsd:sequence>
             <xsd:element name="key" type="xsd:string" minOccurs="0"/>
             <xsd:element name="value" type="xsd:anyType" minOccurs="0"/>
          </xsd:sequence>
       </xsd:complexType>
       <xsd:element name="myMapSDO" type="MyMapSDO"/>
    </xsd:schema>
    
  • MyEntrySDO.java
    package soadev.sdo.sdohashmap.model;
    
    public interface MyEntrySDO {
        String getKey();
        void setKey(String key);
        Object getValue();
        void setValue(Object value);
    }
    
    
  • MyMapSDO.java
    
    package soadev.sdo.sdohashmap.model;
    
    import java.util.List;
    
    public interface MyMapSDO {
        List getEntry();
        void setEntry(List value);
    }
    
  • MyEntrySDOImpl.java
    
    package soadev.sdo.sdohashmap.model;
    
    import org.eclipse.persistence.sdo.SDODataObject;
    
    public class MyEntrySDOImpl extends SDODataObject implements MyEntrySDO {
        public String getKey() {
            return getString("key");
        }
    
        public void setKey(String key) {
            set("key", key);
        }
    
        public Object getValue() {
            return get("value");
        }
    
        public void setValue(Object value) {
            set("value", value);
        }
    }
    
  • MyMapSDOImpl.java
    
    package soadev.sdo.sdohashmap.model;
    
    import commonj.sdo.DataObject;
    
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    
    import java.util.Map;
    
    import org.eclipse.persistence.sdo.SDODataObject;
    import static soadev.sdo.utils.SimpleTypeWrapperUtils.unwrap;
    
    public class MyMapSDOImpl extends SDODataObject implements MyMapSDO {
        public List getEntry() {
            return getList("entry");
        }
    
        public void setEntry(List value) {
            set("entry", value);
        }
        //EL reachable
        public Map<String, Object> getMap(){
            Map<String, Object> map = new HashMap<String, Object>();
            for(Object obj: getEntry()){
                MyEntrySDO entry = (MyEntrySDO)obj;
                map.put(entry.getKey(), unwrap((DataObject)entry.getValue()));
            }
            return map;
        }
    }
    

Testing ...

Below is a sample runner class to illustrate the use case:
package soadev.sdo.sdohashmap.main;

import commonj.sdo.helper.DataFactory;

import commonj.sdo.helper.XMLHelper;

import java.math.BigDecimal;

import java.util.HashMap;
import java.util.List;

import java.util.Map;

import oracle.jbo.common.sdo.SDOHelper;

import soadev.sdo.sdohashmap.model.MyEntrySDO;
import soadev.sdo.sdohashmap.model.MyMapSDO;
import soadev.sdo.sdohashmap.model.MyMapSDOImpl;
import soadev.sdo.sdohashmap.sampleentity.JobSDO;
import static soadev.sdo.utils.SimpleTypeWrapperUtils.*;

public class Runner {

    public static void main(String[] args) {
        try {
            SDOHelper.INSTANCE.defineSchema("soadev/sdo/sdohashmap/sampleentity/",
                                            "JobSDO.xsd");
            SDOHelper.INSTANCE.defineSchema("soadev/sdo/sdohashmap/model/",
                                            "MyMapSDO.xsd");
            MyMapSDO myMapSDO =
                (MyMapSDO)DataFactory.INSTANCE.create(MyMapSDO.class);
            MyEntrySDO entry =
                (MyEntrySDO)DataFactory.INSTANCE.create(MyEntrySDO.class);
            entry.setKey("param1");
            entry.setValue(wrap("SampleValue"));
            MyEntrySDO entry2 =
                (MyEntrySDO)DataFactory.INSTANCE.create(MyEntrySDO.class);
            entry2.setKey("param2");
            entry2.setValue(wrap(1));
            MyEntrySDO entry3 =
                (MyEntrySDO)DataFactory.INSTANCE.create(MyEntrySDO.class);
            entry.setKey("param1");
            JobSDO job = (JobSDO)DataFactory.INSTANCE.create(JobSDO.class);
            job.setJobId("SOADev");
            job.setJobTitle("SOA Developer");
            job.setMaxSalary(20000L);
            job.setMinSalary(10000L);
            entry3.setKey("param3-job");
            entry3.setValue(job);
            MyEntrySDO entry4 =
                (MyEntrySDO)DataFactory.INSTANCE.create(MyEntrySDO.class);
            entry4.setKey("param4");
            entry4.setValue(wrap(100L));
            MyEntrySDO entry5 =
                (MyEntrySDO)DataFactory.INSTANCE.create(MyEntrySDO.class);
            entry5.setKey("param5");
            entry5.setValue(wrap(true));
            MyEntrySDO entry6 =
                (MyEntrySDO)DataFactory.INSTANCE.create(MyEntrySDO.class);
            entry6.setKey("param6");
            entry6.setValue(wrap(200.50));
            MyEntrySDO entry7 =
                (MyEntrySDO)DataFactory.INSTANCE.create(MyEntrySDO.class);
            entry7.setKey("param7");
            entry7.setValue(wrap(new BigDecimal("550.90")));
            List entries = myMapSDO.getEntry();
            entries.add(entry);
            entries.add(entry2);
            entries.add(entry3);
            entries.add(entry4);
            entries.add(entry5);
            entries.add(entry6);
            entries.add(entry7);
            
            //print XML representation
            String xmlFragment = XMLHelper.INSTANCE.save((MyMapSDOImpl)myMapSDO, null, "myMapSDO");
            System.out.println(xmlFragment);
            
            //get map Object
            Map<String, Object> parameterMap = ((MyMapSDOImpl)myMapSDO).getMap();
            for(Map.Entry<String, Object> mapEntry: parameterMap.entrySet()){
                System.out.println("key: " + mapEntry.getKey());
                System.out.println("value: " + mapEntry.getValue());
                System.out.println("value class: " + mapEntry.getValue().getClass());
                System.out.println("-----------------------------------------------");
            }

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
Below is the output in the console after running the runner class above:
C:\Oracle\11gR1PS2\jdk160_18\bin\javaw.exe -client -classpath ////--removed very long classpath---////
Djavax.net.ssl.trustStore=C:\Oracle\11gR1PS2\wlserver_10.3\server\lib\DemoTrust.jks soadev.sdo.sdohashmap.main.Runner
[EL Warning]: 2010-09-30 03:22:46.25--SDOUtil: Generated Type [ChangeSummary] conflicts with SDO specification naming rules for [ChangeSummary] and should be renamed.
<?xml version="1.0" encoding="UTF-8"?>
<myMapSDO xsi:type="ns1:MyMapSDO" xmlns:ns1="http://soadev.blogspot.com/map" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <entry>
      <key>param1</key>
      <value xsi:type="ns0:string" xmlns:ns0="http://www.w3.org/2001/XMLSchema">SampleValue</value>
   </entry>
   <entry>
      <key>param2</key>
      <value xsi:type="ns0:int" xmlns:ns0="http://www.w3.org/2001/XMLSchema">1</value>
   </entry>
   <entry>
      <key>param3-job</key>
      <value xsi:type="ns0:JobSDO" xmlns:ns0="http://soadev.blogspot.com/sampleentity">
         <jobId>SOADev</jobId>
         <jobTitle>SOA Developer</jobTitle>
         <maxSalary>20000</maxSalary>
         <minSalary>10000</minSalary>
      </value>
   </entry>
   <entry>
      <key>param4</key>
      <value xsi:type="ns0:long" xmlns:ns0="http://www.w3.org/2001/XMLSchema">100</value>
   </entry>
   <entry>
      <key>param5</key>
      <value xsi:type="ns0:boolean" xmlns:ns0="http://www.w3.org/2001/XMLSchema">true</value>
   </entry>
   <entry>
      <key>param6</key>
      <value xsi:type="ns0:double" xmlns:ns0="http://www.w3.org/2001/XMLSchema">200.5</value>
   </entry>
   <entry>
      <key>param7</key>
      <value xsi:type="ns0:decimal" xmlns:ns0="http://www.w3.org/2001/XMLSchema">550.90</value>
   </entry>
</myMapSDO>

key: param1
value: SampleValue
value class: class java.lang.String
-----------------------------------------------
key: param2
value: 1
value class: class java.lang.Integer
-----------------------------------------------
key: param4
value: 100
value class: class java.lang.Long
-----------------------------------------------
key: param5
value: true
value class: class java.lang.Boolean
-----------------------------------------------
key: param6
value: 200.5
value class: class java.lang.Double
-----------------------------------------------
key: param7
value: 550.90
value class: class java.math.BigDecimal
-----------------------------------------------
key: param3-job
value: soadev.sdo.sdohashmap.sampleentity.JobSDOImpl@1c208b0
value class: class soadev.sdo.sdohashmap.sampleentity.JobSDOImpl
-----------------------------------------------
Process exited with exit code 0.

Prototype

You can download the sample application from here.

What's Next?

In subsequent post, I will show how this SDO HashMap be used through Java Embedding inside a BPEL process. I will also show how to initialize an SDO entity with an XML fragment. And... I will also describe a problem that I later realize in the process of this goal of having a Generic ADF Human Task Form - there is always workaround though :-) .

Monday, September 13, 2010

SDO: Wrapping Simple Types as DataObjects

  <xsd:element name="value" type="xsd:anyType" minOccurs="0"/>
The SDO specs specifies that an XSD element with type "anyType" is map to a DataObject SDO type. This means that you cannot assign simple types like String, Integer, Long, and Boolean among others into this element, because if you do so, you will receive a java.lang.ClassCastException in runtime.

To be able to do that therefore, you need to wrap those simple types into SDO DataObjects. Luckily the current org.eclipse.persistense_1.0.0.0_2-0.jar that ships with JDeveloper already contains simple type wrappers with type "org.eclipse.persistence.sdo.types.SDOWrapperType" as follows:

  • String - org.eclipse.persistence.sdo.StringWrapperImpl
  • Integer - org.eclipse.persistence.sdo.IntObjectWrapperImpl
  • Long - org.eclipse.persistence.sdo.LongObjectWrapperImpl
  • Double - org.eclipse.persistence.sdo.DoubleObjectWrapperImpl
  • BigDecimal - org.eclipse.persistence.sdo.DecimalWrapperImpl
  • Boolean - org.eclipse.persistence.sdo.BooleanObjectWrapperImpl

How do we wrap our simple types into SDO DataObjects?
Below is a utility class that I have devised to handle wrapping and unwrapping of simple types.

package soadev.sdo.utils;

import commonj.sdo.DataObject;
import commonj.sdo.Type;
import commonj.sdo.helper.DataFactory;

import java.math.BigDecimal;

import oracle.jbo.common.sdo.SDOTypeHandler;

import org.eclipse.persistence.sdo.types.SDOWrapperType;


/**@author Rommel Pino http://soadev.blogspot.com
 */
public class SimpleTypeWrapperUtils {

    public static DataObject wrap(String value) {
        return wrap(value, "java.lang.String");
    }

    public static DataObject wrap(Long value) {
        return wrap(value, "java.lang.Long");
    }

    public static DataObject wrap(Integer value) {
        return wrap(value, "java.lang.Integer");
    }

    public static DataObject wrap(BigDecimal value) {
        return wrap(value, "java.math.BigDecimal");
    }

    public static DataObject wrap(Short value) {
        return wrap(value, "java.lang.Short");
    }

    public static DataObject wrap(Boolean value) {
        return wrap(value, "java.lang.Boolean");
    }

    public static DataObject wrap(Byte value) {
        return wrap(value, "java.lang.Byte");
    }
    
    public static DataObject wrap(Double value) {
        return wrap(value, "java.lang.Double");
    }

    public static DataObject wrap(Float value) {
        return wrap(value, "java.lang.Float");
    }


    private static DataObject wrap(Object value,
                                   String fullyQualifiedSimleTypeClassName) {
        Type type =
            SDOTypeHandler.getSDOType(fullyQualifiedSimleTypeClassName);
        DataObject wrapper = DataFactory.INSTANCE.create(type);
        wrapper.set("value", value);
        return wrapper;
    }

    public static Object unwrap(DataObject wrapper) {
        if (wrapper.getType() instanceof SDOWrapperType) {
            return wrapper.get("value");
        }
        //if not wrapper return the same object
        return wrapper;
    }

}

In subsequent post, I will describe how to implement some sort of SDO HashMap.