Skip to main content

Accentuate the power of JAX-RPC type mapping with Eclipse Modeling Framework

Jeffrey Liu (jeffliu@ca.ibm.com), Software Developer, IBM, Software Group
Jeffrey Liu is a software developer on the Rational Studio Web Services Tools Team at the IBM Toronto Lab. You can reach Jeffrey at: jeffliu@ca.ibm.com.

Summary:  This article demonstrates how to use the Eclipse Modeling Framework (EMF) to enhance the JAX-RPC type mapping model. It also provides code samples to guide you through the creation of a Web service from a Web Services Description Language (WSDL) document that uses JAX-RPC unsupported XML data types.

Date:  16 Jul 2004
Level:  Intermediate
Activity:  2330 views

Introduction

JAX-RPC, also known as JSR-101, is an important step forward in achieving a standard programming model that facilitates the building of interoperable Web services on the Java™ platform. A key aspect of JAX-RPC is its XML to Java type mapping model, which serves as an implementation standard for Web services product providers. Without such a model, Web services product providers might fall into the trap of defining proprietary type mappings, which can be a serious source of Java interoperability problems.

Although JAX-RPC devotes a considerable amount of effort in supporting XML data types, room for improvement still exists. Moreover, JAX-RPC requires the mapping of any unsupported XML data types to the javax.xml.soap.SOAPElement interface. This interface does not provide a strongly typed Java model for users to work with, meaning they might have to write custom code to parse through a SOAPElement instance. This might not be intuitive for novice users, especially when dealing with large XML fragments. This article demonstrates how to use EMF to support XML data types that do not have standard JAX-RPC type mappings. Generating a Web service that has substantial usage of JAX-RPC unsupported XML data types is not easy, but this article provides you with an effective solution by combining the use of Web services tools and EMF tools in IBM® WebSphere® Studio Application and Site Developer V5.1.2 (Application and Site Developer).


Create the supply-chain Web service

To follow this article, you must install WebSphere Application and Site Developer V5.1.2. If necessary, you can download a 60-day trial version.

  1. Create a Web project. Click on menu File > New > Project... > Web > Dynamic Web Project > Next to open the New Dynamic Web Project wizard.
  2. Enter SupplyChainWeb as the Web project name, select the Configure advance options checkbox and click Next.
  3. Enter SupplyChainEAR as the EAR project name and click Finish.
  4. Click on the Code icon at the top of this article and download SupplyChainService.wsdl and SupplyChainSchema.xsd to your file system.
  5. Import or copy SupplyChainService.wsdl and SupplyChainSchema.xsd into the root of the SupplyChainWeb project.
  6. In the navigator view, right click on SupplyChainService.wsdl > Web Services > Generate Java bean skeleton to open the WSDL to Java Bean Skeleton wizard Figure 1 shows. This wizard generates a Java skeleton code implementation based on the information defined in the WSDL document. Accept the default settings and click Finish.
    Figure 1. WSDL to Java Bean Skeleton wizard
    WSDL to Java Bean Skeleton wizard
  1. After the wizard completes, you see a few WSDL validation errors in the tasks view because the XML schema file, SupplyChainSchema.xsd, was not copied to the proper places. To fix these errors, copy SupplyChainSchema.xsd from the root of the SupplyChainWeb project to the /SupplyChainWeb/WebContent/WEB-INF/wsdl/ directory and the /SupplyChainWeb/WebContent/wsdl/com/example/supplychain/www/ directory. Rerun validation by right clicking on SupplyChainService.wsdl > Run validation.

Create the supply-chain EMF model

