Index Changes

Use Encoders in POJO SE



Table of Content

Why Invoke Encoders in POJO SE?


Currently the encoder runtime support is packaged as part of the OpenESB v2.0 runtime environment and is installed as a JBI shared library. Only File BC, JMS BC and FTP BC support encoders in a protocol-specific manner. The coupling between these BC’s and encoders means that the exceptions thrown in encoders from parsing data or serializing output are handled by BC’s, but the way that a BC handles the exception is specific to the BC, for example, the File BC may put the bad input data causing the encoder to fail parsing into an error folder based on the configurations on the error channel. However, the custom user’s actions in response to bad input data may not be able to achieve in the File BC. One typical problem has been reported in issue 820.

This exercise is to explore the easy, simple, flexible and powerful programming model for integration applications in POJO Service Engineand to invoke message decoding/encoding of encoders (more specifically, the custom encoder in a POJO java class and to handle decoding/encoding exceptions in custom logics written in Java, BPEL for example. The following represents step-by-step instructions on our initial research to get the custom encoder work in POJO SE, and to trigger Java and BPEL actions when the decoding fails.
Back to Top

Prerequisites

  1. Install a latest Glassfish ESB build or open-esb build which can be downloaded from here.
  2. Install POJO SE runtime and netbeans design-time support as indicated in the “download” section of POJO Service Engine

Back to Top

Create a Java Project


Using NetBeans, create a “Java Application” project which will later contain a POJO endpoint (see later).
In this example, we use Project Name: UseEncoderInPojose

Back to Top

Create a Custom Defined Structure


To test the invocation of the custom encoder in POJO SE, we need to have a XSD metadata with custom encoding information and input data in native format. Please refer to Create a Custom Structure and Test it for creating the sample custom defined structure and test it using Encoder Tester.
Back to Top

Invoke Custom Encoder in POJO SE


Now we will create a POJO class which will invoke the custom encoder and will invoke encoder error handling BP in the case that the custom encoder fails to decode an input data.

Create a POJO Class

Create a POJO class by right clicking on the Java SE project and selecting "New -> POJO...".
Alternatively, this can be achieved from selecting "New File" from the "File" menu.
In our sample, we specify the following:
  • Class Name: CustomEncoderPOJO
  • Package: com.sun.customencoder.pojose
  • Method name: parse
  • Input: String (text delimited message)
  • Return type: String (decoded XML, or Decoding Exception Details)
After click on "Finish", the POJO class skeleton code is generated.

Include Jar Files for Custom Encoder


Please refer to Include Jar Files for Custom Encoder for details on how to include the set of jars for the custom encoder into the POJO java project.

Invoke Decoding in POJO

Now modify the method “parse” in the POJO to invoke the custom encoder.

    public String parse(String input) {
        String output = "";
        try {
            // Save input data as POJO class member variable to access later
            this.input = input;
 
            if (logger.isLoggable(Level.INFO)) {
                logger.info("Starting invoke parse on input [" + input + "]");
            }
 
            // Get the encoder factory instance
            EncoderFactory factory = EncoderFactory.newInstance();
 
            // Get the encoder type instance using an encoding style. In our case, custom encoding style.
            EncoderType type = factory.makeType("customencoder-1.0");
 
            // Specify a top element
            String namespaceURI = "http://xml.netbeans.org/schema/customDefined1";
            String rootElementName = "root";
            QName topElem = new QName(namespaceURI, rootElementName);
 
            // Locate xsd metadata
            String xsdMetaFile = "customDefined1.xsd";
            URL url = this.getClass().getClassLoader().getResource(xsdMetaFile);
 
            // Construct the metadata instance
            MetaRef meta = factory.makeMeta(url, topElem);
 
            // Create the encoder instance. In our case, a custom encoder instance
            Encoder coder = factory.newEncoder(type, meta);
 
            // Decode the data
            Source decodedXML = coder.decodeFromString(input);
 
            if (decodedXML == null) {
                return "";
            }
 
            // Create a writer for decoded XML string
            StringWriter writer = new StringWriter();
 
            // Create the StreamResult object
            StreamResult sResult = new StreamResult(writer);
 
            // Get the TransformerFactory instance
            TransformerFactory tf = TransformerFactory.newInstance();
 
            // Invoke transform from decoded source to StreamResult
            tf.newTransformer().transform(decodedXML, sResult);
 
            output = writer.toString();
            if (logger.isLoggable(Level.INFO)) {
                logger.info("Finished parse, get output=[" + output + "]");
            }
        } catch (Exception e) {
             // leave Exception unhandled for now.
        }
 
        return output;
    }


Back to Top

Create Encoder Exception Handling BP


The main purpose in this exercise to invoke encoder functionality from the POJO SE instead of the BC's that support encoders is to allow custom actions to take following decoding/encoding errors from the encoders. We'll create Encoder Exception Handler BPEL as a custom action which is invoked from POJO SE when the custom encoder fails parsing on an input data.
  • Create a new BPEL project.

Let’s use “BPEncoder” as Project Name.

  • Create a simple WSDL to be implemented by BPEL process.

Use "procEncoderErrorWSDL" as "File Name" for the WSDL.

The Abstract Configurations are as follows:

Click on "Finish" once done.

  • Create a BPEL process that implements above WSDL.

Let’s use “procEncoderErrorBP” as "File Name".

Click on "Finish" once done.

Drag the wsdl into BPEL canvas.

  • Create mapping of input message to output. This simulates the encoder exception handling logics.


Back to Top

Invoke Error Handling BP from POJO


We'll need to modify the POJO class to invoke the Encoder Handling BP under the condition that the custom encoder fails to parse an input bad data.

  • To consume a JBI endpoint, drag and drop "POJO Consumer" palette icon into the method.
  • Configure POJO consumer in the palette action dialog by selecting WSDL from file system or URL. Choose "Select From File" in our case.
  • Browse to and select the "procEncoderErrorWSDL.wsdl" file. Dialog will read the WSDL
and populate all the values needed for you.
  • Click on "Finish", and the stub code is generated inside the method “handleException”:
  • Modify the “handleException” method to have your own custom logics. In our example, we have 3 actions in the case that the custom encoder throws Exception during decoding on an input data:
  1. Log the exception at the level of “SEVERE”
  2. Invoke Encoder Error Handler BP from POJO
  3. Write out to a file
    String handleException(Exception exp) {
        // (1) Log the exception
        if (logger.isLoggable(Level.SEVERE)) {
            logger.severe(exp.toString());
        }
        // (2) Invoke Encoder Error Handler BP from POJO
        String outputMsg = null;
        {
            String inputMessage = exp.toString();
           
            // replace angle brackets with square brackets since not supported
            inputMessage = inputMessage.replace('<', '[').replace('>', ']');
 
            try {
                outputMsg = (String) ctx.sendSynchInOut(mServiceEndpoint12261, inputMessage, org.glassfish.openesb.pojose.api.res.POJOContext.MessageObjectType.String);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        // (3) Write out to a file
        writeToFile(outputMsg);
 
        // return outputMsg
        return outputMsg;
    }
 
    void writeToFile(String outputMsg) {
        FileWriter writer = null;
        try {
            String filename = "./encoder_error_details.txt";
            writer = new FileWriter(filename);
            String content = "\nInput text data is:\n" + inData
                    + "\n\nError Detail is:\n" + outputMsg;
            writer.write(content);
            writer.flush();
            writer.close();
        } catch (IOException e) {
            // log the IOException
            logger.severe(e.toString());
            if (writer != null) {
                try {
                    writer.flush();
                    writer.close();
                } catch (IOException e2) {
                    // log the IOException
                    logger.severe(e2.toString());
                }
            }
        }
    }
  • Modify the “parse” method to include the "handleException" method invocation as follows:
    public String parse(String input) {
        String output = "";
        try {
            ……
        } catch (Exception e) {
            output = handleException(e);
        }
        ……
    }

Back to Top

Create Composite Application Project

  • Create a new Project of "Composite Application".

In our example, specify the Project Name: UseEncoderInPojoseCA

Drag and drop both Encoder Exception Handling BPEL project and Java SE application project into the CASA editor.

Clean and build the composite application project. Notice the connections. Make sure that POJO Service Engine is installed and running in Glassfish server.

Test with HTTP SOAP BC

  • Create a "soap" port to linked to POJO SE endpoint, so that it will allow to trigger POJO endpoint from HTTP SOAP BC. Make sure composite application project “clean and build” correctly.
  • Create a test in composite application project using Http SOAP BC port/WSDL created in composite application project. Run the test.
    • Positive Testcase:
      • Sample Input SOAP Message:
<soapenv:Envelope xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:use="UseEncoderInPojoseCA">
    <soapenv:Body>
        <use:CustomEncoderPOJOOperation>
            <part1>a,b|0123456789abcde0123456789</part1>
        </use:CustomEncoderPOJOOperation>
    </soapenv:Body>
</soapenv:Envelope>


      • Sample Expected Output SOAP Message, indicating the input data was successfully decoded by the custom encoder.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <m:CustomEncoderPOJOOperationResponse xmlns:m="UseEncoderInPojoseCA">
      <part1 xmlns:jbi="http://java.sun.com/xml/ns/jbi/wsdl-11-wrapper" xmlns:msgns="http://pojose.customencoder.sun.com/CustomEncoderPOJO/" xmlns="">
        <root xmlns="http://xml.netbeans.org/schema/customDefined1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xml.netbeans.org/schema/customDefined1 C:/GlassFishESB/glassfish/domains/domain1/jbi/service-assemblies/UseEncoderInPojoseCA.4/UseEncoderInPojoseCA-UseEncoderInPojose/openesb-pojo-engine/customDefined1.xsd">
          <group1>
            <delimited1>a</delimited1>
            <delimited2>b</delimited2>
          </group1>
          <group2>
            <fixed1>0123456789</fixed1>
            <fixed2>abcde0123456789</fixed2>
          </group2>
        </root>
      </part1>
    </m:CustomEncoderPOJOOperationResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


    • Negative Test Case:

In this negative test case, we remove the required "delimited2" field from the input data, which would cause the decoding to fail.
      • Sample Input SOAP Message:
<soapenv:Envelope xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:use="UseEncoderInPojoseCA">
  <soapenv:Body>
    <use:CustomEncoderPOJOOperation>
      <part1>a|0123456789abcde0123456789</part1>
    </use:CustomEncoderPOJOOperation>
  </soapenv:Body>
</soapenv:Envelope>
      • Sample Expected Output SOAP Message, indicating the failed parse with detailed error message information which was processed by the Encoder Error Handling BP:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <m:CustomEncoderPOJOOperationResponse xmlns:m="UseEncoderInPojoseCA">
      <part1 xmlns:jbi="http://java.sun.com/xml/ns/jbi/wsdl-11-wrapper" xmlns:msgns="http://pojose.customencoder.sun.com/CustomEncoderPOJO/" xmlns="">Processed Error Details=[javax.xml.transform.TransformerException: com.sun.encoder.runtime.UnmarshalException: Parse failed with data=[[SOD]a[POS]|012345678...] for node name='{http://xml.netbeans.org/schema/customDefined1}delimited2' after last matched path=0.0: End of parent.], Current Time=2008-11-10T16:00:06.40-08:00, BP Id=129.153.183.83:-66b7d25:11d87b5c3b8:-7c84</part1>
    </m:CustomEncoderPOJOOperationResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Also notice the error file “encoder_error_details.txt” is created in a subdirectory relative to the glassfish domain directory. The content may read as follows:
Input text data is:
a|0123456789abcde0123456789
 
Error Detail is:
Processed Error Details=[javax.xml.transform.TransformerException: com.sun.encoder.runtime.UnmarshalException: Parse failed with data=[[SOD]a[POS]|012345678...] for node name='{http://xml.netbeans.org/schema/customDefined1}delimited2' after last matched path=0.0: End of parent.], Current Time=2008-11-10T16:00:06.40-08:00, BP Id=129.153.183.83:-66b7d25:11d87b5c3b8:-7c84

Test with File BC


We may also test on input data located inside a file in the filesystem. We’ll need File BC as endpoint to communicate with the filesystem.
  • Create a WSDL document using "FILE" as Binding.
  • Configure Request parameters. In "Payload Processing", select “text” instead of “encoded data” as “Message Type” because we will not decode the input data from the File BC (instead, we invoke decoding of input data from POJO class).
  • Configure Response parameters for outbound decoded XML or Detailed decoding errors.
  • Create a "file" port with WSDL created above to linked to POJO SE endpoint, so that it will allow to trigger POJO endpoint from File BC. Make sure composite application project “clean and build” correctly.
  • Deploy and run the Application with input data file in designated folder and examine the output file.
    • Positive Test:
      • Sample Input file content:
a,b|0123456789abcde12345ABCDE
      • Sample Output file content, indicating the input data was successfully decoded by the custom encoder.
<root xmlns="http://xml.netbeans.org/schema/customDefined1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xml.netbeans.org/schema/customDefined1 C:/GlassFishESB/glassfish/domains/domain1/jbi/service-assemblies/UseEncoderInPojoseCA.7/UseEncoderInPojoseCA-UseEncoderInPojose/openesb-pojo-engine/customDefined1.xsd">
<group1>
<delimited1>a</delimited1>
<delimited2>b</delimited2>
</group1>
<group2>
<fixed1>0123456789</fixed1>
<fixed2>abcde12345ABCDE</fixed2>
</group2>
</root>
    • Negative Test:

In this negative test case, we remove the required "delimited2" field from the input data, which would cause the decoding to fail.
      • Sample Input file content:
a|0123456789abcde12345ABCDE
      • Sample Output file content, indicating the failed parse with detailed error message information which was processed by the Encoder Error Handling BP:
 
Processed Error Details=[javax.xml.transform.TransformerException: com.sun.encoder.runtime.UnmarshalException: Parse failed with data=[[SOD]a[POS]|012345678...] for node name='{http://xml.netbeans.org/schema/customDefined1}delimited2' after last matched path=0.0: End of parent.], Current Time=2008-11-10T17:47:20.04-08:00, BP Id=129.153.183.83:-66b7d25:11d87b5c3b8:-7b28

Also notice the error file “encoder_error_details.txt” is created in a subdirectory relative to the glassfish domain directory. The content may read as follows:

Input text data is:
a|0123456789abcde0123456789
 
Error Detail is:
Processed Error Details=[javax.xml.transform.TransformerException: com.sun.encoder.runtime.UnmarshalException: Parse failed with data=[[SOD]a[POS]|012345678...] for node name='{http://xml.netbeans.org/schema/customDefined1}delimited2' after last matched path=0.0: End of parent.], Current Time=2008-11-10T16:00:06.40-08:00, BP Id=129.153.183.83:-66b7d25:11d87b5c3b8:-7c84

Back to Top

Source Code


The complete NetBean Projects are available to download from here (zip)(info)
  • Any questions/feebacks?

Please email: soabi-encoders@sun.com

JSPWiki v2.4.100
[RSS]
« Home Index Changes Prefs
This page (revision-30) was last changed on 19-Nov-08 17:34 PM, -0800 by LixinTang