I went through the documentation, which helped me figure out several issues I had, but not the following two problems:
1) I have got a get(GET) method: get(#Context Request request, #PathParam("isbn")String isbn)
How do I formulate the WADL for it so that I get the #Context in the produced Java code?
2) I have got a update (PUT) method: update(#PathParam("isbn") String isbn, BookState st)
How do I formuate the WADL to get the BookState in the produced Java code?
Here is my current WADL, which does not do it:
<resource path="/{isbn}">
....
<method name="GET" id="get" >
<request />
<response>
<representation mediaType="application/xml" element="prefix1:book" />
</response>
</method>
<method name="PUT" id="update" >
<request>
<representation mediaType="application/xml" element="prefix1:book" />
</request>
<response>
<representation mediaType="application/octet-stream" />
</response>
</method>
</resource>
Related
I have a C# client which produces the .NET SOAP envelope below, which works against a C# ASMX SOAP web service. However we have a Java Client calling into our service which is producing the Java envelope specified below. The main difference between the envelopes is that some values are serialised as attributes in the java client envelope rather than as XML element nodes in the C# client envelope. The java client is using AXIS WSDL2Java to generate their client. Would anyone know what I would need to tell the Java developers so they may generate the correct soap envelope for the example shown.
Kind Regards
Working SOAP Envelope Captured from C# Client
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<getDocumentPageRequest xmlns="urn:mycorp-com:MyApp.Schema.DocumentEnquiry.Messages.v01">
<header xmlns="urn:mycorp-com:MyApp.Schema.Common.Types.v01">
<extensions />
<corelationIdentifier>41edebfb-fffd-44f8-94e9-be043e1dad48</corelationIdentifier>
</header>
<securityToken xmlns="urn:mycorp-com:MyApp.Schema.Common.Types.v01">
<Value>218FD85D</Value>
</securityToken>
<documentIdentifier>15236HDFG000005</documentIdentifier>
<pageNumber>1</pageNumber>
</getDocumentPageRequest>
</soap:Body>
</soap:Envelope>
Java SOAP Envelope - Not working with web-service
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<getDocumentPageRequest
documentIdentifier="15236HDFG000005"
pageNumber="1"
xmlns="urn:mycorp-com:MyApp.Schema.DocumentEnquiry.Messages.v01">
<ns1:header corelationIdentifier="" xmlns:ns1="urn:mycorp-com:MyApp.Schema.Common.Types.v01">
<ns1:extensions/>
</ns1:header>
<ns2:securityToken xmlns:ns2="urn:mycorp-com:MyApp.Schema.Common.Types.v01">218FD85D</ns2:securityToken>
</getDocumentPageRequest>
</soapenv:Body>
</soapenv:Envelope>
Edited:: Added in WSDL as requested.
Sample WSDL and XSD Extract
Below is a sample of the WSDL generated and an extract of the XSD that it imports for the message type. I can see in this that the XML has attributes, which is what the AXIS WSDL2Java is generating, but the C# proxy and web-service is expecting XML nodes. I think this means the way the C# services is implemented is different somehow or other than the schema it is defined against. This is confusing...
<!-- WSDL Extract -->
<message name="getDocumentPageIn">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" />
<part name="messagePart" element="import0:getDocumentPageRequest" />
</message>
<message name="getDocumentPageOut">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" />
<part name="messagePart" element="import0:getDocumentPageResponse" />
</message>
<!-- import0 XSD extract -->
<xs:element name="getDocumentPageRequest">
<xs:complexType>
<xs:complexContent>
<xs:extension base="MyApp:request">
<xs:attribute name="documentIdentifier" type="xs:string" use="required"/>
<xs:attribute name="pageNumber" type="xs:short" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
Thanks for taking the time to review this, but I found the actual problem.
It turns out the C# code that was being generated for the types for the web-service and proxy was missing an [XmlAttribute] attribute in the code for each attribute defined in the XML. This caused the XmlSerializer to flatten the properties on the class to elements rather than keeping them as attributes.
I am using Liferay 6.1.1 CE.
I've created a multilevel kaleo workflow (i.e. with two levels of approvals), by writing a definition in a xml file (leaveapproval.xml) and loading it to the server. It works fine as I have tested this workflow in Blogs.
So now, I wants to submit the content of the workflow to a web service after completing the second level approval.
How can i handle the content of the workflow?
Is it possible?
<?xml version="1.0"?>
<workflow-definition
xmlns="urn:liferay.com:liferay-workflow_6.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:liferay.com:liferay-workflow_6.1.0 http://www.liferay.com/dtd/liferay-workflow-definition_6_1_0.xsd">
<name>LEAVE IN ACTION USER ACTION</name>
<description>A sample multilevel approver can approve a workflow content.</description>
<version>1</version>
<state>
<name>created</name>
<metadata>
<![CDATA[
{"xy":[36,51]}
]]>
</metadata>
<initial>true</initial>
<transitions>
<transition>
<name>review</name>
<target>review</target>
<default>true</default>
</transition>
</transitions>
</state>
<task>
<name>review</name>
<metadata>
<![CDATA[
{"xy":[168,36]}
]]>
</metadata>
<actions>
<notification>
<name>Review Notification</name>
<template>You have a new submission waiting for review in the workflow.</template>
<template-language>text</template-language>
<notification-type>email</notification-type>
<execution-type>onAssignment</execution-type>
</notification>
<notification>
<name>Review Completion Notification</name>
<template>
Your submission has been reviewed and the reviewer has applied the following ${taskComments}.</template>
<template-language>freemarker</template-language>
<notification-type>email</notification-type>
<recipients>
<user />
</recipients>
<execution-type>onExit</execution-type>
</notification>
</actions>
<assignments>
<roles>
<role>
<role-type>regular</role-type>
<name>Portal Head</name>
</role>
<role>
<role-type>regular</role-type>
<name>Portal Content Reviewer</name>
</role>
</roles>
</assignments>
<transitions>
<transition>
<name>approve</name>
<target>recommended</target>
</transition>
<transition>
<name>reject</name>
<target>update</target>
<default>false</default>
</transition>
</transitions>
</task>
<task>
<name>recommended</name>
<metadata>
<![CDATA[{"xy":[168,36]}]]>
</metadata>
<actions>
<notification>
<name>Review Notification</name>
<template>You have a new submission waiting for your review in the workflow.</template>
<template-language>text</template-language>
<notification-type>email</notification-type>
<execution-type>onAssignment</execution-type>
</notification>
<notification>
<name>Review Completion Notification</name>
<template>
Your submission has been reviewed and the reviewer has applied the following ${taskComments}.</template>
<template-language>freemarker</template-language>
<notification-type>email</notification-type>
<recipients>
<user />
</recipients>
<execution-type>onExit</execution-type>
</notification>
</actions>
<assignments>
<user>
<user-id>13379</user-id>
</user>
</assignments>
<transitions>
<transition>
<name>approve</name>
<target>approved</target>
</transition>
<transition>
<name>reject</name>
<target>update</target>
<default>false</default>
</transition>
</transitions>
</task>
<task>
<name>update</name>
<metadata>
<![CDATA[
{"transitions":{"resubmit":{"bendpoints":[[303,140]]}},"xy":[328,199]}
]]>
</metadata>
<actions>
<action>
<name>reject</name>
<script>
<![CDATA[
Packages.com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil.updateStatus(
Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.toStatus("denied"),
workflowContext);
Packages.com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil.updateStatus(
Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.toStatus("pending"),
workflowContext);
]]>
</script>
<script-language>javascript</script-language>
<execution-type>onAssignment</execution-type>
</action>
<notification>
<name>Creator Modification Notification</name>
<template>Your submission was rejected by a reviewer, please modify and resubmit.</template>
<template-language>text</template-language>
<notification-type>email</notification-type>
<execution-type>onAssignment</execution-type>
</notification>
</actions>
<assignments>
<user />
</assignments>
<transitions>
<transition>
<name>resubmit</name>
<target>review</target>
</transition>
</transitions>
</task>
<state>
<name>approved</name>
<metadata>
<![CDATA[
{"xy":[380,51]}
]]>
</metadata>
<actions>
<action>
<name>approve</name>
<script>
<![CDATA[Packages.com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil.updateStatus (Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.toStatus("approved"), workflowContext);]]>
</script>
<script-language>javascript</script-language>
<execution-type>onEntry</execution-type>
</action>
</actions>
</state>
</workflow-definition>
Help me..
For running anything programmatically on a certain workflow step, you generally just need a <script> tag, just like you're doing to update the statuses.
So, in your approved <state>, you'd probably want to add another <action> tag, this one to handle the web service call (and let the other action remain the way it is).
The language you'd use for the script will depend on what you're comfortable with. I'd use groovy, since it handles plain java code pretty well, and that's what I know.
Here's what it might look like (only including that last <state> tag):
<state>
<name>approved</name>
<metadata>
<![CDATA[
{"xy":[380,51]}
]]>
</metadata>
<actions>
<action>
<name>approve</name>
<script>
<![CDATA[
Packages.com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil.updateStatus(
Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.toStatus("approved"),
workflowContext);
]]>
</script>
<script-language>javascript</script-language>
<execution-type>onEntry</execution-type>
</action>
<action>
<name>submit-web-service</name>
<script>
<![CDATA[
import java.io.*
import java.net.*
URL url = new URL(
"www.my-web-service.com/api/whatever?theParam=" +
${theRelevantContextVariable});
URLConnection urlConnection = url.openConnection();
// if necessary to read response data:
// BufferedReader bufferedReader = new BufferedReader(
// new InputStreamReader(urlConnection.getInputStream()));
// String something = bufferedReader.readLine();
// etc.
]]>
</script>
<script-language>groovy</script-language>
<execution-type>onEntry</execution-type>
</action>
</actions>
</state>
You may need a POST request instead, in which case you'd implement the web service call differently. But in any case you'd write the web service code in an action tag. Something like this should work.
I'm testing out Jersey and I can't seem to figure out why I get a 405 Method Not Allowed when I call PUT:
#Singleton #Path("images")
public class ImageResource {
private static final String IMAGE_ID_PATH_PARAM = "{imageId : [A-Za-z0-9_\\-]+}";
private static final String EXTENSION_PATH_PARAM = "{extension : (\\.[A-Za-z]+)?}";
#GET #Path(IMAGE_ID_PATH_PARAM + EXTENSION_PATH_PARAM)
#Produces("image/*")
public Response getImage(#PathParam("imageId") String imageId,
#PathParam("extension") String extension, #QueryParam("mods") String mods) {
...
}
#PUT #Path(IMAGE_ID_PATH_PARAM)
#Consumes("image/*")
public Response putImage(#PathParam("imageId") String imageId, File image) {
...
}
}
PUT only works if I set the #GET path to #Path(IMAGE_ID_PATH_PARAM). When I add the extension part, I am getting a 405 status code. GET seems to work in both cases. Here's the output from a failed PUT:
$ curl -v --header "Content-Type: image/jpeg" --upload-file /Users/andy/Desktop/test.jpg http://localhost:9090/images/abcde
* About to connect() to localhost port 9090 (#0)
* Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 9090 (#0)
> PUT /images/abcde HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:9090
> Accept: */*
> Content-Type: image/jpeg
> Content-Length: 48198
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
< HTTP/1.1 405 Method Not Allowed
< Content-Type: text/html; charset=iso-8859-1
< Date: Mon, 20 Aug 2012 18:35:59 GMT
< Allow: GET,OPTIONS,HEAD
< Transfer-Encoding: chunked
I've also tried testing without the #Produces and #Consumes annotations and it did not work either.
Let's take a look at what happens when you send the request.
Situation 1: no extension
Your methods look like this:
#GET #Path(IMAGE_ID_PATH_PARAM)
#Produces("image/*")
public Response getImage(#PathParam("imageId") String imageId,
#PathParam("extension") String extension, #QueryParam("mods") String mods) {
...
}
#PUT #Path(IMAGE_ID_PATH_PARAM)
#Consumes("image/*")
public Response putImage(#PathParam("imageId") String imageId, File image) {
...
}
When you send the following request:
PUT http://localhost:9090/images/abcde
first of all, Jersey looks for resources with the URI in question:
http://localhost:9090/images/abcde
After the resource is found, it checks what methods can be used to access it.
In this case, you have a single resource with the path defined by IMAGE_ID_PATH_PARAM. This resource can be accessed by either GET or PUT requests. Just like you specified with the annotations.
Situation 2: extension added to getImage
You methods now look like this:
#GET #Path(IMAGE_ID_PATH_PARAM + EXTENSION_PATH_PARAM)
#Produces("image/*")
public Response getImage(#PathParam("imageId") String imageId,
#PathParam("extension") String extension, #QueryParam("mods") String mods) {
...
}
#PUT #Path(IMAGE_ID_PATH_PARAM)
#Consumes("image/*")
public Response putImage(#PathParam("imageId") String imageId, File image) {
...
}
Again, you send the same request:
PUT http://localhost:9090/images/abcde
And yet again, Jersey finds the first resource matching the URL. The resource is represented by your getImage method, just like the first time. This time again, the #GET annotation does not match your request. And just like before, Jersey tries to find another method available for the resource, in order to match your request.
This time, however, no such method is found so it returns a 405.
The reason why this happens is that the methods getImage and putImage now represent different resources. If you look carefully, the paths can be read like this (I'll omit the regex for clarity):
#Path({imageId}{extension}) for getImage
and
#Path({imageId}) for putImage
While these two paths, considering the regex, can become the same thing, Jersey still sees them as identifiers of separate resources.
If you take a look at the WADL (feel free to look here if you're not familiar with the standard) file generated by Jersey (it should be available at http://localhost:9090/application.wadl), you'll notice that this is exactly what's happening.
<application xmlns="http://research.sun.com/wadl/2006/10">
<resources base="http://localhost:9090/">
<resource path="images">
<resource path="{imageId : [A-Za-z0-9_\-]+}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="imageId" style="template" type="xs:string"/>
<method id="putImage" name="PUT">
<request>
<representation mediaType="image/*"/>
</request>
<response>
<representation mediaType="*/*"/>
</response>
</method>
</resource>
<resource path="{imageId : [A-Za-z0-9_\-]+}{extension : (\.[A-Za-z]+)?}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="extension" style="template" type="xs:string"/>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="imageId" style="template" type="xs:string"/>
<method id="getImage" name="GET">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="mods" style="query" type="xs:string"/>
</request>
<response>
<representation mediaType="image/*"/>
</response>
</method>
</resource>
</resource>
</resources>
</application>
Notice how images has two, separate sub-resources, each one with a single method.
Solution
Adding the EXTENSION_PATH_PARAM segment to putImage's #Path annotation causes these two methods to be mapped to a single resource again, so the problem disappears. Since the regex makes this part optional, you are free to omit it and pretend it doesn't exist.
The difference can be clearly seen in the generated WADL.
<application xmlns="http://research.sun.com/wadl/2006/10">
<resources base="http://localhost:9090/">
<resource path="images">
<resource path="{imageId : [A-Za-z0-9_\-]+}{extension : (\.[A-Za-z]+)?}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="extension" style="template" type="xs:string"/>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="imageId" style="template" type="xs:string"/>
<method id="putImage" name="PUT">
<request>
<representation mediaType="image/*"/>
</request>
<response>
<representation mediaType="*/*"/>
</response>
</method>
<method id="getImage" name="GET">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="mods" style="query" type="xs:string"/>
</request>
<response>
<representation mediaType="image/*"/>
</response>
</method>
</resource>
</resource>
</resources>
</application>
In this case, images has exactly one sub-resource, which in turn has two available methods.
Personally, I find the automatic generation of WADL a fantastic feature of Jersey. It's a great way to see what's happening with your resource methods without spending too much time with curl or other REST client.
My Java application tries to get information from a webservice. The XML request needs to have the namespace specified in the XML root element (class name), but the namespace of the tags (class fields) need to be empty (null), otherwise the webservice rejects the request.
I have to use Spring 3.0 and Spring WS 2.0 with CastorMarshaller (currently using Castor version 1.3.1) to marshall/unmarshall my Java objects into/from XML.
Please note the __PREFIX__ and __NAMESPACE__ locations in following code snippets.
Desired marshalled output
(i.e. the desired generated SOAP request)
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" />
<soap-env:Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<__PREFIX__:className xmlns:__PREFIX__="__NAMESPACE__">
<fieldName>fieldValue</fieldName>
</__PREFIX__:className>
</soap-env:Body>
</soap-env:Envelope>
Currently marshalled output (i.e. the generated SOAP request)
Not adding the namespace
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" />
<soap-env:Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<className>
<fieldName>fieldValue</fieldName>
</className>
</soap-env:Body>
</soap-env:Envelope>
or adding the namespace to all elements
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" />
<soap-env:Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<__PREFIX__:className xmlns:__PREFIX__="__NAMESPACE__">
<__PREFIX__:fieldName xmlns:__PREFIX__="__NAMESPACE__">fieldValue</__PREFIX__:fieldName>
</__PREFIX__:className>
</soap-env:Body>
</soap-env:Envelope>
which are both rejected by the webservice.
My configuration
CastorMarshaller bean in applicationContext.xml
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation" value="classpath:castor-mapping.xml" />
<property name="ignoreExtraAttributes" value="true" />
<property name="ignoreExtraElements" value="true" />
<property name="namespaceMappings">
<map>
<entry key="__PREFIX__" value="__NAMESPACE__" />
</map>
</property>
</bean>
Castor Mapping file castor-mapping.xml
Not adding the namespace (namespace specified in the castorMarshaller bean through namespaceMappings should be added to the root)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="some.package.ClassName">
<map-to xml="className">
<field name="fieldName" type="string">
<bind-xml name="fieldName" node="element" />
</field>
</class>
</mapping>
or adding the namespace to all elements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="some.package.ClassName">
<map-to xml="className" ns-uri="__NAMESPACE__" ns-prefix="__PREFIX__">
<field name="fieldName" type="string">
<bind-xml name="fieldName" node="element" />
</field>
</class>
</mapping>
Since I am facing the same problem, a solution that I am considering is the following:
Create a interceptor extending EndpointInterceptorAdapter
Override handleResponse method
Modify to soap message by directly access or using a transformer
public class MyEndpointInterceptorAdapter extends
EndpointInterceptorAdapter{
#Override
public boolean handleResponse(MessageContext msgContext, Object endpoint) throws IOException {
WebServiceMessage responseMsg = msgContext.getResponse();
SoapMessage soapMsg = (SoapMessage) responseMsg;
if(soapMsg!=null){
SoapEnvelope soapEnvelope=soapMsg.getEnvelope();
if(soapEnvelope!=null){
SoapBody soapbody=soapEnvelope.getBody();
if(soapbody!=null){
Source bodySource=soapbody.getSource();
if(bodySource instanceof DOMSource){
DOMSource bodyDomSource=(DOMSource)bodySource;
Node bodyNode=bodyDomSource.getNode();
if(bodyNode!=null){
NodeList bodyNodeList=bodyNode.getChildNodes();
if(bodyNodeList.getLength()!=0){
Element root=(Element)bodyNodeList.item(0);
root.setAttribute("xmlns:ns", "YourURI");
root.setPrefix("ns");
}
}
}
}
}
}
return true;
}
}
I have a JiBX binding file that specifies namespaces. However, I want to turn off namespace validation so that even an XML message with invalid namespace could be unmarshalled.
I have a binding file like the following:
<binding name="test_binding">
<namespace prefix="soapenv" uri="http://www.w3.org/2003/05/soap-envelope" />
<!-- Envelope -->
<mapping name="Envelope" ns="http://www.w3.org/2003/05/soap-envelope"
class="com.test.data.Envelope">
<structure get-method="getHeader" set-method="setHeader"
ns="http://www.w3.org/2003/05/soap-envelope" usage="optional" />
<structure get-method="getBody" set-method="setBody"
ns="http://www.w3.org/2003/05/soap-envelope" usage="optional" />
</mapping>
...
I pass the following message to JiBX unmarshaller (with different namespace for Envelope element):
<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope">
<soapenv:Header>
<MyElement>
....
The following shows the error message when JiBX unmarshalls the message:
[Time:2011-10-04 17:39:29,802][Level:FATAL]org.jibx.runtime.JiBXException: No unmarshaller for element "{http://schemas.xmlsoap.org/soap/envelope}Envelope" (line 2, col 76)
...
Is there a way to disable namespace validation in JiBX? Thanks.