This is the final and most important post in the series which will make the CXF-RS app running on GAE.
Till now we have seen
In this post we will see how will we run make changes in Apache CXF source so that everything starts working.
The ideas and changes are influenced by one of the apache CXF developer Daniel Kulp who gave some interesting insights about CXF.
Issues:
- Writing to file should be disabled as it is restricted by GAE
- GAE doesn’t allow to spawn new threads
- Changes in JAXB source should be integrated with CXF
Changes are done keeping in mind that
- We are interested only in JAX-RS
- WSDL is not required
CXF has “workqueues” using threads which provides support for one-way operations. But as in JAX-RS we hardly have any one way operations so we need not consider about “workqueues.
For attachments and message logging, a special output stream is used such that once a threshold is reached, it starts saving to temporary files on the file system. As on GAE we can’t create new files. So we have two options
- To save all that data which was earlier written by CXF in a temp file to GAE datastore.
- We can just proceed keeping them in memory.
But the, the maximum message size GAE allows in or out is 10MB(which also sometimes cause a problem as some kind of “Server Error” starts coming on sending a request of ≥1MB and so we are only able to send a request of ≤1MB successfully ) Thus, the message sizes are small enough to keep them in memory itself. So we will proceed by disabling this feature of saving to temp files.
We also have to reflect the changes in JAXB (i.e. to add jaxb.jar) and change the classes to use the new packages(changed names) from jaxb.jar instead of jaxb-impl*.jar and jaxb-api*.jar
Changes:
1. In org.apache.cxf.io.CachedOutputStream.java
Comment out regions using FleOutputStream , boolean inmem and threshold
After commenting out these things CXF won’t make any temporary files for storing logs or attachments.
2. Change the package name from javax.xml.bind.* to ae.javax.xml.bind.* in the following files :-
- org.apache.cxf.jaxrs.provider.XSLTJaxbProvider.java
- org.apache.cxf.ws.policy.builder.jaxb.JaxbAssertionBuilder.java
- org.apache.cxf.transport.http.policy.HTTPClientAssertionBuilder.java
- org.apache.cxf.transport.http.policy.HTTPServerAssertionBuilder.java
- org.apache.cxf.transport.AbstractMultiplexDestination.java
- org.apache.cxf.jaxrs.provider. AbstractJAXBProvider.java
3. Disable saving to file in
- org.apache.cxf.interceptor.LoggingInInterceptor.java by commenting out
if (bos.getTempFile() != null) {
//large thing on disk…
buffer.getMessage().append(“\nMessage (saved to tmp file):\n”);
buffer.getMessage().append(“Filename: ” + bos.getTempFile().getAbsolutePath() + “\n”);
}
- org.apache.cxf.interceptor.LoggingOutInterceptor.java by commenting out
if (cos.getTempFile() == null) {
//buffer.append(“Outbound Message:\n”);
if (cos.size() > limit) {
buffer.getMessage().append(“(message truncated to ” + limit + ” bytes)\n”);
}
}else {
buffer.getMessage().append(“Outbound Message (saved to tmp file):\n”);
buffer.getMessage().append(“Filename: ” + cos.getTempFile().getAbsolutePath() + “\n”);
if (cos.size() > limit) {
buffer.getMessage().append(“(message truncated to ” + limit + ” bytes)\n”);
}
}
4. In the file org.apache.cxf.jaxrs.provider.JAXBElementProvider.java
Change the package name from javax.xml.bind.* to ae.javax.xml.bind.*
Change the function as
protected Object unmarshalFromReader(Unmarshaller unmarshaller, XMLStreamReader reader, MediaType mt) throws JAXBException {
return unmarshaller.unmarshal ((ae.javax.xml.stream.XMLStreamReader)reader);
}
public Object readFrom(Class<Object> type, Type genericType, Annotation[] anns, MediaType mt,
MultivaluedMap<String, String> headers, InputStream is)
throws IOException {
try {
Class<?> theType = getActualType(type, genericType, anns);
Unmarshaller unmarshaller = (Unmarshaller)createUnmarshaller(theType, genericType);
……..
……..
……..
The changes done are normal typecasting of reader and unmarshaller.
With these changes I got my CXF-RS app running on GAE.
A sample CXF-RS app on GAE can be viewed on appengine
astebbot said:
Hello, I found this article tremendous. Also, I’m wondering about some points that aren’t clear to myself…With CXF Im’ trying to run unit tests then hit problems, like so:
javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR: : java.lang.ClassCastException: com.ctc.wstx.stax.WstxOutputFactory cannot be cast to ae.javax.xml.stream.XMLOutputFactory
at …etc
Because, as you probably guessed, I want to make WS Soap Webservices, not only Restful
So my questions are…
Did you get that point?
Do you have any clue in that package naming and dependencies nightmare?
Do you have any update with all that since…A GAE ready-to-use CXF version would be very welcomed 😀 ?
Thank you again for that article which makes me hope and believe…so am I still working forward to making it!
Tanguy