JBoss.Net Email Transport

WhatÕs the Point?

The first question usually asked when an email transport is mentioned is, ÒWhy would anyone want to do such a thing?Ó Well, email is a transport that allows both incoming and outgoing communication without ever having to be exposed directly to the Internet.

 

LetÕs take an example where company A and company B both have intranet servers behind their respective firewalls, but company B needs to exchange information on occasion with company A.  Neither server can communicate directly with the other due to the corporate firewall however the servers could easily communicate via email.

Using email as the transport in this situation provides an easy way to bypass the firewalls, without exposing the servers to additional risk of attack from the Internet. Be warned however, email by itself doesnÕt have any mechanism to guarantee the security or authenticity of a SOAP message. For this reason, we would most likely combine the use of an email transport with handlers that implement the WS-Security specification.

How It Works

Since we donÕt have a server actively listening for connections the way the HTTP transport does, we use the Scheduler to tell the MailTransportService to check its mail.

The MailTransportService fetches a mail session from JNDI and uses that session to connect to the email server. When the MailTransportService finds a message to process, it verifies that the message is a SOAP 1.2 message. It then looks for a valid from: or reply-to: header that can be used to complete the response. If all of these things check out, a MessageContext is created and passed on to the axis engine. Since email addresses do not have a path portion the way HTTP URLs do, the mail transport has a handler in its request chain that sets the target service based upon the ÒactionÓ attribute of the content type. From this point forward, the message is handled way it would be if the request had come via HTTP.

The MailService

The JBoss.Net MailTransportService mbean requires that there is a properly configured and deployed MailService. Edit the mail-service.xml (in the deploy directory) and make sure that it contains values that are pertinent to the environment in which JBoss.Net will be running. It would probably be best for JBoss.Net to have itÕs own email address for servicing SOAP calls.

 

If you want to have a completely different MailService to process JBoss.Net calls, you could add a MailService mbean to the jboss-net.sar/META-INF/jboss-service.xml file.

 

<mbean code="org.jboss.mail.MailService"

        name="jboss.net:service=JBossNetMail">

   <attribute name="JNDIName">java:/JBossNetMail</attribute>

   <attribute name="User">nobody</attribute>

   <attribute name="Password">password</attribute>

   <attribute name="Configuration">

      <configuration>

         <property name="mail.store.protocol" value="pop3"/>

         <property name="mail.transport.protocol" value="smtp"/>

         <property name="mail.user" value="nobody"/>

         <property name="mail.pop3.host" value="pop3.nosuchhost.nosuchdomain.com"/>

         <property name="mail.smtp.host" value="smtp.nosuchhost.nosuchdomain.com"/>

         <property name="mail.from" value="nobody@nosuchhost.nosuchdomain.com"/>

         <property name="mail.debug" value="false"/>

      </configuration>

   </attribute>

</mbean>

The MailTransportService

The actual server side transport is in the form of an mbean. It should be configured from the jboss-net.sar/META-INF/jboss-service.xml file.

 

<mbean code="org.jboss.net.axis.transport.mail.server.MailTransportService"

         name="jboss.net:service=MailTransport">

   <depends>jboss.net:service=Axis</depends>

   <depends>jboss:service=Mail</depends>

   <attribute name="SessionName">java:/Mail</attribute>

   <attribute name="FolderName">INBOX</attribute>

   <attribute name="TransportName">mail</attribute>

   <attribute name="EngineName">jboss.net:service=Axis</attribute>

   <attribute name="DeleteMail">true</attribute>

</mbean>

 

The available attributes are as follows:

á      SessionName

Must match the JNDIName attribute from the configured mail service.

á      FolderName

Indicates the name of the folder on the email server where SOAP messages will be found. Typically mail on pop servers is found in the INBOX.

á      TransportName

Allows the transport to be given a different name.

á      EngineName

Must match the name property of the AxisService mbean.

á      DeleteMail

Flag that instructs the mail transport to delete the email messages from the mail server once the message has been processed.

All of the attributes have been shown in the example with their default values. Attributes may be omitted from the mbean configuration if there is no need to change the default values.

