traversing a BPEL array - soa

I need to traverse an array (input to BPEL) in java embed activity and need to generate a response (output variable) of BPEL process.
I am using Jdeveloper and SOA 11g
following is my xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://xmlns.oracle.com/BPELInpuandOutPutArray_jws/Project1/BPEL_input_output_array" xmlns="http://www.w3.org/2001/XMLSchema">
<element name="process">
<complexType>
<sequence>
<element name="simpleinput" type="string"/>
<element name="arrayofObjects" maxOccurs="unbounded" nillable="true">
<complexType>
<sequence>
<element name="input1" type="string"/>
<element name="input2" type="string"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
<element name="processResponse">
<complexType>
<sequence>
<element name="arrayofObjectsoutput" maxOccurs="unbounded" nillable="true">
<complexType>
<sequence>
<element name="output1" type="string"/>
<element name="output2" type="string"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
so far I am able to manage for traversing in input array
oracle.xml.parser.v2.XMLElement e1=
(oracle.xml.parser.v2.XMLElement)getVariableData("inputVariable","payload","/client:process/client:arrayofObjects[1]/client:input1");
System.out.println(e1.getFirstChild().getNodeValue());
But my business requirement is to based on some logic set the values in output array.
for this I used following sample code.
for(int i=1; i < 4 ;i++)
{
setVariableData("outputVariable","payload","/client:processResponse/client:arrayofObjectsoutput['i']/client:output1",i);
setVariableData("outputVariable","payload","/client:processResponse/client:arrayofObjectsoutput['i']/client:output2",i);
}
My feeling is array would be created of length 3 and value will be settes(1,1) (2,2) (3,3) but at the output value is only (3,3) .
please tell me how can i achieve the same.
sample code will be appreciated.

The way I did it for a similar situation was to use a transformation to create the first element and then use the bpelx:insertAfter to insert additional array elements and then set them.
<assign name="Assign_2">
<bpelx:insertAfter>
<bpelx:from variable="outputVariable" part="payload"
query="/client:ArrayManipulationProcessResponse/client:arrayofObjectsoutput"/>
<bpelx:to variable="outputVariable" part="payload"
query="/client:ArrayManipulationProcessResponse/client:arrayofObjectsoutput"/>
</bpelx:insertAfter>
<copy>
<from expression="'MyOutput1-Index2'"/>
<to variable="outputVariable" part="payload"
query="/client:ArrayManipulationProcessResponse/client:arrayofObjectsoutput[2]/client:output1"/>
</copy>
<copy>
<from expression="'MyOutput2-Index2'"/>
<to variable="outputVariable" part="payload"
query="/client:ArrayManipulationProcessResponse/client:arrayofObjectsoutput[2]/client:output2"/>
</copy>
</assign>

If proprietary extensions do not work, you can try the standard BPEL approach and use an XSLT script to iteratively construct a result document.
An example is given in the BPEL 2.0 specification, pp 65, look for Iterative document construction.
Basically, the list and the element to add is passed (via the doXSLTransform XPath function) to an XSLT script, which copies the element to add to the list and returns the new document. This is then assigned to a variable.

I feel there is no need to write custom Java code for such a simple task. The following code (BPEL2.0) does the job of copying the values.<assign name="Copy values">
<extensionAssignOperation>
<bpelx:copyList>
<bpelx:from>$inputVariable.payload/ns1:arrayofObjects</bpelx:from>
<bpelx:to>$outputVariable.payload/ns1:arrayofObjectsoutput</bpelx:to>
</bpelx:copyList>
</extensionAssignOperation>
</assign>

Related

How to replace attributes in XML transforms without the name attribute

