/////////////////////////////////////////////////////////////////////////
//
// © University of Southampton IT Innovation Centre, 2004
//
// Copyright in this library belongs to the IT Innovation Centre of
// 2 Venture Road, Chilworth Science Park, Southampton, SO16 7NP, UK.
//
// This software may not be used, sold, licensed, transferred, copied
// or reproduced in whole or in part in any manner or form or in or
// on any media by any person other than in accordance with the terms
// of the Licence Agreement supplied with the software, or otherwise
// without the prior written consent of the copyright owners.
//
// This software is distributed WITHOUT ANY WARRANTY, without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE, except where stated in the Licence Agreement supplied with
// the software.
//
//      Created by:             Darren Marvin
//      Created date:           2003/10/19
//      Created for project:    GEMSS
//
/////////////////////////////////////////////////////////////////////////
//
//      Dependencies: None
//
/////////////////////////////////////////////////////////////////////////
//
//      Last commit info:       $Author: $
//                              $Date: $
//                              $Revision: $
//
/////////////////////////////////////////////////////////////////////////

package uk.ac.soton.itinnovation.gemss.transportmessaging;

import eu.gemss.components.security.token.*;
import eu.gemss.components.transport.servicedescription.*;
import eu.gemss.components.transport.servicedescription.policytypes.*;
import eu.gemss.components.transport.servicedescription.endpointtypes.*;
import eu.gemss.components.transport.servicedescription.interfacetypes.*;
import eu.gemss.signals.*;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import javax.xml.soap.SOAPMessage;
import uk.ac.soton.itinnovation.gemss.security.context.configuration.*;
import uk.ac.soton.itinnovation.gemss.signal.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.configuration.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.context.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.policytypes.*;
import uk.ac.soton.itinnovation.gemss.utils.configuration.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.endpointtypes.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.ServiceDescriptionImp;
import java.net.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.interfacetypes.*;



public class WebServiceInvocationEnforcer implements SignalHandler {

    //private static String ENFORCEMENT_LIST_FILE = "message_enforcement.xml";
    private static Logger mLogger = Logger.getLogger("uk.ac.soton.itinnovation.gemss.transportmessaging.WebServiceInvocationEnforcer");
    private TransportMessagingConfiguration mTConfig = null;
    private String mWSDLUri = null;
    private String mEndpoint = null;
    private String mPortType = null;
    private String mBinding = null;
    private String mEnforcementFile = null;
    private uk.ac.soton.itinnovation.gemss.security.context.SecurityContext mSecurityContext;


    public WebServiceInvocationEnforcer(String transportConfigDir, String securityConfigDir, String wsdlURI, String endpoint, String portType, String binding) throws TransportMessagingException {
      try{
      if(transportConfigDir==null)
        throw new TransportMessagingException("Invalid transport configuration directory supplied in configuration");
      if(securityConfigDir==null)
        throw new TransportMessagingException("Invalid security configuration directory supplied in configuration");
      if(wsdlURI==null)
        throw new TransportMessagingException("Invalid WSDL URI value supplied  in configuration");
      if(endpoint==null)
        throw new TransportMessagingException("Invalid endpoint supplied in configuration");
      if(portType==null)
        throw new TransportMessagingException("Invalid portType supplied in configuration");
      if(binding==null)
        throw new TransportMessagingException("Invalid binding supplied in configuration");
      //init(transportConfigDir,securityConfigDir, enforcementFile);
      mTConfig = new TransportMessagingConfiguration(transportConfigDir);
      mWSDLUri = wsdlURI;
      mEndpoint = endpoint;
      mPortType = portType;
      mBinding = binding;
      }
      catch(ConfigurationException ex) {
        mLogger.log(Level.SEVERE,ex.getMessage(),ex);
        throw new TransportMessagingException(ex.getMessage());
      }


    }

