/////////////////////////////////////////////////////////////////////////
//
// © Institute for Software Science, University of Vienna, 2004
//
// Copyright in this software belongs to Institute for Software Science, 
// University of Vienna, Nordbergstrasse 15/C/3, 1090 Vienna, Austria
//
// 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 :		Gerhard Engelbrecht
//	Created Date :		2004/04/20
//	Created for Project:	GEMSS
//
////////////////////////////////////////////////////////////////////////
//
// Dependencies: None
//
/////////////////////////////////////////////////////////////////////////
//
//	Last commit info:	$Author: gerry $
//					$Date: 2004/08/17 09:18:57 $
//					$Revision: 1.3 $
//
/////////////////////////////////////////////////////////////////////////

package at.ac.univie.iss.proxies.qos.impl;


import java.util.logging.*;

import eu.gemss.GEMSS;
import eu.gemss.components.ComponentManager;  
import eu.gemss.components.transport.*;
import eu.gemss.components.transport.payload.*; 
import eu.gemss.GridException;
import eu.gemss.components.transport.servicedescription.*;
import eu.gemss.components.transport.servicedescription.endpointtypes.*;
import eu.gemss.components.transport.servicedescription.interfacetypes.*;
import eu.gemss.components.transport.servicedescription.policytypes.*;
import eu.gemss.components.transport.servicedescription.ServiceDescriptionException;

import uk.ac.soton.itinnovation.gemss.transportmessaging.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.payload.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.payload.typedescriptions.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.endpointtypes.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.interfacetypes.*;
import uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.policytypes.*;

import at.ac.univie.iss.proxies.qos.util.PropertiesHandler;


/**
 * A client proxy corresponding to the GEMSS services
 * QoS interface. Use QoSProxyProvider to retrieve an 
 * instance form the Component Framework 
 *
 * @author Rainer Schmidt (rainer@par.univie.ac.at)
 * @author Nikolay Terziev (terziev@par.univie.ac.at)
 *	 
 * <p>WSDL properties can be overwritten using a configFile</p>
 * <p>Default values are:</p>
 * <ul>
 *   <li><code>strDefaultServiceName = "ApplicationExecuterPhaseThreeImplService"</code></li>
 *   <li><code>strDefaultEndPointPortName = "appex"</code></li>
 *   <li><code>strDefaultServicePortType = "ApplicationExecuter"</code></li>
 *   <li><code>strDefaultBinding = "appexSoapBinding"</code></li>
 *   <li><code>strDefaultReqOperation1 = "requestQoSDescriptor"</code></li>
 *   <li><code>  defaultPartNameStrReq11 = "qoSDescriptor"</li>
 *   <li><code>  defaultPartNameStrReq12 = "requestDescriptor"</code></li>
 *   <li><code>strDefaultConOperation1 = "confirmQoSDescriptor"</code></li>
 *   <li><code>  defaultPartNameStrCon11 = "qoSDescriptor"</code></li>
 *   <li><code>strDefaultCanOperation1 = "cancelQoSDescriptor"</code></li>
 *   <li><code>  defaultPartNameStrCan11 = "qosDescriptor"</code></li>
 * </ul>
 * <p>Propery names are:</p>
 * <ul>
 *   <li>WSDLURI</li>     
 * 	 <li>ServiceName</li>
 *   <li>EndPointPortName</li>
 *   <li>ServicePortType</li>
 *   <li>Binding</li>
 *   <li>requestOp1</li>
 *   <li>  requestOp1ArgName1</li>
 *   <li>  requestOp1ArgName2</li>
 *   <li>confirmOp1</li>
 *   <li>  confirmOp1ArgName1</li>
 *   <li>cancelOp1</li>
 *   <li>  cancelOp1ArgName1</li>
 * </ul>      

 */
 
final public class QoSProxyImpl implements eu.gemss.components.proxies.qos.QoSProxy {
	
    private static Logger logger = Logger.getLogger(QoSProxyImpl.class.getName());

    private PropertiesHandler properties = null;    

    private ServicePolicyImp policyContainer = null; 
    
    private String strServiceName = null;
    private String strEndPointPortName = null;
    private String strServicePortType = null;
    private String strBinding = null;
    private String wsdlEndpoint = null;
	