If you have a separate MailService configured for JBoss.Net, be sure to edit the <depends> portion, as well as the TransportName attribute to reflect that MailService.

The Scheduler

The MailTransportService requires a scheduler to define how often it should check for new SOAP messages. The Scheduler should also be configured from the jboss-net.sar/META-INF/jboss-service.xml file.

 

<mbean code="org.jboss.varia.scheduler.Scheduler"

      name="jboss.net:service=Scheduler,name=MailTransport">

   <attribute name="StartAtStartup">true</attribute>

   <attribute name="SchedulableMBean">jboss.net:service=MailTransport</attribute>

   <attribute name="SchedulableMBeanMethod">pollMail()</attribute>

   <attribute name="InitialStartDate">NOW</attribute>

   <attribute name="SchedulePeriod">30000</attribute>

   <attribute name="InitialRepetitions">-1</attribute>

</mbean>

 

This scheduler is configured to call the EmailTransportServiceÕs pollMail() method every 30 seconds (30000 milliseconds) from the time the server starts, until it is shutdown.

 

The ÒmailÓ Transport

Once the mail transport is all configured it is necessary to tell the axis engine that it exists. This configuration is done from the jboss-net/axis-config.xml file.

 

<transport name="mail">

  <requestFlow>

     <handler type="java:org.jboss.net.axis.transport.mail.server.handler.TargetServiceHandler"/>

  </requestFlow>

</transport>

 

The transport name here must match the name from the TransportName attribute in the MailTransportService.

 

The SOAP version 1.2 specifications define a content type of Òapplication/soap+xmlÓ for SOAP messages. This new content type has an attribute ÒactionÓ that serves the same purpose as the SOAPAction HTTP header. The TargetServiceHandler routes the incoming message to the service specified by this attribute.

Caveats

1.     This implementation tries to adhere to the W3C Email Binding recommendations, therefore only messages that are composed using SOAP version 1.2 will be accepted. Note: this restriction is likely to be lifted when WS-Addressing is functional.

2.     Email does not have the equivalent of HTTP authentication, so unless other arrangements are made (see WS-Security) only unauthenticated services will be accessible via the email transport.

3.     Email does not have the equivalent of HTTPS so unless other arrangements are made (see WS-Security), you cannot guarantee end-to-end security of your SOAP message using the email transport.

 

A Simple Example

There is an example application that demonstrates the use of the email transport located in the source distributionÕs jboss.net/samples/mail directory. We will look at the parts needed to make a call via email.

The Service

Creating and deploying services that will be accessed via email is really no different than creating other services, so lets just create a simple session bean and expose itÕs echo method as a SOAP service.

 

package org.jboss.net.sample.mail.ejb;

import javax.ejb.SessionBean;

 

/**

 * Simple session bean that just echos the string sent to it

 * @author <a href="mailto:jasone@greenrivercomputing.com>Jason Essington</a>

 *

 * @ejb.bean name="Echo"

 *      display-name="Echo Bean"

 *      type="Stateless"

 *      view-type="local"

 *      local-jndi-name="ejb/jboss/net/sample/EchoLocalHome"

 *

 * @ejb.permission unchecked="true"

 * @jboss-net.web-service urn="Echo"

 */

public abstract class EchoBean implements SessionBean

{

   /**

    * @ejb.interface-method

    * @jboss-net.web-method

    */

   public String echo(String echoText)

   {

      return "echo: "+echoText;

   }

}

 

We start with an ordinary @ejb.bean description. Since this example has no way to identify the sender, we will not be able to access secured beans. Therefore, the @ejb.permission tag is set as unchecked. Finally there is a @jboss-net.web-service tag that defines the name (Echo) we will use to access this bean as a web service.

We define the class as abstract and skip the implementation of all the SessionBean interface methods. The session module called from ejbdoclet will generate simple implementations of the interface methods for us.

Our echo method is given an @ejb.interface-method tag to indicate that it should be exposed in the bean interface. It is also given a @jboss-net.web-method tag to indicate that it is an allowed method of the Echo service.

This bean will be compiled and the jar, wsr, ear archives created by calling ./build.sh (or build.bat) from the jboss.net/samples/mail directory.

 