    public uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage encodeRequest(uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage requestMsg) throws TransportMessagingException{
        try{
            //create a message enforcer
            MessageEnforcer mEnforcer = new MessageEnforcer(mTConfig,this,false);
            //create a service description
            ServiceInterface servIntf = createServiceInterface(requestMsg.getSOAPWireMessage());
            ServiceEndpoint servEndp = new WSDLEndpointImp(new URL(mEndpoint));
            ServiceDescription servDesc = new ServiceDescriptionImp(servIntf,servEndp,mEnforcer.retrieveStaticPolicies());

            /*
            uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage msg =
                    new uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage(requestMsg,new MessageContext(tConfig));
            */
            uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage msg =
                    (uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage)
                    mEnforcer.enforceIncomingMessage(servDesc,requestMsg);
            return msg;
        }
        catch(java.net.MalformedURLException ex) {
            mLogger.log(Level.SEVERE,"Invalid WSDL URI from configuration",ex);
            throw new TransportMessagingException(ex.getMessage());
        }
        catch(ServiceDescriptionException ex) {
            mLogger.log(Level.SEVERE,"Unable to intialise server service description",ex);
            throw new TransportMessagingException("Unable to intialise server service description");
        }
        catch(TransportMessagingException ex) {
            throw new TransportMessagingException(ex.getMessage());
        }

    }

    public uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage encodeResponse(uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage responseMsg) throws TransportMessagingException {
        try{
            //create a message enforcer
            MessageEnforcer mEnforcer = new MessageEnforcer(mTConfig,this,false);

            //create a service description
            ServiceInterface servIntf = createServiceInterface(responseMsg.getSOAPWireMessage());
            ServiceEndpoint servEndp = new WSDLEndpointImp(new URL(mEndpoint));
            ServiceDescription servDesc = new ServiceDescriptionImp(servIntf,servEndp,mEnforcer.retrieveStaticPolicies());
            uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage msg =
                    (uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.SOAPMessage)
                    mEnforcer.enforceOutgoingMessage(servDesc,responseMsg);

            return msg;
        }
        catch(java.net.MalformedURLException ex) {
            mLogger.log(Level.SEVERE,"Invalid WSDL URI from configuration",ex);
            throw new TransportMessagingException(ex.getMessage());
        }
        catch(ServiceDescriptionException ex) {
            mLogger.log(Level.SEVERE,"Unable to intialise server service description",ex);
            throw new TransportMessagingException("Unable to intialise server service description");
        }
        catch(TransportMessagingException ex) {
            throw new TransportMessagingException(ex.getMessage());
        }
    }


    public void process(Signal signal) {
        //I don't like throwing RuntimeException but no clear exception strategy exists for signalling
        throw new RuntimeException("Cannot handle signal");

    }


    private ServiceInterface createServiceInterface(javax.xml.soap.SOAPMessage msg) throws TransportMessagingException, ServiceDescriptionException {
        try{
            //get the soap envelope
            javax.xml.soap.SOAPEnvelope soapEnv = msg.getSOAPPart().getEnvelope();
            javax.xml.soap.SOAPBody soapBody = soapEnv.getBody();
            //want operation name, portType and binding
            String opName = null;
            //operation name is the first child element of the body
            Iterator iterator = soapBody.getChildElements();
            while(iterator.hasNext()) {
                javax.xml.soap.SOAPElement soapE = (javax.xml.soap.SOAPElement) iterator.next();
                //should be only one, element name is opName
                opName = soapE.getElementName().getLocalName();
            }
            if(opName==null) {
                mLogger.log(Level.SEVERE,"Unable to establish the method required for SOAP message");
                throw new TransportMessagingException("Unable to establish the method required for SOAP message");
            }
            //portType and binding come from the configuration

            return new WSDL11InterfaceImp(mWSDLUri,opName,mPortType,mBinding);

        }
        catch(javax.xml.soap.SOAPException ex) {
            mLogger.log(Level.SEVERE,"Unable to establish invocation details from the SOAPMessage",ex);
            throw new TransportMessagingException("Unable to establish invocation details from the SOAPMessage");
        }


    }

}