cxf-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Sergey Beryozkin <>
Subject Re: no-annotations RESTfull webservice - a complex use case
Date Mon, 22 Feb 2010 15:38:24 GMT
Hi Reinis


>> 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

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: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:
> Sent from the cxf-user mailing list archive at

View this message in context:
Sent from the cxf-user mailing list archive at

View raw message