Monday, January 2, 2012

File Read/Write In Batches.

Consider the following composite:



Here, FileRead & FileWrite and 2 file adapters.
File Read is reading file to send messages to mediator, whereas File Write is taking the input and writing the output to another file.
Here is the configuration of FileRead adapter:



The MultiPurchaseOrders.xsd is creating using the Native File Builder wizard, and here is its content:

<?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://TargetNamespace.com/FileRead"
            targetNamespace="http://TargetNamespace.com/FileRead"
            elementFormDefault="qualified"
            attributeFormDefault="unqualified"

            nxsd:version="NXSD"
            nxsd:stream="chars"
            nxsd:encoding="US-ASCII"
>


  <xsd:element name="Root-Element">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="PurchaseOrder" minOccurs="1" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="CustID" type="xsd:int" nxsd:style="terminated" nxsd:terminatedBy="," nxsd:quotedBy="&quot;" />
              <xsd:element name="ID" type="xsd:int" nxsd:style="terminated" nxsd:terminatedBy="," nxsd:quotedBy="&quot;" />
              <xsd:element name="productName" type="xsd:string" nxsd:style="terminated" nxsd:terminatedBy="," nxsd:quotedBy="&quot;" />
              <xsd:element name="itemType" type="xsd:string" nxsd:style="terminated" nxsd:terminatedBy="," nxsd:quotedBy="&quot;" />
              <xsd:element name="price" type="xsd:decimal" nxsd:style="terminated" nxsd:terminatedBy="," nxsd:quotedBy="&quot;" />
              <xsd:element name="quantity" type="xsd:int" nxsd:style="terminated" nxsd:terminatedBy="," nxsd:quotedBy="&quot;" />
              <xsd:element name="status" type="xsd:string" nxsd:style="terminated" nxsd:terminatedBy="," nxsd:quotedBy="&quot;" />
              <xsd:element name="ccType" type="xsd:string" nxsd:style="terminated" nxsd:terminatedBy="," nxsd:quotedBy="&quot;" />
              <xsd:element name="ccNumber" type="xsd:string" nxsd:style="terminated" nxsd:terminatedBy="${eol}" nxsd:quotedBy="&quot;" />
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

</xsd:schema>
<!--NXSDWIZ:C:\FileReadInput\raw_text.txt.txt:-->
<!--USE-HEADER:false:-->

The above schema was creating using the following data:

1111,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765

The FileWrite adapter is also using the same schema, and here is how FileWrite Adapte was created:



So, what I was trying to do is to send 2 records at a time from one file to another. Here is the input to the composite:

1111,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
2222,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
3333,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
4444,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
5555,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
6666,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
7777,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
8888,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
9999,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
1010,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765

And here is how the output looks like:



Since, I tries this multiple times before, so the sequence have reached the count of 18. As you can see, there are 12 records instead of 10 ( with 2 records coming from previous request, with ID 9999 & 1010 ).
The EM shows the correct instance count, ie 5, as shown below:



After deleting old files and instances, I ran the test case again by put the input file to C:\FileRead directory, and here is how the output looks like:



As you can see, 2 records are missing. This is because FileWrite adapter have only received 1 message as of now since 2 records create 1 message that is send from FileRead adapter.
However, FileWrite is configured to accept 2 messages so its waiting for another message.

The point here is that FileWrite adapter waits if the Batch message count is not reached.

Now, test the same for FileRead adapter. Here is the input that I am going to send as input now to check if FileRead adapter also waits for batch count to be reached:

1111,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
2222,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
3333,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
4444,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
5555,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
6666,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
7777,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
8888,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
9999,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
0000,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765
1000,2121,Bluetooth Headset,Electronics,49.99,1,Initial,Mastercard,8765-8765-8765-8765

After deleting all the instances and earlier input files, I ran the test case again and here is the ouptut:



As you can see, all the records are written. Here is how the instance count looks like in EM console:



There are 6 instances, so each composite contains 2 records, and sending it as a single message except one. And here is that instance which contains only 1 record:



The question is if FileRead adapter is configured to read 2 records in a batch, then why even a single message is picked up and send?
FileWrite adapter was waiting for another request to complete the batch, whereas FileRead adapter did't. Any specific reason of why its like that?

Saturday, December 31, 2011

Configuring FTP Adapter.

