Tags

, , ,

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

  1. What are the issues of running CXF on GAE ?
  2. How to run JAXB on GAE ?

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:

  1. Writing to file should be disabled as it is restricted by GAE
  2. GAE doesn’t allow to spawn new threads
  3. 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