Writing the marshaler class

{scrollbar}

We now have to INLINE

write the marshaler class

to handle incoming and outgoing data.

Creating the marshaler class

Preparing an Eclipse project

In order to ease the development we will now make use of Mavens ability to create Eclipse projects. From the http-consumer-su main folder run the following comand:

mvn eclipse:clean eclipse:eclipse

This will cleanup any existing Eclipse config (eclipse:clean) and create a new eclipse project (eclipse:eclipse).
When done it should post something like:

... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5 seconds [INFO] Finished at: Wed Nov 28 12:21:12 CET 2007 [INFO] Final Memory: 14M/78M [INFO] ------------------------------------------------------------------------

Importing the project into Eclipse

Now it's time to start up Eclipse workbench. Choose File > Import > Existing Projects into Workspace.
Then select the projects root directory and press OK. A project named http-consumer-su should now be visible inside the Import window's projects list. Make sure it's checkbox is selected and press finish.
The project should now appear in your Package Explorer view.

Be sure you have specified the M2_REPO classpath variable to point on your local Maven repository which is located in your home folder.
For example: /home/lhe/.m2/repository
If you don't know how to specify this variable refer to the Eclipse documentation or Google it.

Create the marshaler class file

Important note

Until now we have just used our service unit to configure the behaviour of the JBI http-bc. Now we are going to extend the functionlity of this http binding component. To do this we will implement our own marshaler, which will handle incoming and outgoing messages.

For this select the src/main folder in your project. Now create a new folder under main called java. Add this new folder to your source folders.
If you did it correctly the new folder should show up as src/main/java right below the src/main/resources folder.

Now select the new folder and select File > New > Class. In the dialog enter the following:

*

Package: org.apache.servicemix.jbi Name: HTTPMarshaler Superclass: org.apache.servicemix.http.endpoints.DefaultHttpConsumerMarshaler

*
Then hit Finish to create the class.

About the DefaultHttpConsumerMarshaler

The class DefaultHttpConsumerMarshaler implements the interface HttpConsumerMarshaler and is used as default marshaler on http:consumer endpoints
if nothing else is defined.
The interface HttpConsumerMarshaler contains the following method declarations:

java public interface HttpConsumerMarshaler { MessageExchange createExchange(HttpServletRequest request, ComponentContext context) throws Exception; void sendOut(MessageExchange exchange, NormalizedMessage outMsg, HttpServletRequest request, HttpServletResponse response) throws Exception; void sendFault(MessageExchange exchange, Fault fault, HttpServletRequest request, HttpServletResponse response) throws Exception; void sendError(MessageExchange exchange, Exception error, HttpServletRequest request, HttpServletResponse response) throws Exception; void sendAccepted(MessageExchange exchange, HttpServletRequest request, HttpServletResponse response) throws Exception; }

The createExchange method is invoked on incoming data that is accepted. So this will be one method to override in our marshaler.
Another method which is interesting for us is the sendOut method. This method is used to send an answer back to the client and will be overridden as well.
All other methods are out of scope of this tutorial and will be untouched.

HTTPMarshaler

As said above we just subclass the DefaultHttpConsumerMarshaler to have only to code as less as possible.
We just override now the methods createExchange and sendOut to fit our needs.

createExchange()

We will use the commons-fileupload lib to have a multipart-formdata parser out-of-box.
The below code shows how it is checked if the request is a multipart-formdata request and the data is extracted.
Finally we create a message exchange and fill it with a dummy content and the uploaded file in the attachment.

