You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by fahman_dude <fa...@hotmail.com> on 2010/02/22 11:21:38 UTC

no-annotations RESTfull webservice - a complex use case

Hello,

I have the use case where I have to provide a RESTfull webservice. This use
case has a number of constraints:
- contract-first (as in, first - definition (WSDL for SOAP, user model for
REST), then - implementation (ws implementation and JAXB generated stuff))
- same webservice implementation class for both - SOAP and REST
- no manual modifications to the generated classes since they can be
re-generated at any time upon contract change
- REST service will be called by a simple httpclient
(commons-httpclient-3.1jar)

WSDL (trimmed) looks like this:
...
	<wsdl:types>
		<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
			targetNamespace="http://mynamespace"
			elementFormDefault="qualified" xmlns:msg="http://myothernamespace"
			xmlns:emailbus="http://mythirdnamespace">
			<xsd:import schemaLocation="myothernamespace.xsd"
namespace="http://myothernamespace" />
			<xsd:import schemaLocation="mythirdnamespace.xsd"
				namespace="http://mythirdnamespace" />
			<xsd:element name="sendEmail">
				<xsd:complexType>
					<xsd:sequence>
						<xsd:element name="msgCtx" type="msg:ServiceMessageContext"
							minOccurs="1" />
						<xsd:element name="emailMessage" type="emailbus:EmailMessage"
							minOccurs="1" />
					</xsd:sequence>
				</xsd:complexType>
			</xsd:element>
		</xsd:schema>
	</wsdl:types>

	<wsdl:message name="sendEmailIn">
		<wsdl:part element="tns:sendEmail" name="data" />
	</wsdl:message>
...

msgCtx (trimmed) looks like this:
<complexType name="ServiceMessageContext">
	<sequence>
		<element maxOccurs="1" minOccurs="1" name="messageId" type="string" />
		<element maxOccurs="1" minOccurs="0" name="requestId" type="string" />
		<element maxOccurs="1" minOccurs="0" name="correlationId" type="string" />
	</sequence>
</complexType>

emailMessage, like this:
<complexType name="EmailMessage">
	<sequence>
		<element name="from" type="xsd:string" />
		<element name="to" type="xsd:string" />
		<element name="subject" type="xsd:string" />
		<element name="body" type="tns:Body" />
		<element name="attachments" type="tns:Attachment" minOccurs="0"
maxOccurs="unbounded" />
	</sequence>
</complexType>
<complexType name="Body">
	<sequence>
		<element name="content" type="xsd:base64Binary"
xmime:expectedContentTypes="text/html" />
	</sequence>
</complexType>
<complexType name="Attachment">
	<sequence>
		<element name="content" type="xsd:base64Binary" />
	</sequence>
</complexType>