    public String strDefaultServiceName = "ApplicationExecuterPhaseThreeImplService";
    public String strDefaultEndPointPortName = "appex"; 
    public String strDefaultServicePortType = "ApplicationExecuter";
    public String strDefaultBinding = "appexSoapBinding";
    
    public String strDefaultReqOperation1 = "requestQoSDescriptor"; 
    public String defaultPartNameStrReq11 = "qoSDescriptor";
    public String defaultPartNameStrReq12 = "requestDescriptor";
    
    public String strDefaultConOperation1 = "confirmQoSDescriptor"; 
    public String defaultPartNameStrCon11 = "qoSDescriptor";
   	
    public String strDefaultCanOperation1 = "cancelQoSDescriptor"; 
    public String defaultPartNameStrCan11 = "qosDescriptor";
    
    ComponentManager componentManager = null;
    GEMSSTransportAndMessaging transportAndMessaging = null;
    
    private boolean useSecurityPolicyFile = false;
    
    /**
     * <p>Default constructor called by 
     * <code>cm.getInstance("eu.gemss.components.proxies.qos.QoSProxy");</code> or
     * <code>cm.getInstance(serviceRequest);</code>
     * </p>
     */
    public QoSProxyImpl() {
        this(null);
    }

    /**
     * <p>Use
     * <code>QoSProxy qosProxy = (QoSProxy) cm.getInstance(genericProxyRequest);</code> or
     * <code>QoSProxy qosProxy = (QoSProxy) cm.getInstance(gemssProxyRequest);</code>
     * </p>
     * @param propertiesFilePath to endpoint config file
     */
    public QoSProxyImpl(String propertiesFilePath) { 
			
        try {
            ComponentManager componentManager = GEMSS.getInstance();

            logger.log(Level.INFO, "GEMSS Component Manager created.");
            transportAndMessaging = (GEMSSTransportAndMessaging) componentManager.getInstance("eu.gemss.components.transport.GEMSSTransportAndMessaging");
            logger.log(Level.INFO, "GEMSS T&M created.");
            properties = new PropertiesHandler();
            properties.loadProperties(propertiesFilePath);
            wsdlEndpoint = properties.getProperty("WSDLURI");
            strServiceName = (properties.getProperty("ServiceName") != null)
                    ? properties.getProperty("ServiceName")
                    : strDefaultServiceName;
            strEndPointPortName = (properties.getProperty("EndPointPortName")
                    != null)
                    ? properties.getProperty("EndPointPortName")
                    : strDefaultEndPointPortName;
            strServicePortType = (properties.getProperty("ServicePortType")
                    != null)
                    ? properties.getProperty("ServicePortType")
                    : strDefaultServicePortType;
            strBinding = (properties.getProperty("Binding") != null)
                    ? properties.getProperty("Binding")
                    : strDefaultBinding;
                    
            useSecurityPolicyFile = (properties.getProperty("Binding") != null) 
                    ? properties.getProperty("UseSecurityPolicyFile").equals("true")
                    : true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * @param wsdlEndpoint 
     */
    public void init(String wsdlEndpoint) { // , boolean useSecureMessaging) {
        this.wsdlEndpoint = wsdlEndpoint;
        // create and set the policies required 
        policyContainer = new ServicePolicyImp();
        
        // if the service you are invoking does not use message security then you
        // should use lines in the else block below.
            
        logger.log(Level.FINE, "UseSecurityPolicyFile " + useSecurityPolicyFile + ".");
        
        if (!useSecurityPolicyFile) {
            // policyContainer.addIncomingPolicy(new	BasicBodyX509SignatureVerificationWSPolicyImp());
            // policyContainer.addOutgoingPolicy(new	BasicBodyX509SignatureCreationWSPolicyImp());
            policyContainer.addIncomingPolicy(new	BodyX509SigVerifyWSPolicyImp());
            policyContainer.addOutgoingPolicy(new	BodyX509SigCreateWSPolicyImp());
                
        } else {
            policyContainer.addIncomingPolicy(new NoPolicyImp());
            policyContainer.addOutgoingPolicy(new NoPolicyImp());
        }
            
    }
    
    /** Request a QoS offer according to specified QoS and request descriptors
     * @param qoSDescriptor (<code>QoSDescriptor.toString()</code>)
     * @param requestDescriptor (<code>RequestDescriptor.toString()</code>)
     * @return offer (<code>QoSDescriptor.toString()</code>)
     */
    public String requestQoSDescriptor(String qoSDescriptor, String requestDescriptor) {
    	
        DataItem outItem = null;
		
        try {		
			 
            String myStringVal1 = qoSDescriptor; 
            String myStringVal2 = requestDescriptor;  
            
            String strOperation = (properties.getProperty("requestOp1") != null)
                    ? properties.getProperty("requestOp1")
                    : strDefaultReqOperation1;
            String partNameStr1 = (properties.getProperty("requestOp1ArgName1")
                    != null)
                    ? properties.getProperty("requestOp1ArgName1")
                    : defaultPartNameStrReq11;
            String partNameStr2 = (properties.getProperty("requestOp1ArgName2")
                    != null)
                    ? properties.getProperty("requestOp1ArgName2")
                    : defaultPartNameStrReq12;
            
            if (wsdlEndpoint == null) {
            
                throw new Exception("The BasicQoS Component is not initialized! Please call the init() method first.");
            }
            
            // create the service description
            WSDLEndpoint wsdlEndPoint = new WSDLEndpointImp
                    (wsdlEndpoint, strServiceName, strEndPointPortName);
				
            ServiceInterface wsdlInterface = new WSDL11InterfaceImp
                    (wsdlEndpoint, strOperation, strServicePortType, strBinding);

            ServiceDescription serviceDesc = new ServiceDescriptionImp
                    (wsdlInterface, wsdlEndPoint, policyContainer);
				
            // create the input
            DataItem[] arrayDataItems = new DataItem[2];

            // PayloadException
            arrayDataItems[0] = new DataItemImpl(partNameStr1,
                    new XSDTypeDescription
                    ("", XSDTypeDescription.XSD_STRING), myStringVal1);

            arrayDataItems[1] = new DataItemImpl(partNameStr2,
                    new XSDTypeDescription
                    ("", XSDTypeDescription.XSD_STRING), myStringVal2);
			
            Payload payloadInput = new PayloadImpl(arrayDataItems);
			
            InvocationInput input = new InvocationInputImp(payloadInput);
            
            InvocationOutput output = transportAndMessaging.invokeService
                    (serviceDesc, input, useSecurityPolicyFile);

            outItem = output.getPayload().getDataItems()[0]; 
            
            return ((String) outItem.getValue());
 		
        } catch (ServiceDescriptionException sde) {
            // logger.log(Level.SEVERE, sde.toString(), sde);
            sde.printStackTrace();
               
        } catch (PayloadException pe) {
            // logger.log(Level.SEVERE, pe.toString(), pe);
            pe.printStackTrace();
   
        } catch (GridException ge) {
            // logger.log(Level.SEVERE, ge.toString(), ge);
            ge.printStackTrace();
         
        } catch (Exception e) {
            // logger.log(Level.SEVERE, e.toString(), e);
            e.printStackTrace();
             
        }
        
        return null;
    }
    
    /** Confirm (sign) a service offer
     * @param qoSDescriptor received offer (<code>QoSDescriptor.toString()</code>)
     * @return QoS contract (<code>QoSDescriptor.toString()</code>)
     */    
    public String confirmQoSDescriptor(String qoSDescriptor) {
    	 
        DataItem outItem = null;
		
        try { 
           
            String myStringVal1 = qoSDescriptor; 
            
            String strOperation = (properties.getProperty("confirmOp2") != null)
                    ? properties.getProperty("confirmOp2")
                    : strDefaultConOperation1;
            String partNameStr1 = (properties.getProperty("confirmOp2ArgName1")
                    != null)
                    ? properties.getProperty("confirmOp2ArgName1")
                    : defaultPartNameStrCon11;
 
            if (wsdlEndpoint == null) {
            
                throw new Exception("The BasicQoS Component is not initialized! Please call the init() method first.");
            }
            
            // create the service description
            WSDLEndpoint wsdlEndPoint = new WSDLEndpointImp
                    (wsdlEndpoint, strServiceName, strEndPointPortName);
				
            ServiceInterface wsdlInterface = new WSDL11InterfaceImp
                    (wsdlEndpoint, strOperation, strServicePortType, strBinding);

            ServiceDescription serviceDesc = new ServiceDescriptionImp
                    (wsdlInterface, wsdlEndPoint, policyContainer);
				
            // create the input
            DataItem[] arrayDataItems = new DataItem[1];

            arrayDataItems[0] = new DataItemImpl(partNameStr1,
                    new XSDTypeDescription
                    ("", XSDTypeDescription.XSD_STRING), myStringVal1);
 
            Payload payloadInput = new PayloadImpl(arrayDataItems);
			
            InvocationInput input = new InvocationInputImp(payloadInput);
			
            InvocationOutput output = transportAndMessaging.invokeService
                    (serviceDesc, input, useSecurityPolicyFile);

            outItem = output.getPayload().getDataItems()[0];
            
            Object retValue = outItem.getValue();

            if (retValue != null) {
                return ((String) retValue);
            } else {
                return null;
            }
 			
        } catch (ServiceDescriptionException sde) {
            logger.log(Level.SEVERE, sde.toString(), sde);
            sde.printStackTrace();
               
        } catch (PayloadException pe) {
            logger.log(Level.SEVERE, pe.toString(), pe);
            pe.printStackTrace();
   
        } catch (GridException ge) {
            logger.log(Level.SEVERE, ge.toString(), ge);
            ge.printStackTrace();
         
        } catch (Exception e) {
            logger.log(Level.SEVERE, e.toString(), e);
            e.printStackTrace();
             
        }
		
        return null; 
    }
    
    /** Inform service that a (not confirmed) service offer is rejeced
     * @param qoSDescriptor received offer (<code>QoSDescriptor.toString()</code>)
     */    
    public void cancelQoSDescriptor(String qoSDescriptor) {
    	 
        try {	 
            String myStringVal1 = qoSDescriptor; 
            
            String strOperation = (properties.getProperty("cancelOp3") != null)
                    ? properties.getProperty("cancelOp3")
                    : strDefaultConOperation1;
            String partNameStr1 = (properties.getProperty("cancelOp3ArgName1")
                    != null)
                    ? properties.getProperty("cancelOp3ArgName1")
                    : defaultPartNameStrCan11;

            if (wsdlEndpoint == null) {
            
                throw new Exception("The BasicQoS Component is not initialized! Please call the init() method first.");
            }
            
            // create the service description
            WSDLEndpoint wsdlEndPoint = new WSDLEndpointImp
                    (wsdlEndpoint, strServiceName, strEndPointPortName);
				
            ServiceInterface wsdlInterface = new WSDL11InterfaceImp
                    (wsdlEndpoint, strOperation, strServicePortType, strBinding);

            ServiceDescription serviceDesc = new ServiceDescriptionImp
                    (wsdlInterface, wsdlEndPoint, policyContainer);
				
            // create the input
            DataItem[] arrayDataItems = new DataItem[1];

            arrayDataItems[0] = new DataItemImpl(partNameStr1,
                    new XSDTypeDescription
                    ("", XSDTypeDescription.XSD_STRING), myStringVal1);
 
            Payload payloadInput = new PayloadImpl(arrayDataItems);
			
            InvocationInput input = new InvocationInputImp(payloadInput);
			
            InvocationOutput output = transportAndMessaging.invokeService
                    (serviceDesc, input, useSecurityPolicyFile);
			 			
        } catch (ServiceDescriptionException sde) {
            logger.log(Level.SEVERE, sde.toString(), sde);
            sde.printStackTrace();
               
        } catch (PayloadException pe) {
            logger.log(Level.SEVERE, pe.toString(), pe);
            pe.printStackTrace();
   
        } catch (GridException ge) {
            logger.log(Level.SEVERE, ge.toString(), ge);
            ge.printStackTrace();
         
        } catch (Exception e) {
            logger.log(Level.SEVERE, e.toString(), e);
            // e.printStackTrace(); 
        }
		
        return;
    	
    }
}
