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
Related
I am currently learning Camel and i am not sure if we can send messages to a activemq queue/topic from camel at fixed interval.
Currently i have created code in Scala which looks up the database and create a message and sends it to queue after every minute can we do this in camel.
We have a timer component in camel but it does not produce the message. I was thinking something like this.
from("timer://foo?fixedRate=true&period=60000")
.to("customLogic")
.to("jms:myqueue")
Timer will kick after a minute.
Custom logic will do database look up and create a message
Finally send to jms queue
I am very new to Camel so some code will be really helpful thanks
Can you please point me to how can i create this customeLogic method that can create a message and pass it to next ".to("jms:myqueue")". Is there some class that in need to inherit/implement which will pass the the message etc.
I guess your question is about how to hook custom java logic into your camel route to prepare the JMS message payload.
The JMS component will use the exchange body as the JMS message payload, so you need to set the body in your custom logic. There are several ways to do this.
You can create a custom processor by implementing the org.apache.camel.Processor interface and explicitly setting the new body on the exchange:
Processor customLogicProcessor = new Processor() {
#Override
public void process(Exchange exchange) {
// do your db lookup, etc.
String myMessage = ...
exchange.getIn().setBody(myMessage);
}
};
from("timer://foo?fixedRate=true&period=60000")
.process(customLogicProcessor)
.to("jms:myqueue");
A more elegant option is to make use of Camel's bean binding:
public class CustomLogic {
#Handler
public String doStuff() {
// do your db lookup, etc.
String myMessage = ...
return myMessage;
}
}
[...]
CustomLogic customLogicBean = new CustomLogic();
from("timer://foo?fixedRate=true&period=60000")
.bean(customLogicBean)
.to("jms:myqueue");
The #Handler annotation tells Camel which method it should call. If there's only one qualifying method you don't need that annotation.
Camel makes the result of the method call the new body on the exchange that will be passed to the JMS component.
I have an interface that extends the com.google.gwt.i18n.client.Messages class, which I use for retrieving i18n messages in my GWT application. It looks like this:
public interface MyMessages extends com.google.gwt.i18n.client.Messages {
#DefaultMessage("Hello world")
#Key("message1")
String message1();
#DefaultMessage("Hello again")
#Key("message2")
String message2();
//...
}
Normally, I create an instance of it using GWT.create() like so:
private MyMessages messages = GWT.create(MyMessages.class);
However, this does not work with server-side code, only client-side code (it throws an error saying that GWT.create() is only usable in client-side code).
The answer to a similar question points to a separate library that you can download which will let you access the i18n messages on the server, but I don't want to download any extra libraries (this seems like a simple problem, there must be a simple solution).
In summary: How can I access my i18n messages in server-side code? Thanks.
On the server side you can use the standard Java localization tools like ResourceBundle.
Look here for a tutorial how to use it.
// Create a ResourceBundle out of your property files
ResourceBundle labels =
ResourceBundle.getBundle("LabelsBundle", currentLocale);
// Get localized value
String value = labels.getString(key);
The GWT specific way of creating an interface out of your property files and providing implementations via deferred binding can not be used on sever side Java.
If you are fearless and willing to spend the time, you can implement a code generation step to read your property files and generate implementation classes for your message interface. That's exactly what the Google GWT compiler does behind the scene.
I agree with Michael.. I was having this problem of trying to "localize" messages generated on the server.... but I decided to instead just throw an Exception on the server (because it is an error message which should only happen exceptionally) which contains the message code, which the client code can then look up and show the correct localized message to the user.
There's a great library for GWT internationalization gwt-dmesg. It allows you to 'share' .properties files between clent and server. However, project looks to be abandoned by author and you must recompile it manually for use with GWT versio >= 2.1.0.
GWT.create() can only be used in client-side code.
The good thing to do is that you provide your own I18NProvider class/interface, from which then you can extend to server side I18N factory and client side I18N factory read the same resource bundle.
After that you can simply use it all over your system, unify your code.
Hope that helps.
Following vanje's answer, and considering the encoding used for the properties files (which can be troublesome as ResourceBundle uses by default "ISO-8859-1", here is the solution I came up with:
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;
public class MyResourceBundle {
// feature variables
private ResourceBundle bundle;
private String fileEncoding;
public MyResourceBundle(Locale locale, String fileEncoding){
this.bundle = ResourceBundle.getBundle("com.app.Bundle", locale);
this.fileEncoding = fileEncoding;
}
public MyResourceBundle(Locale locale){
this(locale, "UTF-8");
}
public String getString(String key){
String value = bundle.getString(key);
try {
return new String(value.getBytes("ISO-8859-1"), fileEncoding);
} catch (UnsupportedEncodingException e) {
return value;
}
}
}
The way to use this would be very similar than the regular ResourceBundle usage:
private MyResourceBundle labels = new MyResourceBundle("es", "UTF-8");
String label = labels.getString(key)
Or you can use the alternate constructor which uses UTF-8 by default:
private MyResourceBundle labels = new MyResourceBundle("es");
I am building a SOAP webservice. I am using JAX-WS to create this service and deploying it on a Glassfish 3.1.2 server.
I have no problem having this service return a String build with the XML representation of what I want. I can also get it to return a specific object. What I am having issues with is streaming this resource.
This is what I have so far :
Interface :
#MTOM
#WebService
#XmlRootElement(name="root.element.class.location")
#SOAPBinding(style = Style.RPC, use=Use.LITERAL)
public interface ResultsServer {
#WebMethod
#XmlMimeType("text/xml")
public Test getResultDataAsXML(#WebParam(name="Id") Integer id) throws Exception;
}
Implementation :
---- Edit ----
This is where I would like to stream my resource. Let's say I need my results object becomes extremely large, I don't want to hold this is memory and would like to start sending it without holding it. (commented this in code)
#WebService(endpointInterface = "my.endpoint.class")
#StreamingAttachment(parseEagerly=true, memoryThreshold=4000000L)
public class ResultsServerImpl implements ResultsServer {
#Override
public Test getResultDataAsXML(Integer id) throws Exception {
Test results = new Test();
for(int i=0; i<[very large number]; i++) {
results.getResults().add("here : " + i);
/**at one point, this is too large to hold in memory
I would like to be able to start returning the object here
so it is not taking up all available memory */
}
return results; //or close the stream
}
}
---- End Edit ----
And my Test class is a simple class looking like this :
public class Test {
private ArrayList<String> results;
public Test() {
results = new ArrayList<String>();
}
public ArrayList<String> getResults() {
return results;
}
public void setResults(ArrayList<String> results) {
this.results = results;
}
}
Let's assume that this Test object becomes very big (and more complexe). I need to be able to stream this object. How would I go to proceed in streaming this.
Ideally, I would like to keep the structure of this object.
From what I have read so far, I would need to convert this object in some sort of DataHandler and return this object.
Any help is welcome! Thank you.
The JAX-WS implementation will leverage a JAXB implementation to marshal the object (most likely to a StAX XMLStreamWriter) so the output will be streamed (there won't be an XML document created in memory).
#BlaiseDoughan I think you've worded this the way I was looking for.
Yes that would be to prevent the instance of Test of fully being saved
in memory. Is there a way to do this?
If you want the data to appear in the messages as XML (as opposed to a SOAP attachment), the you could leverage JAXB's marshal events. In the beforeMarshal event you could load data into an object and then clear it in the afterUnmarshal method. Ultimately all the data will be pulled in, but it won't all be referenced at the same time.
http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/Unmarshaller.html#unmarshalEventCallback
I would recommend using the xstream (http://x-stream.github.io/) library from thoughtworks for your streaming as it is bindable on both sides of your service and is compatible with SOAP envelops. In fact there is even an integration with ActiveSOAP.
An example of a SOAP envelope wrapped xstream object can be seen at http://jira.codehaus.org/secure/attachment/19097/SoapEnvelopeTestCase.java. A full usage from jboss can be seen at https://issues.jboss.org/secure/attachment/12325534/SOAPClient.java?_sscc=t.
XStream has been used for some very large streaming processes (I've used it for some large 100+ MB text objects without issue).
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.
I have a C# service that runs continuously with user credentials (i.e not as localsystem - I can't change this though I want to). For the most part the service seems to run ok, but ever so often it bombs out and restarts for no apparent reason (servicer manager is set to restart service on crash).
I am doing substantial event logging, and I have a layered approach to Exception handling that I believe makes at least some sort of sense:
Essentially I got the top level generic exception, null exception and startup exception handlers.
Then I got various handlers at the "command level" (i.e specific actions that the service runs)
Finally I handle a few exceptions handled at the class level
I have been looking at whether any resources aren't properly released, and I am starting to suspect my mailing code (send email). I noticed that I was not calling Dispose for the MailMessage object, and I have now rewritten the SendMail code as illustrated below.
The basic question is:
will this code properly release all resources used to send mails?
I don't see a way to dispose of the SmtpClient object?
(for the record: I am not using object initializer to make the sample easier to read)
private static void SendMail(string subject, string html)
{
try
{
using ( var m = new MailMessage() )
{
m.From = new MailAddress("service#company.com");
m.To.Add("user#company.com");
m.Priority = MailPriority.Normal;
m.IsBodyHtml = true;
m.Subject = subject;
m.Body = html;
var smtp = new SmtpClient("mailhost");
smtp.Send(m);
}
}
catch (Exception ex)
{
throw new MyMailException("Mail error.", ex);
}
}
I know this question is pre .Net 4 but version 4 now supports a Dispose method that properly sends a quit to the smpt server. See the msdn reference and a newer stackoverflow question.
There are documented issues with the SmtpClient class. I recommend buying a third party control since they aren't too expensive. Chilkat makes a decent one.