To use FTP Adapter, we need to configure the FTP adapter in the Weblogic Admin Console. The steps are as follows:

  1. Open WLS Admin Console.
  2. Click Deployments.
  3. Click FTP Adapter link.
  4. Click Configuration Tab link.
  5. Go to Outbound Connection Pools Tab.
  6. Click New.
  7. Check javax.resource.cci.ConnectionFactory.
  8. Enter the JNDI Name (This JNDI name will be used in the FTP adapter in JDev).
  9. Finish.

The JNDI that the FTP Adapter will use is defined. However, we need to set some properties on it. To set those properties:
  1. In the Outbound Connection Pools Tab, expand javax.resource.cci.ConnectionFactor.
  2. Click on the new JNDI that you created.
  3. Provide the following properties.
    1. Host
    2. Port (I used 21 and it worked)
    3.  Username
    4. Password
  4. Leave the other values with default values. No need to change any other values.
Now, we need to update the FTP Adapter to pick up these latest changes. To do that:
  1. Go to Deployments 
  2. Check FTP Adapter check box  Select table level Update button.
  3. Click Next or Finish to update.

That's all. Now, our FTP Adapter can use the JNDI to connect to the FTP server to read or write files.
Also, in the FTP Adapter, the Directory for outgoing files should point to the directory where we need to place the file on the FTP server.

Note on File Adapter's 'Trigger File' Option.

The Trigger File option of the File Adapter enabled us to tell the adapter when the file is ready to be picked up. For example, assume that you are writing a big file that will be picked up by the file adapter, then there might me a case that file adapter might pick up an incomplete file. To avoid this, there is an option to specify that as soon as the trigger file appears in the specified folder, parse the input file.

There is a catch here. By default, it works only once. By this I mean that if there is a file available to be picked up by the file adapter and its waiting for the trigger file, then as soon as trigger file comes up, the input file is picked up. However, now if you delete the trigger file, and place a new input data file, that file will be picked up again without waiting for the trigger file. This is the default option. To override this option, we need to add the following property in the file adapter's jca file:

<property name="TriggerFileStrategy" value="EveryTime"/>

There are 3 options for TriggerFileStrategy property:EndpointActivation, OnceOnly, EveryTime.

The details are available at:
http://technology.amis.nl/blog/9461/the-inbound-file-adapter-%E2%80%93-use-trigger-file

Note however that the trigger file is not deleted even if the file adapter is configured to delete the input file. The trigger file stays there. So, you need to take care of its deletion by yourself.


Thursday, December 29, 2011

File Adapter Bug.

On JDEV 11.1.1.5, I was trying to use and explore File Adapter features. I was just going through the wizard, until on Step 5 I got the following:


The 'Process Files Recursively' checkbox is checked, and I have specified different directories for Incoming and Archived files. However, I am getting the 'File Directory Error' dialog. If I un-check the 'Process File Recursively' checkbox, it works fine and wizard goes to the next step. However, instead of unchecking the 'Process File Recursively' checkbox, if I select a different directory, say C:\ArchiveFileRead, it works fine.
In other words, if both incoming and archive folders have same prefix as 'FileRead', its throwing this error dialog.

A P3 bug.
Confirmed on the post: https://forums.oracle.com/forums/thread.jspa?threadID=2327087

Monday, December 5, 2011

SOA Infra Internally Uses EJB.

Hi,

I always used to think that J2EE uses features of J2SE, then what features of J2EE does Oracle SOA Infrastructure uses. I read somewhere that OSB does not use EJB but I always used to think that internally SOA infra is using EJB, and here is the proof:


Thanks to Ravi Jegga who replied to my forum post to figure this out:

https://forums.oracle.com/forums/thread.jspa?messageID=10016607#10016607


Friday, October 7, 2011

Infinite Loop Using A Mediator

JDev 11.1.1.4

Using a mediator, if you subscribe to an event, and publish the same event, then it creates an infite loop.
For example, consider the following composite:



As you can see, the mediator is both receiving and publishing the event. Here is how mediator looks like:


The event definition is created using the Event Defination creation icon as shown below:


Here is the event definition (.edl file content):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://schemas.oracle.com/events/edl" targetNamespace="http://schemas.oracle.com/events/edl/EmpEvent">
    <schema-import namespace="http://model/events/schema/EmpEO" location="xsd/EmpEO.xsd"/>
    <event-definition name="Emp">
        <content xmlns:ns0="http://model/events/schema/EmpEO" element="ns0:EmpCreateInfo"/>
    </event-definition>
