/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.net.axis.transport.mailto.client;

import org.apache.axis.AxisFault;
import org.apache.axis.MessageContext;
import org.apache.axis.message.addressing.AddressingHeaders;
import org.apache.axis.message.addressing.Constants;
import org.apache.axis.message.addressing.MessageID;

/**
 * <dl>
 * <dt><b>Title: </b><dd>Client Side Email Transport</dd>
 * <p>
 * <dt><b>Description: </b><dd>This transport uses the asynchronous capabilities of axis to send a request. This
 * transport works in cooperation with the AsyncMailClientService. The call is created in the normal way, but rather than
 * issuing a call.invoke() the call is passed to the AsyncMailClinetService along with a callback, and its arguments.
 * the service starts a new thread that invokes the call. The call progresses normally until it gets to the transport
 * (here) where the request is sent, but then the thread is put to sleep. The AsyncMailClientService keeps a reference
 * to the MessageContext of every message it has sent. Every so often, the service checks the inbox for messages that
 * correlate to ones it has sent. When it finds one of these response messages, it adds it to the corresponding
 * message context, and notifies the thread. If the thread wakes up on it's own, it assumes that no response has been
 * received and faults.</dd>
 * <p>
 * </dl>
 * @author <a href="mailto:jasone@greenrivercomputing.com">Jason Essington</a>
 * @version $Revision: 1.1.4.2 $
 */
public class AsyncMailSender extends BaseMailSender
{

   public static final String TIMEOUT = "Timeout";
   public static final long DEFAULT_TIMEOUT = 1800000; // 30 minutes

   protected long getTimeout()
   {
      long timeout = DEFAULT_TIMEOUT;
      String to = (String) getOption(TIMEOUT);
      if (to != null)
      {
         try
         {
            timeout = Long.parseLong(to) * 60 * 1000;
         } catch (NumberFormatException e)
         {
            // this isn't really a big deal, we have a default timeout
            log.warn(to + "is not a valid number we will use 30 minutes instead.", e);
         }
      }
      return timeout;
   }

   private String getMessageID(MessageContext ctx)
   {
      String id = "no message-id";
      
      if (ctx.containsProperty(Constants.ENV_ADDRESSING_REQUEST_HEADERS))
      {
         AddressingHeaders headers = (AddressingHeaders) ctx.getProperty(Constants.ENV_ADDRESSING_REQUEST_HEADERS);
         MessageID msgid = headers.getMessageID();
         if (msgid != null)
         {
            id = msgid.toString();
         }
      }
      return id;
   }

   /**
    * Instead of checking mail, we'll just go to sleep, and when we wake up, hopefully a response message will have
    * appeared in our message context.
    * Really the response handling is done in the AsyncMailClientService
    */
   protected void checkResponse(MessageContext ctx) throws AxisFault
   {
      String id = getMessageID(ctx);
      
      if (log.isDebugEnabled())
         log.debug("Entering: checkResponse [" + id + "]");

      try
      {
         // nap time . . .
         Thread.sleep(getTimeout());

         // Whoa, nobody woke us up! Better pitch a fit.
         if (log.isDebugEnabled())
            log.debug("This request " + id + " timed out.");
         throw new AxisFault("Request Timed Out");
      }
      catch (InterruptedException e)
      {
         // O.K. I'm awake, *YAWN*
         if (log.isDebugEnabled())
            log.debug("The request " + id + " received a response.");
         
         //TODO Now we should be in State.Success. Maybe we should check for that?
      }
      if (log.isDebugEnabled())
         log.debug("Leaving: checkResponse [" + id + "]");
   }
}