Webservice implementation has this single method:
public class EmailServiceImpl implements EmailService {
 public void sendEmail(ServiceMessageContext msgCtx, EmailMessage
emailMessage) {

Now, I can easily generate JAX-WS stuff first (wsdl2java). And it works just
fine (even with mtom and fastinfoset). But when it comes to JAX-RS I am
stuck.

My plan was to define user model and apply it to "EmailService" and
"EmailServiceImpl" like this:

<model xlmns="http://cxf.apache.org/jaxrs">
	<resource name="somepackages.EmailService" path="emailservice"
		produces="application/json" consumes="multipart/form-data">
		<operation name="sendEmail" verb="POST" path="/sendemail">
			&lt;param name="msgCtx" type="REQUEST_BODY" /&gt;
			&lt;param name="emailMessage" type="REQUEST_BODY" /&gt;
		</operation>
	</resource>
</model>

This worked aswell atleast to the point where I was able to succesfully
create a JAX-RS server based on the definition and classes.

Then, I intended to use HttpClient to perform a multipart post by means of
JAXB marshaling both parameters ("msgCtx" and "emailMessage"), attaching
them as Parts to MultipartRequestEntity and posting them over.

Currently I am facing a number of understanding issues even after weekend of
searching and reading on the web.

1. @XmlRootElement is neither "msgCtx" nor "emailMessage" but rather
wsdl2java-generated wrapper class "SendEmail". This kinda makes sense for
JAX-WS but I guess it will not work for JAX-RS (as I understand it, I have
to marshal "msgCtx" and "emailMessage" separatelly and add them to
MultipartRequestEntity as two separate Parts that can be identified later by
JAX-RS server). Can anyone enlighten me on what's wrong with my idea here or
is it really so that I have to configure JAXB so that it is able to marshall
"msgCtx" and "emailMessage" separatelly (I'd greatly appretiate, if anyone
could write me how to do that)

2. "emailMessage" alone consists of multiple parts - there's xml with
primitives, "body" which is xsd:base64Binary and the collection of
"attachments" each of which is xsd:base64Binary. Now, for JAX-WS CXF handles
and hides this complexity and I see a beautifull "multipart/related" message
on the wire. How do I achieve this for REST service? When I marshal instance
of "SendEmail" I see only one part with serialized SendEmail and all the
base64 stuff is inline. Again, can anyone give me a hint on what would be
the solution here that would actually work.

cheers
Reinis
-- 
View this message in context: http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27685209.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: no-annotations RESTfull webservice - a complex use case

Posted by Sergey Beryozkin <sb...@progress.com>.
Actually, you did send me the updated test project, I'm sorry :-). Just would like to finish some coding I'm doing right now and 
next is your issue which I will look at. The reason I'm asking for the message samples be posted is that I can try and reply 
immediately but I'll need to possibly stop what I'm doing at this moment of time, setup the project and verify, which I'm finding 
difficult if I'm really into some coding...

Just an idea : please verify that the @Multipart values match Content-Id values of the parts in your message. See, the reason it all 
works so seamlessly for you with JAXWS is that on the wire you have a single root part repesenting a complete XML fragment to be 
deserialized by JAXB with MTOM links to binary parts being inlined thus the CXF JAXWS runtime does not need a user to provide the 
hints like part names, etc. I'll give it a shot later on and see what would it take for CXF JAXRS to reuse MTOM interceptors, and if 
I manage to make it work then you'll be able to do the same with CXF JAXRS (but with no unwrapping of individual JAXB elemenst)

thanks, Sergey

----- Original Message ----- 
From: "Sergey Beryozkin" <sb...@progress.com>
To: <us...@cxf.apache.org>
Sent: Wednesday, February 24, 2010 3:00 PM
Subject: Re: no-annotations RESTfull webservice - a complex use case


Hi

Please see comments inline.

----- Original Message ----- 
From: "fahman_dude" <fa...@hotmail.com>
To: <us...@cxf.apache.org>
Sent: Wednesday, February 24, 2010 1:59 PM
Subject: Re: no-annotations RESTfull webservice - a complex use case



Hello,

we have moved the detailed discussion into private convo with Sergey, but
for the record or for those of you who might check thisthread later on, here
is an update:

I have implemented both of Sergeys suggestions but, alas, the parameter
mapping still does not work for me. What I did is this:

1. I am setting now the JAXBElementProvider for the JAXRSServer and setting
its UnmarshallAsJaxbElement property to true;

2. I manually added @Multipart("...") annotations to the parameters of the
JAXB generated Webservice interface;

3. I am creating now two Parts for msgCtx and emailMessage and posting them
over by means of httpclient.

S.B : any chance you can actually show how the message looks like on the wire ? See, the previous message your were sending was not
valid

Unfortunatelly I still get NullPointerException for parameters thus the
param-mapping does not work for me even with the @Multipart hack.

S.B : couple of comments here. First using @Multipart is not a hack - what makes you think it is the one ? You're about to have a
plain HTTP-based multipart request being processed.
Second, hope you realize the info you've provided does not give me a slightest clue what is happening ?
Please, give me the info. As I said, I'm committed to making things work for cases like the one you're working upon,
just haven't had a time to investigate yet.
By the way, just would like to clarify one thing : the issue we're dealing with has nothing to do with the
no-annotations feature. Rather, we're trying to make sure that the same service can have both SOAP-based and plain multipart
requests being processed and eventually the data being handled by JAXB such that the same signature can be reused. The steps 1-3
should lead to uncompressed muitparts being deserialized properly (no 1-3 steps will be required if you don't have the code with
unwrapped signatures generated). It won't work at the moment for MTOM-based parts and I may have a look into supporting MTOM too
given that it's not strictly speaking SOAP-based. Alternatively, building a proper multipart/form-data request would do but in this
case it is unlikely you'll be able to preserve the same signature

cheers, Sergey

cheers
Reinis


Sergey Beryozkin-2 wrote:
>
> <snip/>
> S.B : ok, thanks... So ServiceMessageContext and EmailMessage are just
> @XmlType(s)...See, JAXRS does not really like multiple
> request parameters referring to request bodies (as in sendEmail) thus CXF
> JAXRS does not unwrap the way CXF JAXWS does (which is
> very JAXWS compliant) but here we're dealing with a multipart  request so
> even thought it is not standardized in JAXRS, it makes
> sense to refer to individual parts through the use of multiple parameters.
> But the problem is that ServiceMessageContext and
> EmailMessage have no @XmlRootElement - I think you can just register a
> JAXRS JAXBElementProvider and set an 'unmarshalAsJaxbElement'
> property on it and it should fix the JAXB-related issue...
> <snip/>
> S.B. Next, given that CXF JAXRS does not unwrap (well, at the moment at
> least), one needs to 'attach' @Multipart annotations to
> individual method parameters for the MultipartProvider to figure out which
> part needs be deserialized. Given that you've chosen to
> use a user model this may seem like a step back but lets just make it work
> and then I can look at extending the model support... So
> now we have :
>
> sendEmail(@Multipart("context") ServiceMessageContext ctx,
> @Multipart("email")  EmailMessage message)
> <snip/>
> S.B : In meantime, please ensure you have two parts, the above fragment
> just uses a single part but a real multipart/form-data
> would have one part containing a service context, the other one containing
> the body with this second body part containing
> embedded/recursive parts, one per every email attachment. You probably
> just do not need this kind of complexity (yet), just create a
> multipart/mixed or may be multipart/related (and update @Produces) request
> containing two parts, one will 'hold' the context another
> one an email message including the binary content.
> <snip/>
> View this message in context:
> http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27686868.html
> Sent from the cxf-user mailing list archive at Nabble.com.
>
-- 
View this message in context: http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27714207.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: no-annotations RESTfull webservice - a complex use case

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi

Please see comments inline.

----- Original Message ----- 
From: "fahman_dude" <fa...@hotmail.com>
To: <us...@cxf.apache.org>
Sent: Wednesday, February 24, 2010 1:59 PM
Subject: Re: no-annotations RESTfull webservice - a complex use case



Hello,

we have moved the detailed discussion into private convo with Sergey, but
for the record or for those of you who might check thisthread later on, here
is an update:

I have implemented both of Sergeys suggestions but, alas, the parameter
mapping still does not work for me. What I did is this:

1. I am setting now the JAXBElementProvider for the JAXRSServer and setting
its UnmarshallAsJaxbElement property to true;

2. I manually added @Multipart("...") annotations to the parameters of the
JAXB generated Webservice interface;

3. I am creating now two Parts for msgCtx and emailMessage and posting them
over by means of httpclient.

S.B : any chance you can actually show how the message looks like on the wire ? See, the previous message your were sending was not 
valid

Unfortunatelly I still get NullPointerException for parameters thus the
param-mapping does not work for me even with the @Multipart hack.

S.B : couple of comments here. First using @Multipart is not a hack - what makes you think it is the one ? You're about to have a 
plain HTTP-based multipart request being processed.
Second, hope you realize the info you've provided does not give me a slightest clue what is happening ?
Please, give me the info. As I said, I'm committed to making things work for cases like the one you're working upon,
just haven't had a time to investigate yet.
By the way, just would like to clarify one thing : the issue we're dealing with has nothing to do with the
no-annotations feature. Rather, we're trying to make sure that the same service can have both SOAP-based and plain multipart 
requests being processed and eventually the data being handled by JAXB such that the same signature can be reused. The steps 1-3 
should lead to uncompressed muitparts being deserialized properly (no 1-3 steps will be required if you don't have the code with 
unwrapped signatures generated). It won't work at the moment for MTOM-based parts and I may have a look into supporting MTOM too 
given that it's not strictly speaking SOAP-based. Alternatively, building a proper multipart/form-data request would do but in this 
case it is unlikely you'll be able to preserve the same signature

cheers, Sergey

cheers
Reinis


Sergey Beryozkin-2 wrote:
>
> <snip/>
> S.B : ok, thanks... So ServiceMessageContext and EmailMessage are just
> @XmlType(s)...See, JAXRS does not really like multiple
> request parameters referring to request bodies (as in sendEmail) thus CXF
> JAXRS does not unwrap the way CXF JAXWS does (which is
> very JAXWS compliant) but here we're dealing with a multipart  request so
> even thought it is not standardized in JAXRS, it makes
> sense to refer to individual parts through the use of multiple parameters.
> But the problem is that ServiceMessageContext and
> EmailMessage have no @XmlRootElement - I think you can just register a
> JAXRS JAXBElementProvider and set an 'unmarshalAsJaxbElement'
> property on it and it should fix the JAXB-related issue...
> <snip/>
> S.B. Next, given that CXF JAXRS does not unwrap (well, at the moment at
> least), one needs to 'attach' @Multipart annotations to
> individual method parameters for the MultipartProvider to figure out which
> part needs be deserialized. Given that you've chosen to
> use a user model this may seem like a step back but lets just make it work
> and then I can look at extending the model support... So
> now we have :
>
> sendEmail(@Multipart("context") ServiceMessageContext ctx,
> @Multipart("email")  EmailMessage message)
> <snip/>
> S.B : In meantime, please ensure you have two parts, the above fragment
> just uses a single part but a real multipart/form-data
> would have one part containing a service context, the other one containing
> the body with this second body part containing
> embedded/recursive parts, one per every email attachment. You probably
> just do not need this kind of complexity (yet), just create a
> multipart/mixed or may be multipart/related (and update @Produces) request
> containing two parts, one will 'hold' the context another
> one an email message including the binary content.
> <snip/>
> View this message in context:
> http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27686868.html
> Sent from the cxf-user mailing list archive at Nabble.com.
>
-- 
View this message in context: http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27714207.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: no-annotations RESTfull webservice - a complex use case

Posted by fahman_dude <fa...@hotmail.com>.
Hello,

we have moved the detailed discussion into private convo with Sergey, but
for the record or for those of you who might check thisthread later on, here
is an update:

I have implemented both of Sergeys suggestions but, alas, the parameter
mapping still does not work for me. What I did is this:

1. I am setting now the JAXBElementProvider for the JAXRSServer and setting
its UnmarshallAsJaxbElement property to true;

2. I manually added @Multipart("...") annotations to the parameters of the
JAXB generated Webservice interface;

3. I am creating now two Parts for msgCtx and emailMessage and posting them
over by means of httpclient.

Unfortunatelly I still get NullPointerException for parameters thus the
param-mapping does not work for me even with the @Multipart hack.

cheers
Reinis


Sergey Beryozkin-2 wrote:
> 
> <snip/>
> S.B : ok, thanks... So ServiceMessageContext and EmailMessage are just
> @XmlType(s)...See, JAXRS does not really like multiple 
> request parameters referring to request bodies (as in sendEmail) thus CXF
> JAXRS does not unwrap the way CXF JAXWS does (which is 
> very JAXWS compliant) but here we're dealing with a multipart  request so
> even thought it is not standardized in JAXRS, it makes 
> sense to refer to individual parts through the use of multiple parameters.
> But the problem is that ServiceMessageContext and 
> EmailMessage have no @XmlRootElement - I think you can just register a
> JAXRS JAXBElementProvider and set an 'unmarshalAsJaxbElement' 
> property on it and it should fix the JAXB-related issue...
> <snip/>
> S.B. Next, given that CXF JAXRS does not unwrap (well, at the moment at
> least), one needs to 'attach' @Multipart annotations to 
> individual method parameters for the MultipartProvider to figure out which
> part needs be deserialized. Given that you've chosen to 
> use a user model this may seem like a step back but lets just make it work
> and then I can look at extending the model support... So 
> now we have :
> 
> sendEmail(@Multipart("context") ServiceMessageContext ctx,
> @Multipart("email")  EmailMessage message)
> <snip/>
> S.B : In meantime, please ensure you have two parts, the above fragment  
> just uses a single part but a real multipart/form-data 
> would have one part containing a service context, the other one containing
> the body with this second body part containing 
> embedded/recursive parts, one per every email attachment. You probably
> just do not need this kind of complexity (yet), just create a 
> multipart/mixed or may be multipart/related (and update @Produces) request
> containing two parts, one will 'hold' the context another 
> one an email message including the binary content.
> <snip/>
> View this message in context:
> http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27686868.html
> Sent from the cxf-user mailing list archive at Nabble.com.
> 
-- 
View this message in context: http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27714207.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: no-annotations RESTfull webservice - a complex use case

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi Reinis

<snip/>

>
>> S.B I'm a little bit confused here. What is the value of
>> ServiceMessageContext and EmailMessage' XmlRootElements ? As far as I
>
>>> Reinis: I am afraid I do not understand your question.
>>> "ServiceMessageContext" and "EmailMessage"
>>> have no @XmlRootElement annotation instead, they are, as you correctly
>>> mention bellow, wraped in
>>> "SendEmail" wrapper and anotated there. (I can not change this since
>>> they all - "ServiceMess...",
>>> "EmailMessage" and "SendEmail" are generated by JAXB) "SendEmail" looks
>>> ike this:
>
>>> @XmlAccessorType(XmlAccessType.FIELD)
>>> @XmlType(name = "", propOrder = {
>>>     "msgCtx",
>>>     "emailMessage"
>>> })
>>> @XmlRootElement(name = "sendEmail")
>>> public class SendEmail {
>>>
>>>     @XmlElement(required = true)
>>>     protected ServiceMessageContext msgCtx;
>>>     @XmlElement(required = true)
>>>     protected EmailMessage emailMessage;
>>>  ...

S.B : ok, thanks... So ServiceMessageContext and EmailMessage are just @XmlType(s)...See, JAXRS does not really like multiple 
request parameters referring to request bodies (as in sendEmail) thus CXF JAXRS does not unwrap the way CXF JAXWS does (which is 
very JAXWS compliant) but here we're dealing with a multipart  request so even thought it is not standardized in JAXRS, it makes 
sense to refer to individual parts through the use of multiple parameters. But the problem is that ServiceMessageContext and 
EmailMessage have no @XmlRootElement - I think you can just register a JAXRS JAXBElementProvider and set an 'unmarshalAsJaxbElement' 
property on it and it should fix the JAXB-related issue...

S.B. Next, given that CXF JAXRS does not unwrap (well, at the moment at least), one needs to 'attach' @Multipart annotations to 
individual method parameters for the MultipartProvider to figure out which part needs be deserialized. Given that you've chosen to 
use a user model this may seem like a step back but lets just make it work and then I can look at extending the model support... So 
now we have :

sendEmail(@Multipart("context") ServiceMessageContext ctx, @Multipart("email")  EmailMessage message)

where "context" refers to the first part and "email" contains the other one

Reinis, can you give me a favor and also send me generated ServiceMessageContext & EmailMessage ? I'll do a quick test and see what 
needs to be done to ensure JAXBElementProvider can also handle the binary content...I'll let you know then and you'll be able to 
register a custom JAXBWElementProvider.

S.B : Now, if you had just a wrapper SendEmail parameter (perhaps named as EmailRequest instead) then it woull things easier to deal 
with for a number of reasons, you'd definitely not have to register a custom JAXBProvider as suggested above...Perhaps you might 
want to consider running wsdl2java in a mode which produces methods with wrapped signatures ?
.
> If you could attach a sample request message which you're sending with the
> http client (plus the generated ServiceMessageContext and
> EmailMessage) then it could help as well, I may be able to do some testing
> on my side...
>
>>> Reinis: Yes, that is my aim, to send two (or more) individual parts but
>>> apparently I am failing at it
>>> since I have no elegant solution that would keep the three generated
>>> classes without modifications (if
>>> I could change generated classes, I would, for example, add JAXB
>>> annotations to
>>> ServiceMessageContext and EmailMessage and marshal them separatelly). At
>>> the moment I am
>>> marshalling "SendEmail" and wrapping it into "FilePart" which I know is
>>> wrong.
>
>>> PostMethod post = new
>>> PostMethod("http://localhost:9080/emailservice/sendemail");
>>>
>>> //set accept header
>>> post.addRequestHeader("Accept", "application/json");
>>>
>>> ObjectFactory objectFactory = new ObjectFactory();
>>> SendEmail sendEmail = objectFactory.createSendEmail();
>>>
>>> sendEmail.setMsgCtx(EmailBUSTestUtil.generateTestServiceMessageContext());
>>> sendEmail.setEmailMessage(EmailBUSTestUtil.generateTestEmailMessage());
>>>
>>> JAXBContext context = JAXBContext.newInstance(SendEmail.class);
>>> Marshaller m = context.createMarshaller();
>>>
>>> File file = new File(UUID.randomUUID().toString());
>>> FileOutputStream out = new FileOutputStream(file);
>>>
>>> m.marshal(sendEmail, out);
>>>
>>> FilePart sendEmailPart = new FilePart("sendEmail", file);
>>>
>>> //an multipart request entity is required for the e-mail
>>> RequestEntity requestEntity
>>>    = new MultipartRequestEntity(new Part[]{ sendEmailPart },
>>> post.getParams());
>>> post.setRequestEntity(requestEntity);
>>> ...
>>> int result = httpClient.executeMethod(post);
>>> ...
>
>>> Reinis: This produce message on the wire that is not usable (since it
>>> has only one part) and thus,
>>> I am guessing, is  not correctly matched to parameters of the webmethod.
>>> Sergey, apparently I am
>>> confusing you because you may think that I have a more or less clear
>>> idea about how to implement
>>> this, but really, I am just trying things out since I am very new to the
>>> JAX-RS stuff and simply do not
>>> understand how it should work.

S.B : No problems. Thanks for experimenting - we'll get it done/fixed. More comments below...

>>> Please find bellow message from the wire and some other log messages
>>> indicating that JAX-RS server
>>> is able to match resource
>
>>> LoggingInInterceptor (164)     - Inbound Message
>>> ----------------------------
>>> ID: 1
>>> Address: /emailservice/sendemail
>>> Encoding: ISO-8859-1
>>> Content-Type: multipart/form-data;
>>> boundary=tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy
>>> Headers: {content-type=[multipart/form-data;
>>> boundary=tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy], Host=[localhost:9080],
>>> Content-Length=
>>> [1928693], User-Agent=[Jakarta Commons-HttpClient/3.1],
>>> Content-Type=[multipart/form-data;
>>> boundary=tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy],
>>> Accept=[application/json]}
>>> Messages:
>>> Message (saved to tmp file):
>>> Filename: C:\Temp\cxf-tmp-655593\cos15008tmp
>>> (message truncated to 102400 bytes)
>>>
>>> Payload: --tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy
>>> Content-Disposition: form-data; name="sendEmail";
>>> filename="fd90d28f-0b55-4d3a-
>>> 84dc-d9f894be3e80"
>>> Content-Type: application/octet-stream; charset=ISO-8859-1
>>> Content-Transfer-Encoding: binary
>>>
>>> <?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:sendEmail
>>> xmlns="http://..."
>>> xmlns:ns2="http://..." xmlns:ns3="http://..."><ns2:msgCtx><to>Test
>>> Server</to><from>Test
>>> Client</from><messageId>Test1</messageId><correlationId>UUID-
>>> 234234-234324-6456-4643</correlationId><priority>1</priority><senderVersion>1.0</senderVersion>
>>> <receiverVersion>1.0</receiverVersion></ns2:msgCtx><ns2:emailMessage><ns3:from>testclient@...
>>> </ns3:from><ns3:to>testserver@.</ns3:to><ns3:body>
>>> <ns3:content>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NU...</ns3:content>
>>> </ns3:body><ns3:attachments>
>>> <ns3:content>Qk02+RUAAAAAADYAAAAoAAAAIAMAAFgCAAABABgAAAAAAAAAAADED...</ns3:content>
>>> </ns3:attachments></ns2:emailMessage>


S.B : Indeed, it won't work for a number of reasons. Note that if you had just sendEmail(SendEmail) (or rather 
sendEmail(EmailRequest)) then it would probably work (but as I said I'll need to test and check if JAXBElementProvider needs to be 
enhanced a bit).

S.B : In meantime, please ensure you have two parts, the above fragment   just uses a single part but a real multipart/form-data 
would have one part containing a service context, the other one containing the body with this second body part containing 
embedded/recursive parts, one per every email attachment. You probably just do not need this kind of complexity (yet), just create a 
multipart/mixed or may be multipart/related (and update @Produces) request containing two parts, one will 'hold' the context another 
one an email message including the binary content.

S.B : If you didn't have to use JAXB to unmarshal emailMessage then we would have more options like :
sendEmail(Body emailBody, List<Attachment> attachments), etc...But I'd like to ensure JAXBElementProvider is also capable of dealing 
with such requests. So, to summarize, please send me ServiceContextImpl and EmailExchnage and resend the above request with all the 
namespaces in place so that I could just use it in test (sample namespaces will do fine)

thanks, Sergey

>>> --------------------------------------
>>> PhaseInterceptorChain (240)     - Invoking handleMessage on interceptor
>>> org.apache.cxf.transport.https.CertConstraintsInterceptor@194ba17
>>> PhaseInterceptorChain (240)     - Invoking handleMessage on interceptor
>>> org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor@128594c
>>> JAXRSUtils (223)     - Trying to select a resource class
>>> /emailservice/sendemail, request path : {1}

S.B: will get this {1} fixed...It might be fixed in 2.2.6 ?

>>> JAXRSUtils (279)     - Trying to select a resource operation on the
>>> resource class somepackages.EmailService
>>> JAXRSUtils (332)     - Resource operation sendEmail may get selected
>>> JAXRSUtils (355)     - Resource operation sendEmail on the resource
>>> class somepackages.EmailService has been selected
>>> JAXRSInInterceptor (219)     - Request path is: /emailservice/sendemail
>>> JAXRSInInterceptor (220)     - Request HTTP method is: POST
>>> JAXRSInInterceptor (221)     - Request contentType is:
>>> multipart/form-data; boundary=tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy
>>> JAXRSInInterceptor (222)     - Accept contentType is: application/json
>>> JAXRSInInterceptor (224)     - Found operation: sendEmail
>>> ...
>
> --
> View this message in context:
> http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27685209.html
> Sent from the cxf-user mailing list archive at Nabble.com.
>

cheers
Reinis
--
View this message in context: http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27686868.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: no-annotations RESTfull webservice - a complex use case

Posted by fahman_dude <fa...@hotmail.com>.
Hello,

I aswell added comments inline (see bellow)


Sergey Beryozkin-2 wrote:
> 
> 
> I have the use case where I have to provide a RESTfull webservice. This
> use
> case has a number of constraints:
> - contract-first (as in, first - definition (WSDL for SOAP, user model for
> REST), then - implementation (ws implementation and JAXB generated stuff))
> - same webservice implementation class for both - SOAP and REST
> 
>> S.B : I'm wondering, should we start thinking about supporting WSDL2 for
>> cases like this one be supported ?
> 
>>> reinis: For my use case it would be very welcome. Basically, any
>>> SOA-like (governance)process 
>>> attempts to push "contract-first". I could imagine a reasonable number
>>> of commercial projects where 
>>> this would be greatly appretiated aswell.
> 
> WSDL (trimmed) looks like this:
> ...
> <wsdl:types>
> <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
> targetNamespace="http://mynamespace"
> elementFormDefault="qualified" xmlns:msg="http://myothernamespace"
> xmlns:emailbus="http://mythirdnamespace">
> <xsd:import schemaLocation="myothernamespace.xsd"
> namespace="http://myothernamespace" />
> <xsd:import schemaLocation="mythirdnamespace.xsd"
> namespace="http://mythirdnamespace" />
> <xsd:element name="sendEmail">
> <xsd:complexType>
> <xsd:sequence>
> <xsd:element name="msgCtx" type="msg:ServiceMessageContext"
> minOccurs="1" />
> <xsd:element name="emailMessage" type="emailbus:EmailMessage"
> minOccurs="1" />
> </xsd:sequence>
> </xsd:complexType>
> </xsd:element>
> </xsd:schema>
> </wsdl:types>
> 
> <wsdl:message name="sendEmailIn">
> <wsdl:part element="tns:sendEmail" name="data" />
> </wsdl:message>
> ...
> 
> msgCtx (trimmed) looks like this:
> <complexType name="ServiceMessageContext">
> <sequence>
> <element maxOccurs="1" minOccurs="1" name="messageId" type="string" />
> <element maxOccurs="1" minOccurs="0" name="requestId" type="string" />
> <element maxOccurs="1" minOccurs="0" name="correlationId" type="string" />
> </sequence>
> </complexType>
> 
> emailMessage, like this:
> <complexType name="EmailMessage">
> <sequence>
> <element name="from" type="xsd:string" />
> <element name="to" type="xsd:string" />
> <element name="subject" type="xsd:string" />
> <element name="body" type="tns:Body" />
> <element name="attachments" type="tns:Attachment" minOccurs="0"
> maxOccurs="unbounded" />
> </sequence>
> </complexType>
> <complexType name="Body">
> <sequence>
> <element name="content" type="xsd:base64Binary"
> xmime:expectedContentTypes="text/html" />
> </sequence>
> </complexType>
> <complexType name="Attachment">
> <sequence>
> <element name="content" type="xsd:base64Binary" />
> </sequence>
> </complexType>
> 
> Webservice implementation has this single method:
> public class EmailServiceImpl implements EmailService {
>  public void sendEmail(ServiceMessageContext msgCtx, EmailMessage
> emailMessage) {
> 
> My plan was to define user model and apply it to "EmailService" and
> "EmailServiceImpl" like this:
> 
> <model xlmns="http://cxf.apache.org/jaxrs">
> <resource name="somepackages.EmailService" path="emailservice"
> produces="application/json" consumes="multipart/form-data">
> <operation name="sendEmail" verb="POST" path="/sendemail">
> &lt;param name="msgCtx" type="REQUEST_BODY" /&gt;
> &lt;param name="emailMessage" type="REQUEST_BODY" /&gt;
> </operation>
> </resource>
> </model>
> 
> This worked aswell atleast to the point where I was able to succesfully
> create a JAX-RS server based on the definition and classes.
> 
> Then, I intended to use HttpClient to perform a multipart post by means of
> JAXB marshaling both parameters ("msgCtx" and "emailMessage"), attaching
> them as Parts to MultipartRequestEntity and posting them over.
> 
>> S.B Note that it is very easy to post attachments with CXF JAXRS on the
>> client side too, the only thing which has not been 
>> impemented yet is the recursive multiparts (that is, when individual
>> multipart/form-data parts contains multiple parts of its own) 
>> but this works on the server.
> 
>>> Reinis: I believe that in my application, e.g. emailMessage contains
>>> parts of its own (body and attachments collection that are parts of own)
> 
> Currently I am facing a number of understanding issues even after weekend
> of
> searching and reading on the web.
> 
> 1. @XmlRootElement is neither "msgCtx" nor "emailMessage" but rather
> wsdl2java-generated wrapper class "SendEmail". This kinda makes sense for
> JAX-WS but I guess it will not work for JAX-RS (as I understand it, I have
> to marshal "msgCtx" and "emailMessage" separatelly and add them to
> MultipartRequestEntity as two separate Parts that can be identified later
> by
> JAX-RS server). Can anyone enlighten me on what's wrong with my idea here
> or
> is it really so that I have to configure JAXB so that it is able to
> marshall
> "msgCtx" and "emailMessage" separatelly (I'd greatly appretiate, if anyone
> could write me how to do that)
> 
>> S.B I'm a little bit confused here. What is the value of 
>> ServiceMessageContext and EmailMessage' XmlRootElements ? As far as I
> 
>>> Reinis: I am afraid I do not understand your question.
>>> "ServiceMessageContext" and "EmailMessage" 
>>> have no @XmlRootElement annotation instead, they are, as you correctly
>>> mention bellow, wraped in 
>>> "SendEmail" wrapper and anotated there. (I can not change this since
>>> they all - "ServiceMess...", 
>>> "EmailMessage" and "SendEmail" are generated by JAXB) "SendEmail" looks
>>> ike this:
> 
>>> @XmlAccessorType(XmlAccessType.FIELD)
>>> @XmlType(name = "", propOrder = {
>>>     "msgCtx",
>>>     "emailMessage"
>>> })
>>> @XmlRootElement(name = "sendEmail")
>>> public class SendEmail {
>>> 
>>>     @XmlElement(required = true)
>>>     protected ServiceMessageContext msgCtx;
>>>     @XmlElement(required = true)
>>>     protected EmailMessage emailMessage;
>>>  ...
> 
>> understand, there's a single SendEmail wrapper instance which is being
>> sent in case of SOAP and it is unwrapped at the server side 
>> into two individual parts, msgCtx and emailMessage. But in case of JAXRS
>> you're sending a multipart/form-data request, with one 
>> part containing the ServiceMessageContext instance and the other part
>> containing an email itself...
> If you could attach a sample request message which you're sending with the
> http client (plus the generated ServiceMessageContext and 
> EmailMessage) then it could help as well, I may be able to do some testing
> on my side...
> 
>>> Reinis: Yes, that is my aim, to send two (or more) individual parts but
>>> apparently I am failing at it 
>>> since I have no elegant solution that would keep the three generated
>>> classes without modifications (if 
>>> I could change generated classes, I would, for example, add JAXB
>>> annotations to 
>>> ServiceMessageContext and EmailMessage and marshal them separatelly). At
>>> the moment I am 
>>> marshalling "SendEmail" and wrapping it into "FilePart" which I know is
>>> wrong.
> 
>>> PostMethod post = new
>>> PostMethod("http://localhost:9080/emailservice/sendemail");
>>>
>>> //set accept header
>>> post.addRequestHeader("Accept", "application/json");
>>>
>>> ObjectFactory objectFactory = new ObjectFactory();
>>> SendEmail sendEmail = objectFactory.createSendEmail();
>>>		
>>> sendEmail.setMsgCtx(EmailBUSTestUtil.generateTestServiceMessageContext());
>>> sendEmail.setEmailMessage(EmailBUSTestUtil.generateTestEmailMessage());
>>>
>>> JAXBContext context = JAXBContext.newInstance(SendEmail.class);
>>> Marshaller m = context.createMarshaller();
>>>		
>>> File file = new File(UUID.randomUUID().toString());	    
>>> FileOutputStream out = new FileOutputStream(file);
>>>
>>> m.marshal(sendEmail, out);
>>>	    
>>> FilePart sendEmailPart = new FilePart("sendEmail", file);
>>>
>>> //an multipart request entity is required for the e-mail
>>> RequestEntity requestEntity
>>>    = new MultipartRequestEntity(new Part[]{ sendEmailPart },
>>> post.getParams());
>>> post.setRequestEntity(requestEntity);
>>> ...
>>> int result = httpClient.executeMethod(post);
>>> ...
> 
>>> Reinis: This produce message on the wire that is not usable (since it
>>> has only one part) and thus,
>>> I am guessing, is  not correctly matched to parameters of the webmethod.
>>> Sergey, apparently I am 
>>> confusing you because you may think that I have a more or less clear
>>> idea about how to implement 
>>> this, but really, I am just trying things out since I am very new to the
>>> JAX-RS stuff and simply do not 
>>> understand how it should work.
>>> Please find bellow message from the wire and some other log messages
>>> indicating that JAX-RS server
>>> is able to match resource
> 
>>> LoggingInInterceptor (164)     - Inbound Message
>>> ----------------------------
>>> ID: 1
>>> Address: /emailservice/sendemail
>>> Encoding: ISO-8859-1
>>> Content-Type: multipart/form-data;
>>> boundary=tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy
>>> Headers: {content-type=[multipart/form-data;
>>> boundary=tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy], Host=[localhost:9080],
>>> Content-Length=
>>> [1928693], User-Agent=[Jakarta Commons-HttpClient/3.1],
>>> Content-Type=[multipart/form-data; 
>>> boundary=tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy],
>>> Accept=[application/json]}
>>> Messages: 
>>> Message (saved to tmp file):
>>> Filename: C:\Temp\cxf-tmp-655593\cos15008tmp
>>> (message truncated to 102400 bytes)
>>> 
>>> Payload: --tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy
>>> Content-Disposition: form-data; name="sendEmail";
>>> filename="fd90d28f-0b55-4d3a-
>>> 84dc-d9f894be3e80"
>>> Content-Type: application/octet-stream; charset=ISO-8859-1
>>> Content-Transfer-Encoding: binary
>>> 
>>> <?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:sendEmail
>>> xmlns="http://..."
>>> xmlns:ns2="http://..." xmlns:ns3="http://..."><ns2:msgCtx><to>Test
>>> Server</to><from>Test 
>>> Client</from><messageId>Test1</messageId><correlationId>UUID-
>>> 234234-234324-6456-4643</correlationId><priority>1</priority><senderVersion>1.0</senderVersion>
>>> <receiverVersion>1.0</receiverVersion></ns2:msgCtx><ns2:emailMessage><ns3:from>testclient@...
>>> </ns3:from><ns3:to>testserver@.</ns3:to><ns3:body>
>>> <ns3:content>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NU...</ns3:content>
>>> </ns3:body><ns3:attachments>
>>> <ns3:content>Qk02+RUAAAAAADYAAAAoAAAAIAMAAFgCAAABABgAAAAAAAAAAADED...</ns3:content>
>>> </ns3:attachments></ns2:emailMessage>
>>> --------------------------------------
>>> PhaseInterceptorChain (240)     - Invoking handleMessage on interceptor
>>> org.apache.cxf.transport.https.CertConstraintsInterceptor@194ba17
>>> PhaseInterceptorChain (240)     - Invoking handleMessage on interceptor
>>> org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor@128594c
>>> JAXRSUtils (223)     - Trying to select a resource class
>>> /emailservice/sendemail, request path : {1}
>>> JAXRSUtils (279)     - Trying to select a resource operation on the
>>> resource class somepackages.EmailService
>>> JAXRSUtils (332)     - Resource operation sendEmail may get selected
>>> JAXRSUtils (355)     - Resource operation sendEmail on the resource
>>> class somepackages.EmailService has been selected
>>> JAXRSInInterceptor (219)     - Request path is: /emailservice/sendemail
>>> JAXRSInInterceptor (220)     - Request HTTP method is: POST
>>> JAXRSInInterceptor (221)     - Request contentType is:
>>> multipart/form-data; boundary=tgH6XEjCAXXdvx4VtuCkPq1LuT_YwGGRGByuGy
>>> JAXRSInInterceptor (222)     - Accept contentType is: application/json
>>> JAXRSInInterceptor (224)     - Found operation: sendEmail
>>> ...
> 
> -- 
> View this message in context:
> http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27685209.html
> Sent from the cxf-user mailing list archive at Nabble.com.
> 

cheers
Reinis
-- 
View this message in context: http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27686868.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: no-annotations RESTfull webservice - a complex use case

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi

See comments inline please

----- Original Message ----- 
From: "fahman_dude" <fa...@hotmail.com>
To: <us...@cxf.apache.org>
Sent: Monday, February 22, 2010 10:21 AM
Subject: no-annotations RESTfull webservice - a complex use case



Hello,

I have the use case where I have to provide a RESTfull webservice. This use
case has a number of constraints:
- contract-first (as in, first - definition (WSDL for SOAP, user model for
REST), then - implementation (ws implementation and JAXB generated stuff))
- same webservice implementation class for both - SOAP and REST

> S.B : I'm wondering, should we start thinking about supporting WSDL2 for cases like this one be supported ?

- no manual modifications to the generated classes since they can be
re-generated at any time upon contract change
- REST service will be called by a simple httpclient
(commons-httpclient-3.1jar)

WSDL (trimmed) looks like this:
...
<wsdl:types>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://mynamespace"
elementFormDefault="qualified" xmlns:msg="http://myothernamespace"
xmlns:emailbus="http://mythirdnamespace">
<xsd:import schemaLocation="myothernamespace.xsd"
namespace="http://myothernamespace" />
<xsd:import schemaLocation="mythirdnamespace.xsd"
namespace="http://mythirdnamespace" />
<xsd:element name="sendEmail">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="msgCtx" type="msg:ServiceMessageContext"
minOccurs="1" />
<xsd:element name="emailMessage" type="emailbus:EmailMessage"
minOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>

<wsdl:message name="sendEmailIn">
<wsdl:part element="tns:sendEmail" name="data" />
</wsdl:message>
...

msgCtx (trimmed) looks like this:
<complexType name="ServiceMessageContext">
<sequence>
<element maxOccurs="1" minOccurs="1" name="messageId" type="string" />
<element maxOccurs="1" minOccurs="0" name="requestId" type="string" />
<element maxOccurs="1" minOccurs="0" name="correlationId" type="string" />
</sequence>
</complexType>

emailMessage, like this:
<complexType name="EmailMessage">
<sequence>
<element name="from" type="xsd:string" />
<element name="to" type="xsd:string" />
<element name="subject" type="xsd:string" />
<element name="body" type="tns:Body" />
<element name="attachments" type="tns:Attachment" minOccurs="0"
maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="Body">
<sequence>
<element name="content" type="xsd:base64Binary"
xmime:expectedContentTypes="text/html" />
</sequence>
</complexType>
<complexType name="Attachment">
<sequence>
<element name="content" type="xsd:base64Binary" />
</sequence>
</complexType>

Webservice implementation has this single method:
public class EmailServiceImpl implements EmailService {
 public void sendEmail(ServiceMessageContext msgCtx, EmailMessage
emailMessage) {

Now, I can easily generate JAX-WS stuff first (wsdl2java). And it works just
fine (even with mtom and fastinfoset). But when it comes to JAX-RS I am
stuck.

My plan was to define user model and apply it to "EmailService" and
"EmailServiceImpl" like this:

<model xlmns="http://cxf.apache.org/jaxrs">
<resource name="somepackages.EmailService" path="emailservice"
produces="application/json" consumes="multipart/form-data">
<operation name="sendEmail" verb="POST" path="/sendemail">
&lt;param name="msgCtx" type="REQUEST_BODY" /&gt;
&lt;param name="emailMessage" type="REQUEST_BODY" /&gt;
</operation>
</resource>
</model>

This worked aswell atleast to the point where I was able to succesfully
create a JAX-RS server based on the definition and classes.

Then, I intended to use HttpClient to perform a multipart post by means of
JAXB marshaling both parameters ("msgCtx" and "emailMessage"), attaching
them as Parts to MultipartRequestEntity and posting them over.

> S.B Note that it is very easy to post attachments with CXF JAXRS on the client side too, the only thing which has not been 
> impemented yet is the recursive multiparts (that is, when individual multipart/form-data parts contains multiple parts of its own) 
> but this works on the server.

Currently I am facing a number of understanding issues even after weekend of
searching and reading on the web.

1. @XmlRootElement is neither "msgCtx" nor "emailMessage" but rather
wsdl2java-generated wrapper class "SendEmail". This kinda makes sense for
JAX-WS but I guess it will not work for JAX-RS (as I understand it, I have
to marshal "msgCtx" and "emailMessage" separatelly and add them to
MultipartRequestEntity as two separate Parts that can be identified later by
JAX-RS server). Can anyone enlighten me on what's wrong with my idea here or
is it really so that I have to configure JAXB so that it is able to marshall
"msgCtx" and "emailMessage" separatelly (I'd greatly appretiate, if anyone
could write me how to do that)

> S.B I'm a little bit confused here. What is the value of  ServiceMessageContext and EmailMessage' XmlRootElements ? As far as I 
> understand, there's a single SendEmail wrapper instance which is being sent in case of SOAP and it is unwrapped at the server side 
> into two individual parts, msgCtx and emailMessage. But in case of JAXRS you're sending a multipart/form-data request, with one 
> part containing the ServiceMessageContext instance and the other part containing an email itself...
If you could attach a sample request message which you're sending with the http client (plus the generated ServiceMessageContext and 
EmailMessage) then it could help as well, I may be able to do some testing on my side...

2. "emailMessage" alone consists of multiple parts - there's xml with
primitives, "body" which is xsd:base64Binary and the collection of
"attachments" each of which is xsd:base64Binary. Now, for JAX-WS CXF handles
and hides this complexity and I see a beautifull "multipart/related" message
on the wire. How do I achieve this for REST service? When I marshal instance
of "SendEmail" I see only one part with serialized SendEmail and all the
base64 stuff is inline. Again, can anyone give me a hint on what would be
the solution here that would actually work.

> S.B I'd like to have a look at the sample multipart/form-data request message.
cheers, Sergey

cheers
Reinis
-- 
View this message in context: http://old.nabble.com/no-annotations-RESTfull-webservice---a-complex-use-case-tp27685209p27685209.html
Sent from the cxf-user mailing list archive at Nabble.com.