I am using SlowCheetah to transform my Log4Net files when I publish. However, it can't seem to distinguish between the attributes in different appender sections.
My Log4Net.config looks basically like this:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="DevEmail" />
<from value="DevEmail" />
<subject value="Dev Warning" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="Time: %date%newlineHost: %property{log4net:HostName}%newlineClass: %logger%newlineUser: %property{user}%newlineMessage: %message%newline%newline%newline" />
</layout>
<threshold value="WARN" />
</appender>
<appender name="FatalSmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="DevEmail" />
<from value="DevEmail" />
<subject value="Dev Fatal" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="Time: %date%newlineHost: %property{log4net:HostName}%newlineClass: %logger%newlineUser: %property{user}%newlineMessage: %message%newline%newline%newline" />
</layout>
<threshold value="FATAL" />
</appender>
</log4net>
And my transform file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<log4net xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="ProductionEmail" xdt:Transform="SetAttributes" />
<from value="ProductionEmail" xdt:Transform="SetAttributes" />
<subject value="Production Warning" xdt:Transform="SetAttributes" />
</appender>
<appender name="FatalSmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="ProductionEmail" xdt:Transform="SetAttributes" />
<from value="ProductionEmail" xdt:Transform="SetAttributes" />
<subject value="Production Fatal" xdt:Transform="SetAttributes" />
</appender>
</log4net>
The problem is that the transformed config has the same subject attribute value for both appenders; I guess when it hits the SetAttributes it can't tell which tag it's looking for, so it transforms all of them. What it the correct syntax to tell it to only find the elements within the same appender? I assume I need to use the xdt:Locator attribute, but I can't do Match(name) like I do for web.config because these elements don't have a name attribute. The appender element has a name attribute, but I don't know how to tell it to match based on the parent element's name.
I know that I could use replace on the appender node, with the match(Name), but then I would be replacing the entire node, including a bunch of elements such as the layout which I don't want to be transformed (and thus have multiple copy-pastes of the same code, which I would like to avoid).
I found the answer in this MSDN article: http://msdn.microsoft.com/en-us/library/dd465326.aspx.
I needed to use xdt:Locator="Match(name)" on the parent <appender> node, and then xdt:Transform on the child nodes. I had tried this previously but had used xdt:locator="Match(name)" instead of xdt:Locator="Match(name)"... The attribute is case sensitive.

How to show an array in json,when my table contains single record

I'm having trouble understanding why dataTables is refusing to show a single row of data but it works perfectly fine for any data sets greater than 1 row. I don't think this shows the issue either, as I think it's the format of the JSON message at fault here or as per my view filter is not working so.....directly it is going to then condition and returning the values from DBtable
This is a 10 record JSON response which works OK:
<sequence xmlns="http://ws.apache.org/ns/synapse" name="Getmessage_seq" onError="fault" trace="disable">
<property name="CONTENT_TYPE" value="application/json" scope="axis2" type="STRING"/>
<filter xmlns:ns="http://org.apache.synapse/xsd" xmlns:s="http://ws.wso2.org/dataservice" xpath="s://logid/text()=' '">
<then>
<payloadFactory>
<format>
<ResponseJSON xmlns="">
<Exception>NO Data Found In Database</Exception>
<Status>404</Status>
</ResponseJSON>
</format>
</payloadFactory>
<send/>
</then>
<else>
<property name="AAR" expression="count(//s:Datalist)" scope="default" type="STRING"/>
<enrich>
<source clone="true" type="custom" xpath="//s:Datalist"/>
<target action="replace" type="property" property="List"/>
</enrich>
<property name="CONTENT_TYPE" value="application/json" scope="axis2"/>
<payloadFactory>
<format>
<ResponseJSON xmlns="">
<Body>$1</Body>
<Status>200</Status>
<Total>$2</Total>
</ResponseJSON>
</format>
<args>
<arg expression="get-property('List')"/>
<arg expression="get-property('AAR')"/>
</args>
</payloadFactory>
<send/>
</else>
</filter>
</sequence>
enter code here
finally,when my table contains more than one record data is showing as an array in json,when it turns to one record data is not showing as an array in json.
You could wrap your single element in an array so that both responses have the same structure.
$myVar = array('recordSet' => $this->myRecord[0]);

Assigning List of Strings in BPEL