javacreateExchange method with additional comments public MessageExchange createExchange(HttpServletRequest request, ComponentContext context) throws Exception { // create a message exchange with the set default MEP MessageExchange me = context.getDeliveryChannel().createExchangeFactory().createExchange(getDefaultMep()); // Check if we have got a file upload request (multipart content) boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (isMultipart) { // create the "in" message NormalizedMessage in = me.createMessage(); // set a dummy content, otherwise the NMR will throw errors - null content not allowed in.setContent(new StringSource("<payload/>")); // Parse the request with the FileUploadServlet List items = upload.parseRequest(request); // Process the uploaded items Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem)iter.next(); if (item.isFormField()) { // this item is a formular field processFormField(item, in); } else { // this item is a file content item processUploadedFile(item, in); } } // set this in message as the "in" message of the message exchange me.setMessage(in, "in"); } else { throw new Exception("Request is not a valid multipart message"); } // finally return the ready exchange to be sent return me; }

sendOut()

In this method we just take the first attachment in the message exchange and write it to a temporary file.
Afterwards the response header is set and the file is posted as stream into the response's output stream.
Notice that we make use of the sendError method of our super class to handle exceptions.

javasendOut method with additional comments public void sendOut(MessageExchange exchange, NormalizedMessage outMsg, HttpServletRequest request, HttpServletResponse response) throws Exception { // define a DataHandler (see Java Activation Framework) DataHandler dh = null; // if the out message received has no attachments, then we send an error to the client if (outMsg.getAttachmentNames().isEmpty()) { // use the super class method sendError to send an error to the client sendError(exchange, new Exception("Invalid answer from handler."), request, response); // and return return; } // get all attachment names from the out message Set set = outMsg.getAttachmentNames(); Iterator iterator = set.iterator(); String key = null; if (iterator.hasNext()) { // we are now only interested in the first attachment key = iterator.next().toString(); // this resolves the key which is also the filename dh = outMsg.getAttachment(key); // this will resolve the data handler (file content) } else { sendError(exchange, new Exception("Invalid answer from handler."), request, response); return; } if (dh == null) { sendError(exchange, new Exception("Invalid answer from handler."), request, response); return; } // create a temporary file File f = File.createTempFile("tmp_", key); // open an output stream to this file FileOutputStream fos = new FileOutputStream(f); // now we use the FileUtil's copyInputStream method to copy the content of the data // handlers data source into the output stream FileUtil.copyInputStream(dh.getDataSource().getInputStream(), fos); // and close the output stream afterwards fos.close(); // now create a file data source with the temporary file FileDataSource fds = new FileDataSource(f); // create a stream datasource with the input stream of the file data source, the // content type is provided by a method of the FileDataSource StreamDataSource sds = new StreamDataSource(fds.getInputStream(), fds.getContentType()); // then a new datahandler is created with the stream datasource DataHandler dhsds = new DataHandler(sds); // tells the response object to open a popup in the clients browser with the given // filename (stored in key) response.setHeader("content-disposition", "attachment; filename=\"" + key + "\""); // set the content type to what the FileDataSource determined automatically response.setContentType(fds.getContentType()); // also set the length of the content response.setContentLength((int)f.length()); try { // now get the output stream of the servlet to send data to the clients browser ServletOutputStream sos = response.getOutputStream(); // use the writeTo method of the data handler to easy to output of the data // into the servlets output stream dhsds.writeTo(sos); // finally set the status of the response to OK response.setStatus(HttpServletResponse.SC_OK); } catch (Exception e) { logger.log(Level.WARNING, "Exception occurred" + e.getMessage(), e); } // afterwards clean up the temporary file f.deleteOnExit(); }

The finished class

javaHTTPMarshaler.javasolid package org.apache.servicemix.jbi; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.jbi.component.ComponentContext; import javax.jbi.messaging.MessageExchange; import javax.jbi.messaging.MessagingException; import javax.jbi.messaging.NormalizedMessage; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.servicemix.http.endpoints.DefaultHttpConsumerMarshaler; import org.apache.servicemix.jbi.jaxp.StringSource; import org.apache.servicemix.jbi.messaging.MessageExchangeSupport; import org.apache.servicemix.jbi.util.ByteArrayDataSource; import org.apache.servicemix.jbi.util.FileUtil; import org.apache.servicemix.jbi.util.StreamDataSource; public class HTTPMarshaler extends DefaultHttpConsumerMarshaler { private static final Logger logger = Logger.getLogger(HTTPMarshaler.class.getName()); private static final int MAX_MEM_SIZE = 10 * 1024 * 1024; private static final File TEMP_FOLDER = new File(System.getProperty("java.io.tmpdir")); private static final long MAX_UPLOAD_SIZE = 1024 * 1024 * 100; private DiskFileItemFactory factory; private ServletFileUpload upload; /** * constructor */ public HTTPMarshaler() { super(MessageExchangeSupport.IN_OUT); // Create a factory for disk-based file items factory = new DiskFileItemFactory(); // Set factory constraints factory.setSizeThreshold(MAX_MEM_SIZE); factory.setRepository(TEMP_FOLDER); // Create a new file upload handler upload = new ServletFileUpload(factory); // Set overall request size constraint upload.setSizeMax(MAX_UPLOAD_SIZE); } public MessageExchange createExchange(HttpServletRequest request, ComponentContext context) throws Exception { MessageExchange me = context.getDeliveryChannel().createExchangeFactory().createExchange(getDefaultMep()); // Check that we have a file upload request boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (isMultipart) { NormalizedMessage in = me.createMessage(); in.setContent(new StringSource("<payload/>")); // Parse the request List items = upload.parseRequest(request); // Process the uploaded items Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem)iter.next(); if (item.isFormField()) { processFormField(item, in); } else { processUploadedFile(item, in); } } me.setMessage(in, "in"); } else { throw new Exception("Request is not a valid multipart message"); } return me; } /** * processes form fields * * @param item the field * @param msg the in message */ private void processFormField(FileItem item, NormalizedMessage msg) { String name = item.getFieldName(); String value = item.getString(); msg.setProperty(name, value); } /** * processes file items * * @param item the item * @param msg the in message */ private void processUploadedFile(FileItem item, NormalizedMessage msg) { String fieldName = item.getFieldName(); String fileName = item.getName(); String contentType = item.getContentType(); boolean isInMemory = item.isInMemory(); long sizeInBytes = item.getSize(); DataHandler dh = null; if (isInMemory) { dh = new DataHandler(new ByteArrayDataSource(item.get(), item.getContentType())); } else { try { dh = new DataHandler(new StreamDataSource(item.getInputStream(), item.getContentType())); } catch (IOException ioex) { dh = new DataHandler(new ByteArrayDataSource(item.get(), item.getContentType())); } } try { msg.addAttachment(fileName, dh); } catch (MessagingException e) { e.printStackTrace(); } } public void sendOut(MessageExchange exchange, NormalizedMessage outMsg, HttpServletRequest request, HttpServletResponse response) throws Exception { DataHandler dh = null; if (outMsg.getAttachmentNames().isEmpty()) { sendError(exchange, new Exception("Invalid answer from handler."), request, response); return; } Set set = outMsg.getAttachmentNames(); Iterator iterator = set.iterator(); String key = null; if (iterator.hasNext()) { key = iterator.next().toString(); dh = outMsg.getAttachment(key); } else { sendError(exchange, new Exception("Invalid answer from handler."), request, response); return; } if (dh == null) { sendError(exchange, new Exception("Invalid answer from handler."), request, response); return; } File f = File.createTempFile("tmp_", key); FileOutputStream fos = new FileOutputStream(f); FileUtil.copyInputStream(dh.getDataSource().getInputStream(), fos); fos.close(); FileDataSource fds = new FileDataSource(f); StreamDataSource sds = new StreamDataSource(fds.getInputStream(), fds.getContentType()); DataHandler dhsds = new DataHandler(sds); response.setHeader("content-disposition", "attachment; filename=\"" + key + "\""); response.setContentType(fds.getContentType()); response.setContentLength((int)f.length()); try { ServletOutputStream sos = response.getOutputStream(); dhsds.writeTo(sos); response.setStatus(HttpServletResponse.SC_OK); } catch (Exception e) { logger.log(Level.WARNING, "Exception occurred" + e.getMessage(), e); } f.deleteOnExit(); } }

Feel free to play around with this class after you ran it once sucessfully. There is enough room for improvements.

Now the consumer SU is ready for work. Let's move on to the http-handler SU which handles the JBI messages from our consumer.

Proceed to the next step



{scrollbar}
  • No labels