The WSDL to Java Bean Skeleton wizard generated JavaBeans with one or more properties mapped to SOAPElement (specifically, PurchaseOrderType.java, PurchaseReferenceType.java, and ShippingNoticeType.java). In this section, you generate an EMF model for the supply-chain Web service to support the XML data types mapped to SOAPElement.

  1. Create an EMF project. Click on menu File > New > Project... > Eclipse Modeling Framework > EMF Project > Next to open the New EMF Project wizard.
  2. Enter SupplyChainEMF as the project name and click Next.
  3. Select Load from an XML schema and click Next.
  4. Click Browse Workspace... to open the file selection dialog. Find and select SupplyChainSchema.xsd and click OK. Click Next.
  5. Select the supplychain package and click Finish. Refer to Figure 2.
    Figure 2. New EMF Project wizard
    New EMF Project wizard
  6. After the New EMF Project wizard completes, the EMF Generator Editor opens. In this editor, right click on the SupplyChainSchema node > Generate Model Code. You've successfully generated the supply-chain EMF model. In the next section, you learn how to integrate the EMF code into the supply-chain Web service.

Integrate the supply-chain Web service and EMF model

  1. Set up all the dependencies for the SupplyChainWeb project. Add the SupplyChainEMF project to the SupplyChainEAR as a utility JAR file and specify a JAR file dependency from the SupplyChainWeb project to this utility JAR file.
  2. Open /SupplyChainEAR/META-INF/application.xml in the Application Deployment Descriptor Editor. Click on the Module tab.
  3. In the Project Utility JARs section, click Add..., select SupplyChainEMF and click Finish. Save and close the Application Deployment Descriptor Editor.
  4. Open /SupplyChainWeb/WebContent/META-INF/MANIFEST.MF in the JAR Dependency Editor. In the Dependencies section, select SupplyChainEMF.jar. Save and close the JAR Dependency Editor.
  5. Add the EMF libraries to the Java build path of the SupplyChainWeb project. Right click on the SupplyChainWeb project > Properties > Java Build Path. Click on the Libraries tab > Add Variable....
  6. Select EMF_COMMON, EMF_ECORE and EMF_ECORE_XMI. Click OK > OK.
  7. Listing 1 shows all the import statements you use. Open /SupplyChainWeb/JavaSource/com/example/supplychain/www/SupplyChainBindingImpl.java in the Java Editor and add these import statements.


    Listing 1. Import statements
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.List;
    import java.util.Random;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.soap.SOAPElement;
    import javax.xml.soap.SOAPException;
    import javax.xml.soap.SOAPFactory;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerConfigurationException;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    
    import org.eclipse.emf.common.util.URI;
    import org.eclipse.emf.ecore.EObject;
    import org.eclipse.emf.ecore.resource.Resource;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.xml.sax.SAXException;
    
    import com.example.supplychain.ItemType;
    import com.example.supplychain.PaymentMethodType;
    import com.example.supplychain.ProcessingType;
    import com.example.supplychain.ShippingItemType;
    import com.example.supplychain.StatusType;
    import com.example.supplychain.SupplychainFactory;
    import com.example.supplychain.SupplychainPackage;
    import com.example.supplychain.impl.SupplychainPackageImpl;
    import com.example.supplychain.util.SupplychainResourceFactoryImpl;
    


  8. You must initialize the generated supply-chain EMF model before you use it. The initialization process builds a mapping between elements declared in the XML schema (SupplyChainSchema.xsd) and Java classes that the EMF code generator created. This mapping serves as the recipe for converting XML fragments to the corresponding EMF-based Java classes and vice versa. To initialize the supply-chain EMF model, add the following static block to SupplyChainBindingImpl.java.


    Listing 2. Initializing the EMF package
    static
    {
      SupplychainPackageImpl.init();
    }
    


  9. Next, you add four methods to SupplyChainBindingImpl.java that convert a SOAPElement to a DOMElement, and then a DOMElement to the corresponding EMF-based Java class and vice versa. Listings 3, 4, 5, and 6 show these methods. The soapElement2DOMElement(SOAPElement soapElement) method and the domElement2SOAPElement(Element e) method, which are responsible for the SOAPElement to DOMElement conversion, utilize a couple of proprietary methods that are specific to WebSphere Application Server V5.x. Unfortunately at this time, there's no public methods for such conversion. To avoid using version specific code, you can manually traverse the SOAPElement and build the DOMElement accordingly.

    In the future, when a SOAP with Attachments API for Java V1.2 (SAAJ)-compatible implementation becomes available, you no longer need to use version specific code to do SOAPElement to DOMElement conversion because SAAJ V1.2 requires SOAPElement to extend DOMElement directly.


    Listing 3. Converting a SOAPElement to a DOMElement
    public Element soapElement2DOMElement(SOAPElement soapElement)
    throws Exception
    {
      return ((com.ibm.ws.webservices.engine.xmlsoap.SOAPElement)soapElement).getAsDOM();
    }
    



    Listing 4. Converting a DOMElement to an EMF object
    public EObject domElement2EObject(Element e)
    throws TransformerConfigurationException, TransformerException, IOException
    {
      DOMSource domSource = new DOMSource(e);
      Transformer serializer = TransformerFactory.newInstance().newTransformer();
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      serializer.transform(domSource, new StreamResult(baos));
      byte[] b = baos.toByteArray();
      System.out.println(new String(b));
      URI uri = URI.createURI(SupplychainPackage.eNS_URI);
      SupplychainResourceFactoryImpl factory = new SupplychainResourceFactoryImpl();
      Resource res = factory.createResource(uri);
      ByteArrayInputStream bais = new ByteArrayInputStream(b);
      res.load(bais, null);
      List contents = res.getContents();
      return (!contents.isEmpty()) ? (EObject)contents.get(0) : null;
    }
    



    Listing 5. Converting an EMF object to a DOMElement
    public Element eObject2DOMElement(EObject eObject)
    throws IOException, ParserConfigurationException, SAXException
    {
      URI uri = URI.createURI(SupplychainPackage.eNS_URI);
      SupplychainResourceFactoryImpl factory = new SupplychainResourceFactoryImpl();
      Resource res = factory.createResource(uri);
      res.getContents().add(eObject);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      res.save(baos, null);
      byte[] b = baos.toByteArray();
      System.out.println(new String(b));
      DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
      DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
      Document doc = docBuilder.parse(new ByteArrayInputStream(b));
      return doc.getDocumentElement();
    }
    



    Listing 6. Converting a DOMElement to a SOAPElement
    public SOAPElement domElement2SOAPElement(Element e)
    throws SOAPException
    {
      SOAPFactory soapFactory = SOAPFactory.newInstance();
      com.ibm.ws.webservices.engine.xmlsoap.SOAPElement soapElement =
        (com.ibm.ws.webservices.engine.xmlsoap.SOAPElement)soapFactory.createElement(
        "temp");
      soapElement.setAlternateContent(e);
      return soapElement;
    }
    


