Sunday 23 November 2014

Demystifying Oracle Socket Adapter

 

Spent some time today to understand how socket adapter works , how to test composite as it can’t be done from EM for inbound socket adapter. Lets assume the below use case, we have fixed length separated file , say Employee Details coming in source over some TCP port say 12112. SOA composite will bind the incoming file using NXSD and accept the stream data , then it will perform certain operation and return ACK to same socket port with some predefined code. Below are the detailed implementation steps,

1. At first create a new socket adapter outbound connection pool from weblogic console.

image 

image

Give the port no which should be free in your system, to check at your windows PC you can issue netstat -an | find "12112"  from command-prompt, else you can download TCPView from http://technet.microsoft.com/en-in/sysinternals/bb897437.aspx, it has good gui.

image

By default KeepAlive property is set as false, you can change the same to true for better performance.

2. Next create a emp.dat file like below ,

fn111111ln111111232007-01-01100
fn211111ln211111232007-11-01200
fn311111ln311111232007-12-01300

And a fixed length NXSD file to read the same,

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="
http://www.w3.org/2001/XMLSchema"
            xmlns:nxsd="http://xmlns.oracle.com/pcbpel/nxsd"
            xmlns:tns="http://shrikworld.blogspot.in/ReadEmpDetails"
            targetNamespace="http://shrikworld.blogspot.in/ReadEmpDetails"
            elementFormDefault="qualified" attributeFormDefault="unqualified"
            nxsd:version="NXSD" nxsd:stream="chars" nxsd:encoding="US-ASCII">
  <xsd:element name="EmpDetails">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="Emp" minOccurs="1" maxOccurs="unbounded" nxsd:style="array" nxsd:cellSeparatedBy="${eol}">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="FirstName" type="xsd:string" nxsd:style="fixedLength" nxsd:length="8"/>
              <xsd:element name="LastName" type="xsd:string" nxsd:style="fixedLength" nxsd:length="8"/>
              <xsd:element name="Age" type="xsd:int" nxsd:style="fixedLength" nxsd:length="2"/>
              <xsd:element name="DOB" type="xsd:string" nxsd:style="fixedLength" nxsd:length="10"/>
              <xsd:element name="Salary" type="xsd:int" nxsd:style="fixedLength" nxsd:length="3"/>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

Create another XSD file for sync response to socket request,

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://shrikworld.blogspot.in/response"
            targetNamespace="http://shrikworld.blogspot.in/response"
            elementFormDefault="qualified">
  <xsd:element name="Response">
    <xsd:annotation>
      <xsd:documentation>
        A sample element
      </xsd:documentation>
    </xsd:annotation>
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="Code" type="xsd:string"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

3. Now create a empty composite and drag-drop an inbound socket adapter, select Inbound Sync Req/Response from operation ,

image

Select the JNDI you created earlier at step#1.

image

Select request and response XSD that you created step#2,

image

Create request/response XSL for handshake like below and finish.

image

Now create a outbound file adapter to write the input data in the file.Drag and drop a BPEL component defining interface later.

image

Now go to the BPEL process and design like below,

image

It’s just any other BPEL process, screenshot of different activity,

image image

image 

Notice the last assign activity, here I’m setting ‘0x06’ to the response code, you can set any value.

image

4. Next step is important, here we’ll create request.xsl and reply.xsl.

There is a function socketReadWithXlation with that input data will be read from port and will be translated using the input message NXSD, so our request.xsl file look likes,

<xsl:template match="/">
    <xsl:copy-of select="socket:socketReadWithXlation()" />
  </xsl:template>

In sync response.xsl we need the response code that we set from BPEL process on step#3.We are going to use socketWrite function like below in the xslt,

<xsl:template match="//ns0:Response">
  <xsl:variable name="temp">
            <xsl:value-of select="/ns0:Response/ns0:Code"/>
        </xsl:variable>
    <xsl:variable name="var1" select="socket:socketWrite($temp, '','')"/>
    <xsl:variable name="var2" select="socket:socketEndOutput()"/>
  </xsl:template>

5. Now its time to test. First deploy the composite and you’ll notice that it can’t be tested from EM. You need a client program to push the data to the socket.

public class EmpClient {
    public static void main(String[] args) {
        try {
            Socket socket;
            final String HOST = "localhost";
            final int PORT = 12112;
            try {
                socket = new Socket(HOST, PORT);
            } catch (IOException ioe) {
                System.out.println(">>>");
                System.out.println(ioe.getMessage());
                System.out.println(">>>");
                throw ioe;
            }
            System.out.println("sending data: EmpDetails;");
            OutputStream os = socket.getOutputStream();
            byte[] b = "fn111111ln111111232007-01-01100\nfn211111ln211111232007-11-01200\nfn311111ln311111232007-12-01300".getBytes();
            for (int i = 0; i < b.length; i++) {
                os.write(b[i]);
            }
            os.flush();
            socket.shutdownOutput();
            System.out.println("receiving data");
            BufferedReader soc_in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String successCode = soc_in.readLine();
            System.out.println("Success Code: " + successCode);
            socket.close();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

You might noticed I’m sending the same data from Java code with \n separator.When you run this program you should get below output,

image

Now check the flow from EM console,

image

So we are done! You can extend this scenario based on your requirement.