Writing the bean class

{scrollbar}

We now have to INLINE

write the bean class

to handle incoming message exchanges.

Creating the bean 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-handler-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-handler-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 bean class file

Next thing to do is creation the bean class. For this select the src/main/java folder in your project. Now delete everything inside this folder.

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

*

Package: org.apache.servicemix.jbi Name: HandlerBean Interfaces: org.apache.servicemix.MessageExchangeListener

*

Then hit Finish to create the class. Eclipse will also implement the interface's only method for you:
*

java public void onMessageExchange(MessageExchange arg0) throws MessagingException {...}

*
This method is responsible for handling incoming messages.

Handling incoming messages

We assume (and do not further check) that each incoming message exchange is of type InOut MEP. Feel free to improve this and check for the correct Message Exchange Pattern.

We extract the first attachment of the message by name. The name is equal to the filename. After this we have the original filename in the
fileName variable and the file content in the content variable (as DataHandler object).
For the sake of simplicity we just write the contents into a temporary file and use this file for sending it back to the http-consumer-su.

java fileName = it.next().toString(); content = in.getAttachment(fileName); // create a temporary file File f = File.createTempFile("tmp_", fileName); // open an output stream to this file FileOutputStream fos = new FileOutputStream(f); // use the DataHandler to write the contents into the stream content.writeTo(fos); // flush and close the stream (flush should be done automatically on closing the stream and so it's maybe not needed here) fos.flush(); fos.close(); // for the sake of simplicity only return the file received as attachment NormalizedMessage out = exchange.createMessage(); // set the content to dummy xml tag out.setContent(new StringSource("<payload/>")); FileDataSource fds = new FileDataSource(f); InputStream is = fds.getInputStream(); // create a handler for the attachment (the data from the file is obtained by using a StreamDataSource which takes // 2 parameters - the input stream (of the filedatasource) and the content type (for example application/octet-stream) DataHandler dh = new DataHandler(new StreamDataSource(is, fds.getContentType())); // mime type is obtained automatically here // and add the datahandler to the message's attachments (binary data can't be send in the content - so use attachments) out.addAttachment(fileName, dh); // prepare and send the exchange exchange.setMessage(out, "out"); channel.send(exchange); // finally clean up the temporary file f.deleteOnExit();

This is of course a stupid example, so just imagine you convert this file into another format and send the result back.
You can do such a logic if you want. For this you can refer for example to OpenOffice running in headless mode in combination with the JODConverter of "Arts of Solving". This will enable you to convert for example a .odt document into a .pdf document. But this is really out of scope now.

The finished class

javaHandlerBean.javasolid package org.apache.servicemix.jbi; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.Set; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.annotation.Resource; import javax.jbi.messaging.DeliveryChannel; import javax.jbi.messaging.ExchangeStatus; import javax.jbi.messaging.MessageExchange; import javax.jbi.messaging.MessagingException; import javax.jbi.messaging.NormalizedMessage; import javax.jbi.messaging.MessageExchange.Role; import org.apache.log4j.Logger; import org.apache.servicemix.MessageExchangeListener; import org.apache.servicemix.jbi.jaxp.StringSource; import org.apache.servicemix.jbi.util.StreamDataSource; public class HandlerBean implements MessageExchangeListener { private static final Logger logger = Logger.getLogger(HandlerBean.class); @Resource private DeliveryChannel channel; /* * (non-Javadoc) * @see org.apache.servicemix.MessageExchangeListener#onMessageExchange(javax.jbi.messaging.MessageExchange) */ public void onMessageExchange(MessageExchange exchange) throws MessagingException { if (exchange == null) { return; } // The component acts as a consumer, this means this exchange is received because // we sent it to another component. As it is active, this is either an out or a fault // If this component does not create / send exchanges, you may just throw an // UnsupportedOperationException if (exchange.getRole() == Role.CONSUMER) { onConsumerExchange(exchange); } // The component acts as a provider, this means that another component has requested our // service // As this exchange is active, this is either an in or a fault (out are send by this // component) else if (exchange.getRole() == MessageExchange.Role.PROVIDER) { onProviderExchange(exchange); } // Unknown role else { throw new MessagingException("HandlerBean.onMessageExchange(): Unknown role: " + exchange.getRole()); } } /** * handles the incoming consumer messages * * @param exchange * @throws MessagingException */ private void onConsumerExchange(MessageExchange exchange) throws MessagingException { // Out message if (exchange.getMessage("out") != null) { exchange.setStatus(ExchangeStatus.DONE); channel.send(exchange); } // Fault message else if (exchange.getFault() != null) { exchange.setStatus(ExchangeStatus.DONE); channel.send(exchange); } // This is not compliant with the default MEPs else { throw new MessagingException("HandlerBean.onConsumerExchange(): Consumer exchange is ACTIVE, but no out or fault is provided"); } } /** * handles the incoming provider messages * * @param exchange * @throws MessagingException */ private void onProviderExchange(MessageExchange exchange) throws MessagingException { // Exchange is finished if (exchange.getStatus() == ExchangeStatus.DONE) { return; } // Exchange has been aborted with an exception else if (exchange.getStatus() == ExchangeStatus.ERROR) { return; } // Fault message else if (exchange.getFault() != null) { exchange.setStatus(ExchangeStatus.DONE); channel.send(exchange); } else { NormalizedMessage in = exchange.getMessage("in"); if (in == null) { // no in message - strange throw new MessagingException("HandlerBean.onProviderExchange(): Exchange has no IN message"); } else { String fileName = null; DataHandler content = null; Set attNames = in.getAttachmentNames(); Iterator it = attNames.iterator(); if (attNames.size()==1) { if (it.hasNext()) { try { File file = new File(it.next().toString()); fileName = file.getName(); content = in.getAttachment(fileName); File f = File.createTempFile("tmp_", fileName); FileOutputStream fos = new FileOutputStream(f); content.writeTo(fos); fos.flush(); fos.close(); // for the sake of simplicity only return the file received as attachment NormalizedMessage out = exchange.createMessage(); // set the content to dummy xml tag out.setContent(new StringSource("<payload/>")); FileDataSource fds = new FileDataSource(f); InputStream is = fds.getInputStream(); // create a handler for the attachment DataHandler dh = new DataHandler(new StreamDataSource(is, fds.getContentType())); // and add it to the message out.addAttachment(fileName, dh); // prepare and send the exchange exchange.setMessage(out, "out"); channel.send(exchange); f.deleteOnExit(); } catch (IOException ex) { throw new MessagingException("HandlerBean.onProviderExchange(): " + ex.getLocalizedMessage()); } } } else { // more or less than one attachment throw new MessagingException("HandlerBean.onProviderExchange(): Wrong message format (invalid attachment count)"); } } } } }

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

Now the handler SU is ready for work. Let's move on to creating the service assembly.

Proceed to the next step



{scrollbar}
  • No labels

1 Comment

  1. There is a bug in the HandlerBean.java code snippet. The beginning of the try /catch block in the onProviderExchange() method should start with:

    String attName = it.next().toString();
    File file = new File(attName);
    fileName = file.getName();
    content = in.getAttachment(attName);

    The attName includes the path, where the fileName does not. Since the existing code uses the fileName as the key to get the attachment, the key doesn't match and it creates a null content object which results in a null pointer exception.