In my usecase i have to chain two service calls. In particular:
1) The first call returns an xml listing several IDs
2) i have to iterate through the returned ID list and to make an ID parameterized service call for each id-item.
3) Finally i have to collect a whole response made up of each single ID-service-response.
Suppose the first service call returns a response like this one:
<result>
<Link>
<Id>93451</Id>
</Link>
<Link>
<Id>93450</Id>
</Link>
...
The second step is to perform a series of calling to parameterized endpoint like this:
http://myEndpoint/entry/eutils/efetch.fcgi?db=pubmed&rettype=abstract&retmode=xml&id=<ID>
each call of which returns an xml response like this:
<response>
<field1>value1</field1>
<field2>value2</field2>
<field3>value3</field3>
<response>
I have to collect a whole response like this one:
<finalResponse>
<response>
<field1>value1</field1>
<field2>value2</field2>
<field3>value3</field3>
<response>
<response>
<field1>value1</field1>
<field2>value2</field2>
<field3>value3</field3>
<response>
<response>
<field1>value1</field1>
<field2>value2</field2>
<field3>value3</field3>
<response>
</finalResponse>
How can i do? Could you give me some example? Thanks
You need to use iterate mediator and aggregate mediator in combination. Here is a sample code, but you may need to do some modification in order to make it work for your requirements.
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="SampleProxy">
<target>
<inSequence>
<iterate expression="//result/link/id" preservePayload="true"
attachPath="//link">
<target>
<property name="uri.var.servicepath" expression="//link/id/text()"/>
<sequence>
<send>
<endpoint key="MyEndpoint"/>
</send>
</sequence>
</target>
</iterate>
</inSequence>
<outSequence>
<property name="FinalResponse" scope="default">
<finalResponse />
</property>
<aggregate>
<onComplete expression="//response"
enclosingElementProperty="FinalResponse">
<send/>
</onComplete>
</aggregate>
</outSequence>
</target>
</proxy>
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="MyEndpoint">
<http uri-template="http://myEndpoint/entry/eutils/efetch.fcgi?db=pubmed&rettype=abstract&retmode=xml&id={ID}" method="GET">
</http>
</endpoint>
</definitions>
Full documentation on related sample here.
Find how you can parameterize you url here.
Related
I'm using WSO2 with the VFS. I need to take the incoming file, fileinput.xml and log the id fields together. The VFS is enabled and functional and when I move my fileinput.xml into my test_in folder it appropriately gets handled and put into test_out or test_failure correctly. I've read a lot of online documentation but have been unable to wrap my head around how to do the following.
My Question is
How do I get a property from my fileinput.xml ?
How do I iterate over the ids and concatenate them together in a log?
fileinput.xml
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<customers>
<customer>
<id>testid1</id>
<prop1>a</prop1>
<prop2>b</prop2>
<customer/>
<customer>
<id>testid2</id>
<prop1>3</prop1>
<prop2>4</prop2>
<customer/>
</customers>
</soapenv:Body>
</soapenv:Envelope>
My wso2 proxy file
<?xml version="1.0" encoding="UTF-8"?>
<proxy
xmlns="http://ws.apache.org/ns/synapse" name="FileProxy" transports="vfs" startOnLoad="true" trace="disable">
<target>
<parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
<parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter>
<parameter name="transport.PollInterval">5</parameter>
<parameter name="transport.vfs.FileURI">file:///Users/myuser/test_in</parameter>
<parameter name="transport.vfs.MoveAfterProcess">file:///Users/myusertest_out</parameter>
<parameter name="transport.vfs.MoveAfterFailure">file:///Users/myuser/test_failure</parameter>
<parameter name="transport.vfs.FileNamePattern">.*.xml</parameter>
<parameter name="transport.vfs.ContentType">text/xml</parameter>
<inSequence>
<log category="WARN" level="full">
<property name="MESSAGE" value="In Sequence"/>
</log>
<clone>
<target sequence="fileWriteSequence"/>
</clone>
</inSequence>
</target>
<outSequence>
<log category="WARN" level="full">
<property name="MESSAGE" value="Out Sequence"/>
</log>
<send/>
</outSequence>
</proxy>
My fileWriteSequence
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="fileWriteSequence">
<log level="full">
<property name="sequence" value="fileWriteSequence"/>
</log>
<property name="transport.vfs.ReplyFileName" expression="fn:concat(fn:substring-after(get-property('MessageID'), 'urn:uuid:'), '.txt')" scope="transport"/>
<property name="OUT_ONLY" value="true"/>
<send>
<endpoint name="FileEpr">
<address uri="vfs:file:///Users/myuser/test_out"/>
</endpoint>
</send>
</sequence>
You can use the iterate mediator to iterate over 'id' element and use a property in the operation scope to concatenate all the id values. Refer this
Ok, this is a continuation to my original question. (WSo2 Esb filtering messages to an output file)
After a couple more days of research into the iterate and aggregate mediator I have reached a progress wall and would be very grateful for any advice how to resolve my blocking issue. The task at hand is simple, read and xml file, filter on certain records, and only produce an output xml file with just those records that meet the criteria. After previous discussion and research this tasks solution is as follows: use a iterate mediator to access each xml record and use a filter mediator to decide what I want to keep. Then use a aggregator mediator to write all these records to 1 file. Without the aggregator my configuration is producing 1 record per file.
Here is my proxy at this state:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="RenFileFilterProxy"
transports="vfs"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<log level="full"/>
<clone>
<target sequence="RenIqtFilterSequence"/>
</clone>
</inSequence>
<outSequence>
<log level="custom">
<property name="sequence" value="In the outSequence"/>
</log>
<log level="full"/>
<aggregate id="QuizType">
<completeCondition>
<messageCount min="-1" max="-1"/>
</completeCondition>
<onComplete xmlns:z="RowsetSchema" expression="//z:row">
<call-template target="FileWriteTemplate">
<with-param name="targetFileName" value="TEST_FILE"/>
<with-param name="addressUri" value="vfs:file:///var/process/ren/rrout"/>
</call-template>
</onComplete>
</aggregate>
</outSequence>
</target>
<parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
<parameter name="transport.PollInterval">15</parameter>
<parameter name="transport.vfs.MoveAfterProcess">file:///var/process/ren/extractedfiles</parameter>
<parameter name="transport.vfs.FileURI">file:///var/process/ren/extractedfiles</parameter>
<parameter name="transport.vfs.MoveAfterFailure">file:///var/process/ren/failure</parameter>
<parameter name="transport.vfs.FileNamePattern">test.xml</parameter>
<parameter name="transport.vfs.ContentType">application/xml</parameter>
<parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter>
<description/>
</proxy>
Here is the RenIqtFilterSequence:
<sequence xmlns="http://ws.apache.org/ns/synapse" name="RenIqtFilterSequence">
<log level="custom">
<property name="sequence" value="RenIqtFilterSequence"></property>
</log>
<iterate xmlns:ns2="http://org.apache.synapse/xsd" xmlns:ns="http://org.apache.synapse/xsd" xmlns:z="RowsetSchema" expression="//z:row" id="QuizType">
<target>
<sequence>
<log>
<property name="iteratesequence" value="Iterating through the the records"></property>
</log>
<filter xmlns:rs="urn:schemas-microsoft-com:rowset" xpath="//z:row/#name='RP'">
<then>
<log level="custom">
<property name="sequence" value="Condition Write"></property>
</log>
<log level="full"></log>
<log level="custom">
<property name="sequence" value="Getting ready to aggregate"></property>
</log>
</then>
<else>
<log level="custom">
<property name="sequence" value="Condition Drop"></property>
</log>
<drop></drop>
</else>
</filter>
</sequence>
</target>
</iterate>
</sequence>
The issue I am facing now is I cannot get to the outSequence to perform my aggregator logic. The fact is I do not need to call a backend service for this process from the inSequence so I am struggling to find a clean way to get to my outSequence. Any Recomendations? I tried to include the aggregator mediator in my inSequence but it did not work, no output is produced. I figured the aggregator needs to be in the outSequence to capture all the records I filtered and then I can write them all out to 1 file.
I believe I need some configuration here:
<filter xmlns:rs="urn:schemas-microsoft-com:rowset" xpath="//z:row/#name='RP'">
<then>
<log level="custom">
<property name="sequence" value="Condition Write"></property>
</log>
<log level="full"></log>
<log level="custom">
<property name="sequence" value="Getting ready to aggregate"></property>
</log>
===============> Need to transfer to OutSequence somehow here!!!!<============
</then>
<else>
I have tried several approaches based on articles and blogs online but I just cannot put the final pieces in place. Any advice would be much appreciated. Thank you for your time reading this.
I am new to wso2 and working on a few POCs where i have to create a file at some location , i have looked into all vfs examples where there is always a file processed and written to a new location.
What i want to achieve is write a new file to a directory by the content i receive in a sequence.
For my requirement process i have exposed a REST service and it calls this sequence.
The sequence configuration is as follows.
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="FileWriteSequence">
<clone>
<target>
<sequence>
<property name="OUT_ONLY" value="true" scope="default" type="STRING"/>
<property name="transport.vfs.ReplyFileName" value="myOutputFile.txt" scope="transport" type="STRING"/>
<send>
<endpoint name="FileEpr">
<address uri="vfs:file://D:/Tools"/>
</endpoint>
</send>
</sequence>
</target>
</clone>
This sequence creates a file from the latest message from the REST resource but the file name is always the project name.
Whatever i try it doesnt change.
I have tried giving other proxy parameters shown below as property above my sequence as well .Instead of paramters i passed them above the property <property name="OUT_ONLY" value="true" scope="default" type="STRING"/>
Namely :-
<parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
<parameter name="transport.vfs.MoveAfterProcess">file://D:/Tools</parameter>
<parameter name="transport.vfs.MoveAfterFailure">file://D:/backup</parameter>
<parameter name="transport.vfs.FileNamePattern">.*.txt</parameter>
<parameter name="transport.vfs.ContentType">text/plain</parameter>
<parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter>
Still no progress.
Can anyone help me here?
Regards,
Rahul.
In case anyone wants to know i have made a workaround for this i called a proxy service from my rest resource and it worked .
In my resource i called endpoint like this
<send>
<endpoint key="FileProxyEndPt"/>
</send>
Then i created a proxy service as follows
<proxy xmlns="http://ws.apache.org/ns/synapse" name="FileWriteProxy"
transports="http https vfs" startOnLoad="true" trace="enable">
<target>
<inSequence>
<clone>
<target sequence="FileWriteSequence" />
</clone>
</inSequence>
<outSequence />
<faultSequence />
</target>
<parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
<parameter name="transport.vfs.MoveAfterProcess">file://D:/Tools</parameter>
<parameter name="transport.vfs.MoveAfterFailure">file://D:/backup</parameter>
<parameter name="transport.vfs.ContentType">text/plain; charset=ISO-8859-1</parameter>
<parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter>
This way it worked it but never worked exactly in a resource.So had to take a longer route , hope somebody provides a solution which can be implemented directly.
I have the following JPA code, with all the values checked (ticket contains a valid bean, it ends without exception, etc.) It is executed, it does not throw any exceptions, yet in the end no data is written into the table.
I tried also retrieving a bean from the table, it also "works" (it is empty, so no data is returned).
The setup is
JBoss 6.1 Final
SQLServer 2008 Express (driver SQL JDBC 3 from MS)
The persistence code:
public String saveTicket() {
System.out.println("Controller saveTicket() ");
EntityManagerFactory factory = Persistence.createEntityManagerFactory("GesMan"); /* I know it would be better to share a single instance of factory, this is just for testing */
EntityManager entityMan = factory.createEntityManager();
entityMan.persist(this.ticket);
entityMan.close();
}
The persistence unit is
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="GesMan" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/GesManDS</jta-data-source>
<class>es.caib.gesma.gesman.Ticket</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
The datasource
<datasources>
<local-tx-datasource>
<jndi-name>GesManDS</jndi-name>
<connection-url>jdbc:sqlserver://spsigeswnt14.caib.es:1433;DatabaseName=TEST_GESMAN</connection-url>
<driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class>
<user-name>thisis</user-name>
<password>notthepassword</password>
<check-valid-connection-sql>SELECT * FROM dbo.Ticket</check-valid-connection-sql>
<metadata>
<type-mapping>MS SQLSERVER</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
call entityMan.flush() or transaction.commit() befor closing it, otherwise it will discard all changes queued on close.
In the end it looks like I was using the wrong approach.... In JBoss you can`t (better said, I could not get to) access JPA directly (as you would do in JSE).
I ended creating an EJB (with transactions) and passing all JPA logic there.
PS: Of course, if I am wrong please tell me (now it is more of an academic issue, but still I want to know)
I was wondering if it is possible to build a cxf-bc with WS-SecurityPolicy instead of just the WS-Security. WS-SecurityPolicy seems to be a more elegant solution since everything is in the WSDL. Examples welcome. :)
Well with David's help I got the CXF-BC to install and running on the ESB, but I can't seem to test it. It keeps coming back with:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>These policy alternatives can not be satisfied:
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}UsernameToken</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
My msg:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://nwec.faa.gov/wxrec/UserAccount/types">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/ws-securitypolicy-1.2.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-25" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>bob</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">bobspassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<wsa:Action>http://nwec.faa.gov/wxrec/UserAccount/UserAccountPortType/ApproveDenyAccountRequest</wsa:Action>
</soapenv:Header>
<soapenv:Body>
...
</soapenv:Body>
Here's the policy in the wsdl:
<wsp:Policy wsu:Id="UserAccountBindingPolicy" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:ExactlyOne>
<wsp:All>
<wsaw:UsingAddressing xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" wsp:Optional="true" />
<wsp:Policy >
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Always">
<wsp:Policy>
<sp:WssUsernameToken10 />
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
As of the resolution of https://issues.apache.org/activemq/browse/SMXCOMP-711 and https://issues.apache.org/activemq/browse/SMXCOMP-712 (servicemix-cxf-bc-2010.01) it should be possible and easy to do.
See http://fisheye6.atlassian.com/browse/servicemix/components/bindings/servicemix-cxf-bc/trunk/src/test/java/org/apache/servicemix/cxfbc/ws/security/CxfBcSecurityJAASTest.java?r=HEAD for an example. Specifically the testJAASPolicy method.
As for the error relating to asserting the UsernameToken assertion, you may want to try putting the UsernameToken assertion inside of a SupportingToken or binding assertion depending on what you want to do with the token. It looks like you just want a username and password to be passed in the message without any other security such as a cryptographic binding of the token to the message or encryption so a supporting token will likely fit your needs.
I also urge you to consider the following additional precautions when using a UsernameToken:
Cryptographically bind the token to the message using a signature.
Use a nonce and created timestamp and cache the token on the server to prevent replay
Consider encrypting the token (before signing if you also sign) using XML enc
Using TLS either in lieu of or in addition to the above suggestions
With david's and Freeman over at the servicemix-user mailing-list. I was able finally get the correct configuration to implement WS-Security Policy.
Here's my final beans.xml for the my BC
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxfbc="http://servicemix.apache.org/cxfbc/1.0" xmlns:util="http://www.springframework.org/schema/util"
xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:sec="http://cxf.apache.org/configuration/security"
xmlns:person="http://www.mycompany.com/ws-sec-proto"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://servicemix.apache.org/cxfbc/1.0
http://repo2.maven.org/maven2/org/apache/servicemix/servicemix-cxf-bc/2010.01/servicemix-cxf-bc-2010.01.xsd
http://cxf.apache.org/transports/http-jetty/configuration
http://cxf.apache.org/schemas/configuration/http-jetty.xsd
http://cxf.apache.oarg/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http.xml" />
<import resource="classpath:META-INF/cxf/osgi/cxf-extension-osgi.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-policy.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-ws-security.xml" />
<bean id="myPasswordCallback" class="com.mycompany.ServerPasswordCallback" />
<cxfbc:consumer wsdl="classpath:wsdl/person.wsdl"
targetService="person:PersonService" targetInterface="person:Person"
properties="#properties" delegateToJaas="false" >
<!-- not important for ws-security
<cxfbc:inInterceptors>
<bean class="com.mycompany.SaveSubjectInterceptor" />
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</cxfbc:inInterceptors>
-->
</cxfbc:consumer>
<util:map id="properties">
<entry>
<key>
<util:constant
static-field="org.apache.cxf.ws.security.SecurityConstants.CALLBACK_HANDLER" />
</key>
<ref bean="myPasswordCallback" />
</entry>
</util:map>
<httpj:engine-factory bus="cxf">
<httpj:engine port="9001">
<httpj:tlsServerParameters>
<sec:keyManagers keyPassword="password">
<sec:keyStore type="JKS" password="password" resource="certs/cherry.jks" />
</sec:keyManagers>
<sec:cipherSuitesFilter>
<sec:include>.*_WITH_3DES_.*</sec:include>
<sec:include>.*_WITH_DES_.*</sec:include>
<sec:exclude>.*_WITH_NULL_.*</sec:exclude>
<sec:exclude>.*_DH_anon_.*</sec:exclude>
</sec:cipherSuitesFilter>
<sec:clientAuthentication want="false"
required="false" />
</httpj:tlsServerParameters>
</httpj:engine>
</httpj:engine-factory>
<bean id="cxf" class="org.apache.cxf.bus.CXFBusImpl" />
<bean class="org.apache.servicemix.common.osgi.EndpointExporter" />
</beans>
Full example can be found here but it may not be there after a while.