Global vs. local elements

As mentioned earlier, the supply-chain EMF model relies on the element to Java mapping to convert an XML fragment to the corresponding EMF-based Java class. However, by default, the EMF code generator only generates mapping entries for global elements, not for local elements. Global elements are element declarations that appear as children of the schema element in an XML schema document, whereas local elements are not. The default list of mappings excludes local elements, and therefore, the supply-chain EMF model can't convert an XML fragment that represents an instance of a local element. Consider the sample XML schema Listing 7 shows. The corresponding EMF model recognizes the global element instance Listing 8 shows. Conversely, the local element instance Listing 9 shows results in an exception. To support conversion of local elements, you must add custom elements to Java mappings.


Listing 7. Sample XML schema
<schema>
  <element name="GlobalElement">
    <complexType>
      <sequence>
        <element name="LocalElement" type="xsd:string"/>
      </sequence>
    </complexType>
  </element>
</schema>



Listing 8. GlobalElement instance
<GlobalElement>
  <LocalElement>Some String</LocalElement>
</GlobalElement>



Listing 9. LocalElement instance
<LocalElement>Some String</LocalElement>


  1. When you look at the SupplyChainSchema.xsd document and the JavaBeans that the WSDL to Java Bean Skeleton wizard generated, you see three local elements that are mapped to SOAPElement:
    • <paymentMethod> element from the <PurchaseOrderType> complex type
    • <item> element from the <PurchaseOrderType> complex type
    • <item> element from the <ShippingNoticeType> complex type
    To set up a custom mapping between the <paymentMethod> local element and the com.example.supplychain.PaymentMethodType Java class, open /SupplyChainEMF/src/com/example/supplychain/impl/SupplychainPackageImpl.java in the SupplyChainEMF project. Add the code snippet from Listing 10 to the end of the initializePackageContents() method. This method will be called as part of the initialization.


    Listing 10. Adding a local element mapping
    initEClass(paymentMethodTypeEClass, PaymentMethodType.class,
     "paymentMethod", !IS_ABSTRACT, !IS_INTERFACE);
    


  2. Next, you set up custom mappings for the two <item> local elements. Unlike the <paymentMethod> element, you cannot add a static mapping entry in the initializePackageContents() method because the EMF model only allows one mapping for each local element name. To overcome this problem, you dynamically register and remove the necessary mappings as you use them. Listing 11 shows four methods that allow you to register and remove the <item> element mapping from the <PurchaseOrderType> complex type, and register and remove the <item> element mapping from the <ShippingNoticeType> complex type. In the SupplyChainEMF project, open SupplychainPackageImpl.java and add the code snippet Listing 11 shows.


    Listing 11. Adding a local element mapping
    private EClass purchaseItem;
    
    public void initPurchaseItem()
    {
      purchaseItem = initEClass(createEClass(ITEM_TYPE),
       ItemType.class, "item", !IS_ABSTRACT, !IS_INTERFACE);
    }
    
    public void removePurchaseItem()
    {
      if (purchaseItem != null)
        this.eClassifiers.remove(purchaseItem);
    }
    
    private EClass shippingItem;
    
    public void initShippingItem()
    {
      shippingItem = initEClass(createEClass(SHIPPING_ITEM_TYPE),
      
       ShippingItemType.class, "item", !IS_ABSTRACT, !IS_INTERFACE);
    }
    
    public void removeShippingItem()
    {
      if (shippingItem != null)
        this.eClassifiers.remove(shippingItem);
    }
    


  3. Finally, implement the submitPurchaseOrder(com.example.supplychain.www.PurchaseOrderType purchaseOrder) method in SupplyChainBindingImpl.java, as Listing 12 shows. It demonstrates how use the methods you created earlier.


    Listing 12. Sample implementation of the submitPurchaseOrder method
    public com.example.supplychain.www.PurchaseReferenceType
    submitPurchaseOrder(com.example.supplychain.www.PurchaseOrderType purchaseOrder)
    throws java.rmi.RemoteException
    {
      try
      {
        String customerReference = purchaseOrder.getCustomerReference();
    
        /*
         * Converting SOAPElement to PaymentMethodType. The local element
         * mapping for paymentMethod is statically registered in the
         * initializePackageContents() method of SupplychainPackageImpl.java
         */
        PaymentMethodType paymentMethod =
          (PaymentMethodType)domElement2EObject(soapElement2DOMElement((
          SOAPElement)purchaseOrder.getPaymentMethod()));
    
        /*
         * Converting SOAPElement to ItemType. The local element mapping
         * for item is dynamically registered and removed using the
         * initPurchaseItem() and removePurchaseItem() methods.
         */
        ((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).initPurchaseItem();
        ItemType item = (ItemType)domElement2EObject(soapElement2DOMElement((
        SOAPElement)purchaseOrder.getItem()));
        ((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).removePurchaseItem();
    
        ShippingNoticeType shippingNotice = purchaseOrder.getShippingNotice();
        String recipient = shippingNotice.getRecipient();
        String address = shippingNotice.getAddress();
    
        /*
         * Converting SOAPElement to ShippingItemType.
         */
        ((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).initShippingItem();
        ShippingItemType shippingItem =
          (ShippingItemType)domElement2EObject(soapElement2DOMElement((
          SOAPElement)shippingNotice.getItem()));
        ((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).removeShippingItem();
    
        float height = shippingItem.getHeight();
        float length = shippingItem.getLength();
        float width = shippingItem.getWidth();
        float weight = shippingItem.getWeight();
        boolean fragile = shippingItem.isFragile();
    
        float total = 0;
        total += item.getQuantity() * item.getPrice();
        total += weight;
        if (fragile)
          total += 100;
    
        ProcessingType processingType =
        SupplychainFactory.eINSTANCE.createProcessingType();
        StatusType status = SupplychainFactory.eINSTANCE.createStatusType();
        status.setProcessing(processingType);
        PurchaseReferenceType purchaseReference = new PurchaseReferenceType();
        purchaseReference.setReferenceNumber(String.valueOf(Math.abs((
        new Random()).nextInt())));
        /*
         * Converting StatusType to SOAPElement.
         */
        purchaseReference.setStatus(domElement2SOAPElement(eObject2DOMElement(status)));
        purchaseReference.setTotal(total);
        return purchaseReference;
      }
      catch (Throwable t)
      {
        t.printStackTrace();
      }
      return null;
    }
    



Test the supply-chain Web service

You've completed the supply-chain Web service. Now use the Web Services Explorer to test it.

  1. Start the server where you deployed the supply-chain Web service. Open the server view. Click on menu Window > Show View > Other.... Expand the Server folder and click Servers > OK.
  2. In the Servers view, right click on the WebSphere v5.1 Test Environment > Start.
  3. Right click on /SupplyChainWeb/WebContent/wsdl/com/example/supplychain/www/SupplyChainService.wsdl > Web Services > Test with Web Services Explorer to launch the Web Services Explorer.
  4. In the operations table, click on the submitPurchaseOrder link.
  5. Enter the parameter values Table 1 shows.

    Table 1. Parameter values
    ParameterValue
    customerReferenceJohn Doe
    paymentMethodtns:creditCard
    creditCardTypeVISA
    creditCardNumber12345-67890
    expiration2004-06-17
    idPlasma TV
    description42-inch
    quantity1
    price3000
    recipientJohn Doe
    address123 Fake street
    height40
    width25
    length10
    weight60
    fragiletrue

  6. Click Go to invoke the submitPurchaseOrder operation. Figure 3 shows the result of the invocation.
    Figure 3. Result of invoking the submitPurchaseOrder operation
    Result of invoking the submitPurchaseOrder operation

Conclusion

JAX-RPC defines a standard XML to Java type mapping model, however, this model has yet to provide standard mappings for the exhaustive list of XML data types. This article demonstrated how to unite the power of EMF and JAX-RPC to support XML data types that do not have standard mappings. Although EMF provides a solution, this approach requires users to work with two different programming models. In the future, the emerging technology Service Data Objects should provide a more elegant solution to this problem.


Get the products used in this article

If you are a developerWorks subscriber, you have a single user license to use WebSphere Studio Application and Site Developer, and other DB2®, Lotus®, Rational®, Tivoli®, and WebSphere® products -- including the Eclipse-based WebSphere Studio IDE -- to develop, test, evaluate, and demonstrate your applications. If you are not a subscriber, you can subscribe today.



Download

NameSizeDownload method
ws-mapprobcode.zip HTTP

Information about download methods


Resources

About the author

Jeffrey Liu is a software developer on the Rational Studio Web Services Tools Team at the IBM Toronto Lab. You can reach Jeffrey at: jeffliu@ca.ibm.com.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=11943
ArticleTitle=Accentuate the power of JAX-RPC type mapping with Eclipse Modeling Framework
publish-date=07162004
author1-email=jeffliu@ca.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers