Apache CXF different ClassLoader Issue - soap

I'm building a SOAP WebService.
In this SOAP Webservice, I want to save the XML request to a file.
To do so, I know I can simply use a chain handler, however, I need other infos that aren't transmitted in the request itself, but rather calculated in the WebService, wich is why I feel like I should retreive the MessageContext in my WebService.
Hopefully, I can use #Resource to get the WebServiceContext and retreive the Message Context. However, I can't seem to be able to cast the MessageContext to the class I want. Here is the code of my endpoint :
import org.apache.cxf.jaxws.context.WrappedMessageContext;
[...]
public MyClass [...] {
[...]
#Resource
WebServiceContext wsContext;
public WSResponse lister(SecurityInfo security, MessageId messageID, RequestBody body) {
if(wsContext.getMessageContext() instanceof WrappedMessageContext) {
//The code never goes in this
}
//However this :
wsContext.getMessageContext().getClass().toString(); //equals this : "org.apache.cxf.jaxws.context.WrappedMessageContext"
//And this is where the problem is
wsContext.getMessageContext().getClass().getClassLoader().toString(); // is : ModuleClassLoader for Module "org.apache.cxf.impl:main" [...]
this.getClass().getClassLoader().toString(); // is : ModuleClassLoader for Module "deployment.my_ws_module.war:main" [...]
}
I didn't even know about CXF 5 days ago, and discovered classloaders yesterday, but I think I kinda understand why is this happening, however, when it comes to solving it, I'm quite clueless...
Worth noting :
The project uses Maven, Spring, CXF and Java 1.8

Related

How to Pass object to REST Get Method

I am using Jersey Rest implementation. There are one Rest Services Called HelloWorld. See the below code.
Please consider this code as reference not as compiled code.
#Path("helloWorld")
public class HelloWorld{
#Path("test")
#Produces(...)
#Consum(...)
#GET
public Response test(Person person){
System.out.println(person);
}
}
I am using Jersey client to sent the request.
Here My question is apart from POST method is there any way to send the object to GET method directly. Instead of QueryString.
Please let me if there is any way to do so.
Thanks
So the problem shouldn't be with the server. I did a few tests on different servers (not weblogic as I don't use it) and all of them seem to have no problems accepting a body in the GET request. The problem seem to be with the client. To test I used the following code
ClientBuilder.newClient()
.target("http://localhost:8080/api/get-body")
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true)
.request()
.method(HttpMethod.GET, Entity.text("Hello World"));
The SUPPRESS_HTTP_COMPLIANCE_VALIDATION allows us to pass a body to the request. If we didn't use this, then we would get an error.
The problem with this code, is that even though we set this override property, the client completely overrides the GET method and automatically makes it a POST method, so I would get back a 405 Method Not Allowed.
The solution I came up with is to just allow the client to set a header, e.g. X-GET-BODY-OVERRIDE, and then use a #PreMatching filter on the server side to check for this header. If the header is present, then just change the method to a GET
#Provider
#PreMatching
public class GetWithBodyFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext request) throws IOException {
String getOverride = request.getHeaderString("X-GET-BODY-OVERRIDE");
if (getOverride != null && "true".equalsIgnoreCase(getOverride)) {
request.setMethod(HttpMethod.GET);
}
}
}
Then just register the filter with the server side. On the client, you would simply need to add the header
ClientBuilder.newClient()
.target("http://localhost:8080/api/get-body")
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true)
.request()
.header("X-GET-BODY-OVERRIDE", "True")
.method(HttpMethod.GET, Entity.text("Hello World"));
This solution is good because it takes into account more than just the Jersey client, in regards with being able to send a body in the GET request.

Auto Conversion to XML from Java Object is not working in Restlet

I have a method
#Get("xml")
public User getUser()
{
return new User();
}
In this case when calling this method browser is showing null as response. I have also annotated the User class with #XmlRootElement Tag.
It is working fine for Json transformation
#Get("json")
public User getUser()
{
return new User();
}
Please help me where I am going wrong
You can leverage the converter service of Restlet for automatic transformation of objects to payload and payload to objects.
I don't know what you use for JSON, but for XML and JAXB you need to add the org.restlet.ext.jaxb jar file corresponding to the JAXB extension of Restlet.
Doing that a converter for JAXB will be automatically add into the Restlet engine to actually handle such beans.
Hope it helps you,
Thierry

JAX-WS SoapHandler with large messages: OutOfMemoryError

Using JAX-WS 2, I see an issue that others have spoken about as well. The issue is that if a SOAP message is received inside a handler, and that SOAP message is large - whether due to inline SOAP body elements that happen to have lots of content, or due to MTOM attachments - then it is dangerously easy to get an OutOfMemoryError.
The reason is that the call to getMessage() seems to set off a chain of events that involve reading the entire SOAP message on the wire, and creating an object (or objects) representing what was on the wire.
For example:
...
public boolean handleMessage(SOAPMessageContext context)
{
// for a large message, this will cause an OutOfMemoryError
System.out.println( context.getMessage().countAttachments() );
...
My question is: is there a known mechanism/workaround for dealing with this? Specifically, it would be nice to access the SOAP part in a SOAP message without forcing the attachments (if MTOM for example) to also be vacuumed up.
For those who run their app on JBoss 6 & 7 (with Apache CXF)... I was able to troubleshoot the problem by implementing my handler from the LogicalHandler interface instead of the SOAPHandler.
In this case your handleMessage() method would get the LogicalMessageContext context (instead of SOAPMessageContext) in the arguments that has no issues with the context.getMessage() call
There's actually a JAX-WS RI (aka Metro) specific solution for this which is very effective.
See https://javaee.github.io/metro/doc/user-guide/ch02.html#efficient-handlers-in-jax-ws-ri. Unfortunately that link is now broken but you can find it on WayBack Machine. I'll give the highlights below:
The Metro folks back in 2007 introduced an additional handler type, MessageHandler<MessageHandlerContext>, which is proprietary to Metro. It is far more efficient than SOAPHandler<SOAPMessageContext> as it doesn't try to do in-memory DOM representation.
Here's the crucial text from the original blog article:
MessageHandler:
Utilizing the extensible Handler framework provided by JAX-WS
Specification and the better Message abstraction in RI, we introduced
a new handler called MessageHandler to extend your Web Service
applications. MessageHandler is similar to SOAPHandler, except that
implementations of it gets access to MessageHandlerContext (an
extension of MessageContext). Through MessageHandlerContext one can
access the Message and process it using the Message API. As I put in
the title of the blog, this handler lets you work on Message, which
provides efficient ways to access/process the message not just a DOM
based message. The programming model of the handlers is same and the
Message handlers can be mixed with standard Logical and SOAP handlers.
I have added a sample in JAX-WS RI 2.1.3 showing the use of
MessageHandler to log messages and here is a snippet from the sample:
public class LoggingHandler implements MessageHandler<MessageHandlerContext> {
public boolean handleMessage(MessageHandlerContext mhc) {
Message m = mhc.getMessage().copy();
XMLStreamWriter writer = XMLStreamWriterFactory.create(System.out);
try {
m.writeTo(writer);
} catch (XMLStreamException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean handleFault(MessageHandlerContext mhc) {
.....
return true;
}
public void close(MessageContext messageContext) { }
public Set getHeaders() {
return null;
}
}
(end quote from 2007 blog post)
You can find a full example in the Metro GitHub repo.
What JAX-WS implementation runtime are you using? If there's a way to do this using the runtime built into WebSphere I'm certain there's a way to do this cleanly in other runtimes like Axis2 (proper), Apache CXF, and Metro/RI.
I am using the other way to reduce the memory costing, which is Message Accessor.
Instead of using context.getMessage(), I changed it to this way:
Object accessor = context.get("jaxws.message.accessor");
if (accessor != null) {
baosInString = accessor.toString();
}
Base on advice from IBM website. http://www-01.ibm.com/support/docview.wss?uid=swg1PM21151

Complex (non string) return type for Jersey REST method

I'm having trouble setting something up that I'm pretty sure /should/ be easy, so I thought I'd throw it to the crowd. I can't seem to find what I'm looking for elsewhere on the web or on SE.
I am simplifying my project of course, but basically I have a JAX-WS annontated Jersey resource class that looks something like this:
#Path("myresource")
public class MyResource {
#Autowired
MyComplexObjectDAO daoInstance;
#Path("findObject/{id}")
#GET
public MyComplexObject findObject( #PathParam(value="id") String id ) {
return daoInstance.findObject( id );
}
#Path("saveObject")
#PUT
public MyComplexObject saveObject( MyComplexObject objectToSave ) {
MyComplexObject savedObject = daoInstance.saveObject( objectToSave );
return savedObject;
}
}
So you can see I'm autowiring a DAO object using spring, and then I use the DAO methods in the REST handlers.
The 'findObject' call seems to work fine - so far it works exactly as I expect it to.
The 'saveObject' call is not working the way I want and that's what I need some advice on.
You can see that I'm trying to directly take an instance of my complex object as a parameter to the REST method. Additionally I would like to return an instance of the complex object after it's been saved.
I put together some 'client' code for testing this out.
#Test
public void saveTest() {
WebResource wsClient = createWebServiceClient();
MyComplexObject unsavedInstance = createMyComplexObject();
MyComplexObject savedInstance =
wsClient
.path("saveObject")
.accept(MediaType.APPLICATION_XML)
.put(MyComplexObject.class, unsavedInstance);
assertNotNull(savedIntent);
}
Which is returning the following error:
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:8081/rest/myresource/save returned a response status of 400 Bad Request
I don't see why this isn't working and I think I've tried just about everything I can think of. Any help or direction would be very much appreciated.
Thanks so much!
I see that you call the accept() method in your test client (which means that a "Accept:" header is added to the request, indicating the server what type of representation you would like). However, you don't call the type() method to add a "Content-type:" header and inform the server that you are sending XML data. See http://jersey.java.net/nonav/documentation/latest/client-api.html#d4e644 for examples.
Side remark: your URLs are not RESTful - you should avoid verbs in your path:
So, instead of:
/api/findObject/{id}
/api/saveObject
You should use:
/api/objects/{id}
/api/objects
Last note: to create an object on calling /api/objects, you should do a POST and not a PUT to adhere to REST best practices and widely adopted patterns.
switching to the 'concrete class' solution I alluded to in my earlier comment is what fixed things up for me.

adding http headers in call to SoapHttpClient service

I have to consume a service provided by one of our partners. I was given little direction, but was told the security was to be PasswordDigest. I looked it up and immediatly saw lots of references to WSE, so off I went. It was very easy to implement and in no time I had a standard WSE user token using PasswordDigest sitting in the SOAP headers of my messages.
When we started testing today I was immediatly told (by the error message) that things weren't right. Turns out, out partner doesn't look in the SOAP header, but rather wants the security info in the http header.
I have seen lots of articles on how to add custom http headers to a proxy class, but my proxy inherits from SoapHttpClientProtocol which doesn't have a headers collection to add to. I was looking at making a raw httpWebRequest, but I have a specific method to access that has some complex parameters to deal with (and besides it feels like going backwords).
What is the best way to add custom http headers to a service proxy class that doesn't have a GetWebRequest method?
For reference:
Proxy class decleration:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.3053")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="MtomServiceSoap11", namespace="http://ws.xxxxxxx.com/")]
public partial class MtomServiceService : System.Web.Services.Protocols.SoapHttpClientProtocol {
Target method I need to call:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
[return: System.Xml.Serialization.XmlElementAttribute("uploadDocumentResponse", Namespace="http://ws.edsmtom.citizensfla.com/")]
public uploadDocumentResponse uploadDocument([System.Xml.Serialization.XmlElementAttribute(Namespace="http://ws.xxxxxxx.com/")] uploadDocumentRequest uploadDocumentRequest) {
object[] results = this.Invoke("uploadDocument", new object[] {
uploadDocumentRequest});
return ((uploadDocumentResponse)(results[0]));
}
}
The actual call to the Service is simple. The objects being pass in are not:
request.criteria = docCriteria;
request.document = document;
var result = service.uploadDocument(request);
Thanks.
It figures that 30 minutes after posting I would stumble across the answer. While the proxy class decelaration does not create a GetWebRequest method, its base class System.Web.Services.Protocols.SoapHttpClientProtocol has it and it can be overridden.
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
var request = base.GetWebRequest(uri);
request.Headers.Add("blah", "blah"); // <----
return request;
}