Search code examples
javaxmlxsdwebspheresdo

SDO API: how to make XSDHelper.INSTANCE to define XSD schemas with <include> correctly?


I'm facing a following problem. We're using Service Data Objects since our target runtime is IBM WebSphere which supposes to be native for this API. The stack that we're using is Java EE, Eclipse Oxygen as the main IDE, SDO reference implementation according to SDO 2.1.0 specification, IBM WebSphere 9 and JRE8.

According to SDO javadoc there are a define(java.io.InputStream xsdInputStream, java.lang.String schemaLocation) method under XSDHelper class which loads a desired XSD schema into the WAS runtime. Once the schema is being loaded its type becomes available for other operations, including DataObject creation.. The way I define schemas looks like the following:

InputStream is = new BOStorage().getInputStreamXSD("/test.xsd"); 
XSDHelper.INSTANCE.define(is, null);

The define() method invokes from the EJB constructor. test.xsd is located under the src folder of my eclipse project.

src
| test.xsd
| test1.xsd
|
|___ejb.package.name

Now a little bit about the test.xsd itself. It references to another XSDs of the same targetNamespace using <include> tag:

test.xsd snippet:

...
<xsd:schema
    targetNamespace="http://ejb/package/name"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:bons0="http://ejb/package/name">
    <xsd:include schemaLocation="test1.xsd"></xsd:include>
    <xsd:include schemaLocation="test2.xsd"></xsd:include>
    <xsd:complexType name="TestSDO">
...
<xsd:element minOccurs="0" name="RefObject"
                type="bons0:RefObject">
            </xsd:element>
...

test1.xsd contains a complexType named RefObject, which is referenced in test.xsd.

test1.xsd snippet:

...
<xsd:complexType name="RefObject">

          <xsd:simpleContent>
            <xsd:extension base="xsd:string">
                <xsd:attribute name="type"/>
            </xsd:extension>
        </xsd:simpleContent>

  </xsd:complexType>
...

As official SDO Java spec for the version 2.1.0 says:

9.7 XSD Mapping Details

...

  1. All <group> references, <attributeGroup> references, <include>s, and <import>s are fully expanded to the equivalent XSD as if these declarations were not present.

...

For my vision that means, that in my case, SDO implementation should:

  1. Load test.xsd;

  2. Figures out, that it references to the test1.xsd in its <include> section;

  3. As the test1.xsd located at the same src folder, as the test.xsd is, my expectations is that it would be implicitly loaded in WebSphere runtime environment.

But I'm experiencing an error while trying to create a DataObject of RefObject type:

CWSDO0001E: Cannot create a data object of the type {http://ejb/package/name}RefObject because the type cannot be found

The conclusions I can make is that SDO API isn't designed to work that way or my XSD's or any aren't suitable or contain some mistakes.

Any help would be highly appreciated.

UPDATE: It works just as expected in case of using the "global" XSD, which includes all references inline. Everything I've mentioned before is running from stateless EJB bean.

A sample code leading to the error:

        @Stateless(mappedName = "TestSDO")
        @Remote(TestSDORemote.class)
        @Local(TestSDOLocal.class)

        public class TestSDO implements TestSDORemote, TestSDOLocal{
            ...


        // default EJB constructor

     public TestSDO() {
           String textInfo = "";

            try {
                defineSDOTypes();
            } catch (Exception e) {
                LOGGER.log(Level.WARNING, "Could not define SDO types");
            }
        }
             ...
      private void defineSDOTypes() {
            HelperContext hc =   
            SDO.getHelperContextFactory().createHelperContext("ScopeManagerTestID", 
            null);
            XSDHelper xsdHelper = hc.getXSDHelper();
            try (InputStream is = new BOStorage().getInputStreamXSD("/test.xsd")) {          
                 xsdHelper.define(is, null);    
            } catch (IOException e) { 
              LOGGER.logp(Level.WARNING, CLASS_NAME, METHOD_NAME, "Unable to load the 
              schema: " + 
              "test.xsd" + ": " + e.getMessage());      
               e.printStackTrace();     
            }
             ...
      // creates the target Data Object (here comes the error)
      private void createBO(){
            DataObject dob = DataFactory.INSTANCE.create("http://ejb/package/name", 
            "RefObject");
        }
             ...

Solution

  • Looking at the Tuscany SDO repo it seems you want to do something like:

        URL url = getClass().getResource("/test.xsd");
        InputStream inputStream = url.openStream();
        xsdHelper.define(inputStream, url.toString());
        inputStream.close();
    

    That is, instead of doing xsdHelper.define(is, null), I think you need to pass in a value for the second parm: schemaLocation as the javadoc suggests:

    schemaLocation - the URI of the location of the schema, used for processing relative imports and includes. May be null if not used.