/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software License
 * version 1.1, a copy of which has been included with this distribution in
 * the docs/licenses/apache-1.1.txt file.
 */
package org.jboss.net.axis.message.addressing.handler;

import org.apache.axis.EngineConfiguration;
import org.apache.axis.MessageContext;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.message.addressing.Action;
import org.apache.axis.message.addressing.AddressingHeaders;
import org.apache.ws.axis.security.WSDoAllConstants;
import org.jboss.net.axis.server.JMXEngineConfigurationFactory;

import java.util.StringTokenizer;
import java.util.Vector;

/**
 * <dl>
 * <dt><b>Title: </b><dd>WS-Addressing Handler</dd>
 * <p/>
 * <dt><b>Description: </b><dd>This Subclass of the org.apache.axis.message.addressing.handler.AddressingHandler will
 * properly use the wsa:Action header to direct the incoming messages to the proper services. It also
 * correctly fetches the client config when sending a response via the ReplyTo header. wss4j properties are also
 * moved into the new request (server response) so encryption / signing can happen after addressing.<p>
 * <p/>
 * This handler can be placed in the global (or transport) request and response chains to handle messages with ws-addressing
 * headers. For added security, have the ws-security (wss4j) handlers sign any ws-addressing headers that contain addresses
 * (To, From, ReplyTo, FaultTo). This means that wss4j will have to process incoming messages BEFORE addressing, and it will
 * have to process outgoing messages AFTER addressing.
 * <p/>
 * The parameters transportPackages, and transports can be configured in the DD to allow the response objects to
 * understand any special transports that may be in use. @see #initializeCall()
 * </dd>
 * <p/>
 * <dt><b>Copyright: </b><dd>Copyright (c) 2004</dd>
 * <dt><b>Company: </b><dd>Green River Computing Services</dd>
 * </dl>
 *
 * @author <a href="mailto:jasone@greenrivercomputing.com">Jason Essington</a>
 * @version $Revision: 1.1.6.3 $
 */
public class AddressingHandler extends org.apache.axis.message.addressing.handler.AddressingHandler
{
   /* (non-Javadoc)
    * @see org.apache.axis.Handler#init()
    */
   public void init()
   {
      super.init();
      initializeCall();
   }

   /**
    * Invokes the static addTransportPackage, and setTransportForProtocol methods on Call
    * so that our transport will be recognised.<p>
    * Add transportPackages with the option addTransportPackages, and a comma separated list of packages<br>
    * &lt;parameter name="transportPackages" value="com.some.transport,com.some.other.transport"/&gt;<p>
    * <p/>
    * Add transports with a comma separated list of transportName:transportClassName<br>
    * &lt;parameter name="transports" value="http:com.my.transport.http.HTTPTransport,mail:com.my.transport.mail.MailTransport"/&gt;
    */
   private void initializeCall()
   {
      String transportPackages = null; //(String) getOption("transportPackages");
      if (transportPackages != null)
      {
         StringTokenizer t = new StringTokenizer(transportPackages, ",");
         while (t.hasMoreTokens())
         {
            Call.addTransportPackage(t.nextToken().trim());
         }
      }

      String transports = null; //(String) getOption("transports");
      if (transports != null)
      {
         StringTokenizer t = new StringTokenizer(transports, ",");
         while (t.hasMoreTokens())
         {
            String tToken = t.nextToken().trim();
            String[] transport = new String[2];

            if (tToken.indexOf(':') < 0 || tToken.indexOf(':') != tToken.lastIndexOf(':'))
            {
               log.warn(tToken + " is not in the proper form of [transport]:[class]");
               continue;
            }
            else
            {
               transport[0] = tToken.substring(0, tToken.indexOf(':'));
               transport[1] = tToken.substring(tToken.indexOf(':') + 1);
            }

            String tName = transport[0];
            String tClassName = transport[1];
            Class tClass = null;
            try
            {
               tClass = Class.forName(tClassName);
            }
            catch (ClassNotFoundException e)
            {
               log.warn("Unable to locate the class " + tClassName + " for the transport " + tName);
               continue;
            }
            Call.setTransportForProtocol(tName, tClass);
         }
      }
   }

   /* (non-Javadoc)
    * @see org.apache.axis.message.addressing.handler.AddressingHandler#configureCall(org.apache.axis.client.Call, org.apache.axis.MessageContext)
    */
   protected void configureCall(Call call, MessageContext msgContext)
   {
      // TODO Auto-generated method stub
      //super.configureCall(call, msgContext);
      
      // WSS4J expects to find the results of processing the incoming message when processing the response.
      if (msgContext != null)
      {
         Vector wssResults = null;
         wssResults = (Vector)msgContext.getProperty(WSDoAllConstants.RECV_RESULTS);
         call.setProperty(WSDoAllConstants.RECV_RESULTS, wssResults);
      }
   }

   /* (non-Javadoc)
    * @see org.apache.axis.message.addressing.handler.AddressingHandler#getService(org.apache.axis.MessageContext)
    */
   protected Service getService(MessageContext msgContext)
   {
      String engineName = null; //(String)getOption("engineName");
      EngineConfiguration config = JMXEngineConfigurationFactory.newJMXFactory(engineName)
              .getClientEngineConfig();
      return new Service(config);
   }

   /**
    * We set the target service based upon the Action header since email addresses don't have
    * path attributes.
    */
   protected void setTargetService(MessageContext msgCtx, AddressingHeaders headers) throws Exception
   {
      if (log.isDebugEnabled())
         log.debug("Entering: invoke(MessageContext)");
      Action action = headers.getAction();

      if (action != null)
      {
         String actionURI = null; //action.toString();
         msgCtx.setUseSOAPAction(true);
         msgCtx.setSOAPActionURI(actionURI);
         msgCtx.setTargetService(actionURI);
      }
      else
      {
         // fault ?
      }
   }
}