Writing the bean class

We now have to 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:

   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.

   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

HandlerBean.java
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