Is there a way to assign a list of strings from input variable to invoke input variable?The problem is that there are multiple inputs in my web service so i am not able to copy the wrapping element in input variable to wrapping variable in invoke variable.Will copy the snippet of the code here :
<assign name="Assign1">
<copy>
<from variable="inputVariable" part="payload"
query="/ns2:process/ns2:dsaName"/>
<to variable="Invoke1_processList_InputVariable"
part="parameters" query="/ns1:processList/dsaName"/>
</copy>
<copy>
<from variable="inputVariable" part="payload"
query="/ns2:process/ns2:linesOfData"/>
<to variable="Invoke1_processList_InputVariable"
part="parameters" query="/ns1:processList/linesOfData"/>
</copy>
<copy>
<from variable="inputVariable" part="payload"
query="/ns2:process/ns2:description"/>
<to variable="Invoke1_processList_InputVariable"
part="parameters" query="/ns1:processList/description"/>
</copy>
<copy>
<from variable="inputVariable" part="payload"
query="/ns2:process/ns2:application"/>
<to variable="Invoke1_processList_InputVariable"
part="parameters" query="/ns1:processList/application"/>
</copy>
</assign>
The problem is that only one is of list type all others are of string type.The XML for this is:
<element name="process">
<complexType>
<sequence>
<element name="dsaName" type="string" minOccurs="0"/>
<element name="linesOfData" type="string" minOccurs="0" maxOccurs="unbounded"/>
<element name="description" type="string" minOccurs="0"/>
</sequence>
</complexType>
</element>
<element name="processResponse">
<complexType>
<sequence>
<element name="result" type="string" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
</schema>
Looking at your schema, you can use doXSLTransform operation where <xsl:for-each> is used to read the list type (here it's linesOfData) and add each of those elements to Invoke1_processList_InputVariable.

NHibernate is updating my changed record during a .list call

I've got a record I'm editing in a ASP.net web app using nhibernate and MVP. When I make the changes to the record, I need to check to see that one field is unique (see 'friendlyUrl' below). However when I so my Criteria.List call, it updates the record as well as all child records (PharmacyStoreHours) first then does the select (found this out with a SQL profile). Obviously I don't want to update the record before the validation is complete and the validation fails as the data has been updated before the select. How do I do a select without the record updating?
As this is my first project with NHibernate, I'm not sure what would be causing this. I've copied what I've done from other parts of the code so if things look funny, please explain why they are so I can better understand what I should be doing.
NHibernate Config File Class:
<class table="Pharmacy" name="DataAccess.Domains.Pharmacy, DataAccess">
<id name="PharmacyId" column="PharmacyId" unsaved-value="0">
<generator class="increment" />
</id>
<property name="StoreAccountNumber" column="StoreAccountNumber" type="System.String" not-null="true" />
<property name="ClientName" column="ClientName" type="System.String" not-null="true" />
<property name="PharmacyName" column="PharmacyName" type="System.String" not-null="true" />
<property name="Address" column="Address" type="System.String" not-null="false" />
<property name="AddressContinued" column="AddressContinued" type="System.String" not-null="false" />
<property name="City" column="City" type="System.String" not-null="false" />
<property name="State" column="State" type="System.String" not-null="false" />
<property name="Zipcode" column="Zipcode" type="System.String" not-null="false" />
<property name="Phone" column="Phone" type="System.String" not-null="false" />
<property name="Fax" column="Fax" type="System.String" not-null="false" />
<property name="Email" column="Email" type="System.String" not-null="false" />
<property name="FriendlyUrl" column="FriendlyUrl" type="System.String" not-null="false" />
<property name="OwnersName" column="OwnersName" type="System.String" not-null="false" />
<property name="Latitude" column="Latitude" type="System.Decimal" not-null="false" />
<property name="Longitude" column="Longitude" type="System.Decimal" not-null="false" />
<bag name="Hours" table="PharmacyStoreHours" cascade="all" inverse="true">
<key column="PharmacyId" />
<one-to-many class="DataAccess.Domains.PharmacyWorkDays, DataAccess" />
</bag>
</class>
<class table="PharmacyStoreHours" name="DataAccess.Domains.PharmacyWorkDays, DataAccess">
<id name="PharmacyStoreHourId" column="PharmacyStoreHourId" unsaved-value="0">
<generator class="increment" />
</id>
<property name="WorkDay" column="WorkDay" type="System.Int32" not-null="true" />
<property name="OpenTime" column="OpenTime" type="System.DateTime" not-null="true" />
<property name="CloseTime" column="CloseTime" type="System.DateTime" not-null="true" />
<many-to-one name="PharmacyMap" class="DataAccess.Domains.Pharmacy, DataAccess" column="PharmacyId" not-null="true" />
</class>
Code:
public bool IsFriendlyUrlUnique(string clientName, string friendlyUrl)
{
bool result = false;
ICriteria crit = CurrentSession.CreateCriteria(typeof (Pharmacy));
crit.Add(new EqExpression("ClientName", clientName));
crit.Add(new EqExpression("FriendlyUrl", friendlyUrl));
crit.AddOrder(Order.Asc(PHARMACY_NAME));
if (crit.List<Pharmacy>().Count == 0)
result = true;
return result;
}
Thanks in advance for the help.
NHibernate essentially tracks all changes you make to the objects you have attached to your NHibernate session. When you retrieve an object, modifies it and then do a query to the database, NHibernate is faced with a problem. Let say, for argument's sake, that you retrieve a customer from the database, set customer.IsValuedCustomer = true and next query for all valued customers. NHibernate now has (at least) two options:
If NHibernate just translates the query you are doing to SQL and returns the result, the result might not be what you expect, because it will not include the newly promoted customer.
NHibernate can get the correct result by first flushing all the changes you've made to the database and only then executing the SQL query. This, however, means that even though you think you are doing a harmless query, it actually triggers a write to the database.
Based on your description I am not totally sure, but I think that what you are seeing is scenario 2 (btw, Entity Framework has chosen to go with option 1).
You could perhaps do your uniqueness-checking before making any changes to the object. However, this would still leave room for a race condition to occur: just after you checked for uniqueness some other thread might write a change to the database causing your new value to no longer be unique. To circumvent this, you could put the uniqueness constraint straight into your database schema, where it usually belongs.
Hope this helps
Advised Solution
I would advise, in the query, you filter out the current record.
ICriteria crit = CurrentSession.CreateCriteria(typeof (Pharmacy));
crit.Add(Restrictions.Not(Restrictions.Eq("PharmacyId", pharmacyIdToIgnore)));
crit.Add(Restrictions.Eq("ClientName", clientName));
crit.Add(Restrictions.Eq("FriendlyUrl", friendlyUrl));
crit.AddOrder(Order.Asc(PHARMACY_NAME));
crit.SetProjection(Projections.RowCount);
return crit.UniqueResult<int> == 0;
Ideally, you should perform this validation before you alter the entity itself. Also see Rune's answer about placing a constraint in the DB to enforce this constraint. This check is not to prevent duplicates, its to try and detect them earlier so you can present a nicer error message and avoid trying to commit a change that you know will fail.
Why this is happening (FlushMode)
This is on purpose to ensure the results from your query are consistent with the edits you have made locally. Since NHibernate is trying to model your entities as if they are always available in memory by automatically persisting to/from the database as required.
You can change this by looking at the auto flush setting. There is a default value on the session factory used for any newly created sessions, and an individual setting on each session.
The default value is FlushMode.Auto which will save when a transaction is committed or before running any query that might be affected by changes in memory. If you change it to FlushMode.Commit then it will only persist changes back to the database when committing a transaction, or when saving a new entity that uses a primary key strategy such as identity.
You can also manually persist the changes in the current session back to the database at any time using Session.Flush.

Constructing a sequence of nodes

Is there an easier way to do this
<Elements>
{
for $i in ("a", "b", "c")
return <Element name="{$i}"/>
}
</Elements>
in xquery?
You can use fn:map() is your XQuery processor has XQuery 3.0 support:
fn:map(function($e){ <Element name="{$e}" /> }, $sequence)
I don't really understand your question. What do you mean by easier?
How about:
<Elements>
<Element name="a" />
<Element name="b" />
<Element name="c" />
</Elements>
I also wonder what do you mean by "easier".
Have all items in a variable $seq and use:
for $i in 1 to count($seq)
return <Element name="{$seq[$i]}"/>
Here is a whole XQuery program:
let $seq := 1 to 15
return
for $i in 1 to count($seq)
return <Element name="a{$seq[$i]}"/>
and it produces the correct, wanted result:
<Element name="a1"/>
<Element name="a2"/>
<Element name="a3"/>
<Element name="a4"/>
<Element name="a5"/>
<Element name="a6"/>
<Element name="a7"/>
<Element name="a8"/>
<Element name="a9"/>
<Element name="a10"/>
<Element name="a11"/>
<Element name="a12"/>
<Element name="a13"/>
<Element name="a14"/>
<Element name="a15"/>

Resources