The Client

To access this service via email, we will create a simple client application that calls our new Echo service. This client is not terribly smart about asynchronous messaging. It will just wait until it receives a response that correlates with its request.

 

package org.jboss.net.sample.mail.client;

import javax.xml.rpc.ParameterMode;

import org.apache.axis.client.Call;

import org.apache.axis.client.Service;

import org.apache.axis.encoding.XMLType;

import org.apache.axis.soap.SOAPConstants;

import org.jboss.net.axis.transport.mail.client.MailTransport;

 

/**

 * Email Sample Client

 * @author <a href="mailto:jasone@greenrivercomputing.com>Jason Essington</a>

 */

public class MailClient

{

   public static final String MAIL_ENDPOINT = "jboss.net@somehost.com";

   public static final String METHOD = "echo";

   public static final String ACTION = "Echo";

   public static final String NAMESPACE = "http://org.jboss.net/SAMPLE";

 

   public static void main(String[] args) throws Exception

   {

      try

      {

         Service service = new Service();

         Call call = (Call) service.createCall();

 

         call.setOperationName(new javax.xml.namespace.QName(NAMESPACE, METHOD));

         // We must use SOAP 1.2 or our message will be rejected.

         call.setSOAPVersion(SOAPConstants.SOAP12_CONSTANTS);

         call.addParameter("inStr", XMLType.XSD_STRING, ParameterMode.IN);

         call.setReturnType(XMLType.XSD_STRING);

         MailTransport mail = new MailTransport();

         mail.setRecipient(MAIL_ENDPOINT);

         mail.setAction(ACTION);

         call.setTransport(mail);

         String ret;

         if (args.length > 0)

            ret = (String) call.invoke(new Object[] {args[0]});

         else

            ret = (String) call.invoke(new Object[] {"oops forgot to add a parameter!"});

         System.out.println(ret);

      }

      catch (Exception e)

      {

         e.printStackTrace(System.out);

      }

   }

}

 

The client starts with a few constant definitions for the endpoint, service name, method, and namespace, which would most certainly be set programmatically in real life. Be sure to set the MAIL_ENDPOINT to the email address being used by JBoss.Net.

 

The client_deploy.wsdd

The last part is some configuration for the client engine.

 

<deployment name="sample"

    xmlns="http://xml.apache.org/axis/wsdd/"

    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

  <handler name="MailSender" type="java:org.jboss.net.axis.transport.mail.client.MailSender">

    <parameter name="username" value="noone"/>

    <parameter name="password" value="password"/>

    <parameter name="timeout" value="120"/>

    <parameter name="mail.debug" value="false"/>

    <parameter name="mail.from" value="nobody@foo.bar.com"/>

    <parameter name="mail.transport.protocol" value="smtp"/>

    <parameter name="mail.user" value="nobody"/>

    <parameter name="mail.host" value="mail.wyoming.com"/>

    <parameter name="mail.store.protocol" value="pop3"/>

  </handler>

  <transport name="mail" pivot="MailSender"/>

</deployment>

 

Be sure to fill in values that are pertinent to your environment. The username and password parameters are used for authentication with the email server. The timeout parameter is the amount of time, in minutes, the client will wait for a response. All of the parameters that start with mail are javamail properties. Any valid javamail properties can be used here.

This file is used by calling Òjava org.apache.axis.utils.Admin client client_deploy.wsddÓ.

Putting it All Together

For this example to work, the client will need a different email address than JBoss.Net.

There is a build.properties file that contains lines to allow all the static fields from the client_deploy.wsdd and MailClient.java to be set in one place.

Calling ./build.sh (or build.bat) from the jboss.net/samples/mail directory will compile both the client and server parts. Move the echo.ear file (found in the output/lib dir) to the deploy directory of your configured server. Execute the client portion by calling ./build.sh runclient -Decho=ÓThis is a testÓ. The -Decho=ÓÓ part just sets the string that will be sent to the server. The build script will execute the org.apache.axis.utils.Admin command to configure the axis client engine to understand the email transport. Then it will execute the client application. Depending upon the speed of your email server, the client should receive its response within a couple of minutes.