MailTransportService.java |
/* * JBoss, the OpenSource J2EE webOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.net.axis.transport.mailto.server; import javax.mail.Flags; import javax.mail.Message; import javax.mail.MessagingException; import org.apache.axis.AxisEngine; import org.apache.axis.AxisFault; import org.apache.axis.MessageContext; import org.apache.axis.server.AxisServer; import org.jboss.net.axis.server.JMXEngineConfigurationFactory; import org.jboss.net.axis.transport.mailto.server.MailTransportServiceMBean; import org.jboss.net.axis.transport.mailto.AbstractMailTransportService; import org.jboss.net.axis.transport.mailto.MailConstants; /** * <dl> * <dt><b>Title: </b><dd>Mail Transport MBean</dd> * <p> * <dt><b>Description: </b> * <dd> * <p>This MBean is the service that polls the mail box (pop/imap) and processes any soap messages it finds there. * * <p> To define a mail transport and the transport level handlers, the jboss-net.sar/server-config.wsdd file must be * modified to include: * <pre> * <transport name="mail"> * <requestFlow> * <handler type="java:org.jboss.net.axis.transport.mail.server.handler.TargetServiceHandler"/> * </requestFlow> * <responseFlow> * <!-- response flow specific handlers can go here --> * </responseFlow> * </transport> * </pre> * * <p>To enable this service edit the jboss-net.sar/META-INF/jboss-service.xml file to include : * <pre> * <mbean code="org.jboss.net.axis.transport.mailto.server.MailTransportService" * name="jboss.net:service=MailTransport"> * <depends>jboss.net:service=Axis</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> * </pre> * * <p> If you don't want to hammer on the pollMail button from the mbean interface (jmx|web-console) then it would be * best to set up a schedule to do it for you (again in the jboss-service.xml file: * <pre> * <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> * </pre> * * <p> This transport assumes the use of <a href="http://ws.apache.org/ws-fx/addressing/">ws-addressing</a> * handlers and as such has no provision for sending a response. The addressing handler will create a new call * with the response if there is a wsa:Reply-To header. Otherwise the response will disappear into the ether * with nary a log entry. * * </dd> * </dl> * @author <a href="mailto:jasone@greenrivercomputing.com">Jason Essington</a> * @version $Revision: 1.2 $ * * @jboss.service * servicefile="jboss" * * @jmx.mbean * name="jboss.net:service=MailTransport" * description="email transport for soap messages" * extends="org.jboss.net.axis.transport.mailto.AbstractMailTransportServiceMBean" * */ public class MailTransportService extends AbstractMailTransportService implements MailTransportServiceMBean, MailConstants { // members private AxisServer server = null; private String transportName = "mailto"; /** * @return The name this transport has been given. * * @jmx.managed-attribute * description="the name of the transport for email messages" * value="mailto" */ public String getTransportName() { return this.transportName; } /** * @param name The name this transport will be known as (smtp for instance). * * @jmx.managed-attribute */ public void setTransportName(String name) { this.transportName = name; } /** override AxisServlet.getEngine() in order to redirect to * the corresponding AxisEngine. * * This is taken pretty much verbatem from the AxisServiceServlet */ public AxisServer getEngine() throws AxisFault { if (server == null) { try { server = JMXEngineConfigurationFactory.newJMXFactory(getEngineName()).getAxisServer(); } catch (NullPointerException e) { throw new AxisFault("Could not access JMX configuration factory.", e); } } return server; } /* (non-Javadoc) * @see org.jboss.net.axis.transport.mail.AbstractMailTransportService#processMessages(javax.mail.Message[]) */ protected void processMessages(Message[] msgs) { // iterate over all the messages processing them in turn. for (int i = 0; i < msgs.length; i++) { processMessage(msgs[i]); /* * we will need to delete the request messages in all cases * otherwise the inbox will just pile up with the messages that could not * be processed. * * if deleteMail is set to false then the server will respond to any valid messages repeatedly! * perhaps we should have a persistent way to remember which messages we have processed? */ if (getDeleteMail()) { try { msgs[i].setFlag(Flags.Flag.DELETED, true); } catch (MessagingException e1) { log.warn("Unable to flag the message for deletion.", e1); } } } } /** * Creates a message context that will be used while processing this request. * * @param engine Server engine * @param msg Email message * @return * @throws AxisFault */ protected MessageContext createMessageContext(AxisEngine engine, Message msg) throws AxisFault { MessageContext msgCtx = new MessageContext(engine); // set the transport msgCtx.setTransportName(transportName); // NOTE the axis servlet adds lot's more stuff than this to the message context, maybe we should too? return msgCtx; } /** * Serialize the email message body into a SOAPMessage. * @param mc MessageContext that will be used while processing this message * @param msg Email Message * @throws AxisFault if we need to abort this message (drop the context and delete the email message * with out sending a response message.) */ protected void processMessageBody(MessageContext mc, Message msg) throws AxisFault { String msgNS = null; try { org.apache.axis.Message soapMsg = new org.apache.axis.Message(msg.getInputStream(), false, msg .getContentType(), null); mc.setRequestMessage(soapMsg); } catch (Exception e) { log.warn("This message doesn't appear to be a SOAP Message,", e); } } /** * @param ctx MessageContext that is being used for processing this request * @param msg Email message that is theoretically holding a SOAP request. * @return The value of the first Message-ID header found. */ protected String processHeaders(MessageContext ctx, Message msg) throws AxisFault { // over ride this method if you need to do something funky with // the headers of the email message. String msgID = null; try { String[] msgIDs = msg.getHeader(HEADER_MESSAGE_ID); if (msgIDs != null && msgIDs.length > 0) { msgID = msgIDs[0]; } } catch (MessagingException e) { throw new AxisFault("Unable to process mail headers.", e); } return msgID; } /** * Does the actual work of making the incoming request suitable to send off to the axis engine. * * @param msg incoming email message. */ private void processMessage(Message msg) //private Message processMessage(Message msg)//, Session mail, Folder folder) { org.apache.axis.MessageContext sMsgCtx = null; org.apache.axis.Message sResMsg = null; try { // create a new soap message context sMsgCtx = createMessageContext(getEngine(), msg); // wsa can worry about the headers String msgID = processHeaders(sMsgCtx, msg); // decide if the body of our email is a soap envelope processMessageBody(sMsgCtx, msg); archiveMessage(msgID, sMsgCtx); // send it all off to the Axis Server if (log.isDebugEnabled()) log.debug("Invoking Axis Server."); getEngine().invoke(sMsgCtx); if (log.isDebugEnabled()) log.debug("Return from Axis Server."); } catch (AxisFault e) { // There is not much we can do here since we don't have the ability to send email // any faults that happened after engine.invoke should be handled by the addressingHandler's onFault() method. // any faults that happend prior to that will just be logged. log.fatal("The email message number "+msg.getMessageNumber()+" caused an AxisFault:",e); } } /** * Override this method if you need to store incoming messages.<br> * Note: If web service security handlers are in the handler chain, * the message will not have been verified/decrypted yet. * @param msgID * @param msgCtx */ protected void archiveMessage(String msgID, MessageContext msgCtx) { } }
MailTransportService.java |