</definitions>

And here is the EmpEO schmea:

<?xml version= '1.0' encoding= 'UTF-8' ?>
<xs:schema targetNamespace="http://model/events/schema/EmpEO" xmlns="http://model/events/schema/EmpEO"
     elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="EmpCreateInfo">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Empno" type="IntValuePair" minOccurs="1"/>
                <xs:element name="Ename" type="StringValuePair" minOccurs="1"/>
                <xs:element name="Comm" type="DecimalValuePair" minOccurs="0"/>
                <xs:element name="Deptno" type="IntValuePair" minOccurs="0"/>
                <xs:element name="Hiredate" type="DateTimeValuePair" minOccurs="0"/>
                <xs:element name="Job" type="StringValuePair" minOccurs="0"/>
                <xs:element name="Mgr" type="IntValuePair" minOccurs="0"/>
                <xs:element name="Sal" type="DecimalValuePair" minOccurs="0"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="ValuePair" abstract="true"/>
    <xs:complexType name="StringValuePair">
        <xs:complexContent>
            <xs:extension base="ValuePair">
                <xs:sequence>
                    <xs:element name="newValue" minOccurs="0">
                        <xs:complexType>
                            <xs:complexContent>
                                <xs:extension base="xs:anyType">
                                    <xs:attribute name="value" type="xs:string"/>
                                </xs:extension>
                            </xs:complexContent>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="oldValue" minOccurs="0">
                        <xs:complexType>
                            <xs:complexContent>
                                <xs:extension base="xs:anyType">
                                    <xs:attribute name="value" type="xs:string"/>
                                </xs:extension>
                            </xs:complexContent>
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="IntValuePair">
        <xs:complexContent>
            <xs:extension base="ValuePair">
                <xs:sequence>
                    <xs:element name="newValue" minOccurs="0">
                        <xs:complexType>
                            <xs:complexContent>
                                <xs:extension base="xs:anyType">
                                    <xs:attribute name="value" type="xs:int"/>
                                </xs:extension>
                            </xs:complexContent>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="oldValue" minOccurs="0">
                        <xs:complexType>
                            <xs:complexContent>
                                <xs:extension base="xs:anyType">
                                    <xs:attribute name="value" type="xs:int"/>
                                </xs:extension>
                            </xs:complexContent>
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="DateTimeValuePair">
        <xs:complexContent>
            <xs:extension base="ValuePair">
                <xs:sequence>
                    <xs:element name="newValue" minOccurs="0">
                        <xs:complexType>
                            <xs:complexContent>
                                <xs:extension base="xs:anyType">
                                    <xs:attribute name="value" type="xs:dateTime"/>
                                </xs:extension>
                            </xs:complexContent>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="oldValue" minOccurs="0">
                        <xs:complexType>
                            <xs:complexContent>
                                <xs:extension base="xs:anyType">
                                    <xs:attribute name="value" type="xs:dateTime"/>
                                </xs:extension>
                            </xs:complexContent>
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="DecimalValuePair">
        <xs:complexContent>
            <xs:extension base="ValuePair">
                <xs:sequence>
                    <xs:element name="newValue" minOccurs="0">
                        <xs:complexType>
                            <xs:complexContent>
                                <xs:extension base="xs:anyType">
                                    <xs:attribute name="value" type="xs:decimal"/>
                                </xs:extension>
                            </xs:complexContent>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="oldValue" minOccurs="0">
                        <xs:complexType>
                            <xs:complexContent>
                                <xs:extension base="xs:anyType">
                                    <xs:attribute name="value" type="xs:decimal"/>
                                </xs:extension>
                            </xs:complexContent>
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
</xs:schema>

After deploying the project on SOA Server, we can see the no record exists as of now for this composite, as shown below:


Now, I am publishing the event as shown below:



The event is published successfully, as shown below:



Now, we need to see how this composite is behaving. As you can see in the figure below, the instance count moves to 1528 in no time:




After refreshing the page, I see that instance count has increased :




When I tried to see the payload received by the mediator, I see that entered values are not received as well:




However, if we remove the publishing of event from the mediator and just subscribe the event:



And deploy the composite, then mediator component works fine, as shown below:



And payload values are visible as well:



So, never subscribe and publish same event from a mediator.