/////////////////////////////////////////////////////////////////////////
//
// © 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:             Stuart E. Middleton
//      Created date:           2004/06/03
//      Created for project:    GEMSS
//
/////////////////////////////////////////////////////////////////////////
//
//      Dependencies: ISS original ApplicationExecuter source code, of
//      which ISS handler code is still used. See below for old copyright
//      header.
//
/////////////////////////////////////////////////////////////////////////
//
//      Last commit info:       $Author: $
//                              $Date: $
//                              $Revision: $
//
/////////////////////////////////////////////////////////////////////////

/*
  Copyright 2004 Institute for Software Science, University of Vienna, Austria

  This file is part of GGS (GEMSS Grid System).

  GGS is free software; you can redistribute it and/or modify
  it under the terms of the GNU Lesser Public License as published by
  the Free Software Foundation; either version 2.1 of the License, or
  (at your option) any later version.

  GGS 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 Public License for more details.

  You should have received a copy of the GNU Lesser Public License
  along with Foobar; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Author(s):	Gerhard Engelbrecht
  Date:        	2004/04/20

  Commit:		$Author: sem $
  				$Date: 2004/08/06 15:26:32 $
  				$Revision: 1.1.2.2 $
*/

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

import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.activation.DataHandler;

import at.ac.univie.iss.service.app.AppHandler;
import at.ac.univie.iss.service.qos.QoSHandler;
import at.ac.univie.iss.service.recovery.RecoveryHandler;
import at.ac.univie.iss.service.*;
import at.ac.univie.iss.service.global.ServiceInfo;

import java.net.URL;
import java.lang.ClassLoader;
import javax.naming.InitialContext;
import javax.naming.Context;
import java.util.Hashtable;
import java.util.Enumeration;
import uk.ac.soton.itinnovation.gemss.server.Negotiation;
import uk.ac.soton.itinnovation.gemss.server.NegotiationHandlerFactory;
import uk.ac.soton.itinnovation.gemss.negotiation.*;


/**
*	The <code>ApplicationExcecuter</code> class provides all service methods
*	that are exposed as WSDL operations in a standard web service hosting
*	environment (e.g. Jakarta Tomcat). An instance of this class can be seen
*	as entry point to a web service (c.f. remote class in Java RMI).
*	<p>
*	The <code>ApplicationExcecuter</code> class provides all methods a client
*	may use via SOAP. This includes the following operations:
*	<ul>
*	<li>upload input data</li>
*	<li>start native application</li>
*	<li>download output data</li>
*	<li>status-queries</li>
*	<li>kill a native application</li>
*	<li>QoS negotiation (if supported)</li>
*	<li>Recovery operations (if supported)</li>
*	</ul>
*
*	@author Gerhard Engelbrecht
*/
final public class ApplicationExecuter implements ApplicationService, QoS, Recovery, Negotiation {

      private static Logger logger = null;
      private AppHandler appHandler = null;
      private QoSHandler qosHandler = null;
      private RecoveryHandler recoveryHandler = null;
      private boolean qosSupported = false;
      private boolean recoverySupported = false;

	// IT Innov neg handler
	private NegotiationHandler mNegHandler = null;
	private boolean mbNegSupported = false;

	/**
	*	Creates a new <code>ApplicationExecuter</code> instance. This standard
	*	constructor is needed for each web application and it is executed on
	*	the first request (method invocation) of a client.
	*	<p>
	*	Internally this constructor tries to create appropriate handlers for
	*	basic application handling (<code>AppHandler</code>) and for QoS
	*	support (<code>QoSHandler</code>). If no QoS is supported the
	*	invocation of a QoS method (e.g. <code>requestQoSDescirptor</code>)
	*	throws an Exception.
	*/
	public ApplicationExecuter() throws RemoteException {

		try {
                  logger = ServiceInfo.getLogger("ApplicationExecuter"); // TODO sort out server side logging
                  logger.log(Level.INFO, "Started.\n");

                  // Initialize basic application handler

                  HandlerFactory appHandlerFactory = HandlerFactory.getInstance("at.ac.univie.iss.service.app.AppHandler");
                  appHandler = (AppHandler)appHandlerFactory.getHandler();

                  // Trying to initialize QoS handler

                  try {
                        HandlerFactory qosHandlerFactory = HandlerFactory.getInstance("at.ac.univie.iss.service.qos.QoSHandler");
                        qosHandler = (QoSHandler)qosHandlerFactory.getHandler();
                        qosHandler.setAppHandler(appHandler);
						logger.log(Level.INFO, "Quality of Service enabled\n");
                        qosSupported = true;
                  }
                  catch (ClassNotFoundException cnfException) {
                        // QoSHandlerFactory not found --> i.e. no Quality of Service supported!
                        logger.log(Level.INFO, "This service does not support Quality of Service methods.\n");
                        logger.log(Level.FINEST, "An error occurs while trying to load QoSHandler implementation.\n", cnfException);
                  }
                  catch (Exception qosException) {
                        logger.log(Level.WARNING, "An error occurs while trying to initialize the QoS support (see details below).\n", qosException);
                  }

                  // Trying to initialize Recovery handler

                  try {
                        HandlerFactory recoveryHandlerFactory = HandlerFactory.getInstance("at.ac.univie.iss.service.qos.RecoveryHandler");
                        recoveryHandler = (RecoveryHandler)recoveryHandlerFactory.getHandler();
						logger.log(Level.INFO, "Error recovery enabled\n");
                        recoverySupported = true;
                  }
                  catch (ClassNotFoundException cnfException) {
                        // RecoveryHandlerFactory not found --> i.e. no Recovery supported!
                        logger.log(Level.INFO, "This service does not support Recovery methods.\n");
                        logger.log(Level.FINEST, "An error occurs while trying to load RecoveryHandler implementation.\n", cnfException);
                  }
                  catch (Exception recoveryException) {
                        logger.log(Level.WARNING, "An error occurs while trying to initialize the Recovery support (see details below).\n", recoveryException);
                  }

                  // Trying to initialize Negotiation handler

                  try {
                        InitialContext initCtx;
                        Context envCtx;
                        String strConfig;

                        initCtx = new InitialContext();
                        envCtx = (Context) initCtx.lookup("java:comp/env");
                        strConfig = (String)envCtx.lookup("negConfig");
                        //String strConfig="/usr/local/gemss/appserver/gsel/gspf/resources/service/gemss/services/TestServiceITInnov/neghandler.config";

                        logger.log( Level.INFO,"Server: Neg server config URL = "+strConfig );

                        HandlerFactory negHandlerFactory = HandlerFactory.getInstance("uk.ac.soton.itinnovation.gemss.server.NegotiationHandler");
                        mNegHandler = (NegotiationHandler) negHandlerFactory.getHandler();
                        if( !qosSupported ) {
                              mNegHandler.init( strConfig, null );
                        }
                        else {
                              mNegHandler.init( strConfig, qosHandler );
                        }

						logger.log( Level.INFO, "Negotiation enabled\n" );
                        mbNegSupported = true;
                  }
			catch (ClassNotFoundException cnfException) {
                        // NegotiationHandler not found --> i.e. no negotiation supported!
                        logger.log(Level.INFO, "This service does not support qos negotiation methods.\n");
                        logger.log(Level.FINEST, "An error occurs while trying to load NegotiationHandler implementation.\n", cnfException);
			}
                  catch (Exception negException) {
                        logger.log(Level.WARNING, "An error occurs while trying to initialize the qos negotiation support (see details below).\n", negException);
                  }
            }
            catch (Throwable th) {
                  logger.log(Level.SEVERE, "An unrecoverable error occured!\n", th);
                  throw (new RemoteException("ApplicationExecuter failed!", th));
            }
      }

	public String getCId() throws RemoteException { return null; } // needed for old ApplicationService interface

      // ISS QoS management operations

      public String requestQoSDescriptor(String qoSDescriptor, String requestDescriptor) throws RemoteException {
            logger.log(Level.FINEST, "Started.\n");

            if (qosSupported) {
                  return qosHandler.requestQoSDescriptor(qoSDescriptor, requestDescriptor);
            }
            throw (new RemoteException("This service does NOT provide QoS support!"));
      }

      public String confirmQoSDescriptor(String qoSDescriptor) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            if (qosSupported) {
                  return qosHandler.confirmQoSDescriptor(qoSDescriptor);
            }
            throw (new RemoteException("This service does NOT provide QoS support!"));
      }

      public void cancelQoSDescriptor(String qoSDescriptor) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            if (qosSupported) {
                  qosHandler.cancelQoSDescriptor(qoSDescriptor);
                  return;
            }
            throw (new RemoteException("This service does NOT provide QoS support!"));
      }

      // Job handling operations

      public void upload(String cid, byte[] data) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						qosHandler.upload(cid, data);
						return;
					}
				}
			}

			// try app handler
            appHandler.upload(cid, data);
      }

      public byte[] download(String cid, String fileName) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						return qosHandler.download(cid, fileName);
					}
				}
			}

			// try app handler
            return appHandler.download(cid, fileName);
	  }

      public void uploadAttachment(String cid, DataHandler dataHandler) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						qosHandler.uploadAttachment(cid, dataHandler);
						return;
					}
				}
			}

			// try app handler
            appHandler.uploadAttachment(cid, dataHandler);
      }

      public DataHandler downloadAttachment(String cid, String fileName) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						return qosHandler.downloadAttachment(cid, fileName);
					}
				}
			}

			// try app handler
            return appHandler.downloadAttachment(cid, fileName);
      }

      public void uploadString(String cid, String data) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						qosHandler.uploadString(cid, data);
						return;
					}
				}
			}

			// try app handler
            appHandler.uploadString(cid, data);
	  }

      public String downloadString(String cid, String fileName) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						return qosHandler.downloadString(cid, fileName);
					}
				}
			}

			// try app handler
            return appHandler.downloadString(cid, fileName);
      }

      public void start(String cid) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						logger.log(Level.INFO, "QoS handler start called\n");
						qosHandler.start(cid);
						return;
					}
				}
				else logger.log(Level.INFO, "contract not agreed !! using app handler\n");
			}

			// try app handler
            logger.log(Level.INFO, "app handler start called\n");
            appHandler.start(cid);
      }

      public void kill(String cid) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						qosHandler.kill(cid);
						return;
					}
				}
			}

			// try app handler
            appHandler.kill(cid);
      }

      public byte[] getStatus(String cid) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						return qosHandler.getStatus(cid);
					}
				}
			}

			// try app handler
            return appHandler.getStatus(cid);
      }

      public String getStatusAsString(String cid) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						return qosHandler.getStatusAsString(cid);
					}
				}
			}

			// try app handler
            return appHandler.getStatusAsString(cid);
      }

      public void acknowledgeResults(String cid) throws RemoteException {
			boolean bOk;
			String strJobConvID, strNegID;

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

			// use qos handler if there is a WSLA contract agreed
			bOk = false;
			if( mbNegSupported ) {
				if( mNegHandler.queryContractAgreed( cid ) ) {
					if( qosSupported ) {
						qosHandler.acknowledgeResults(cid);
						bOk = true;
					}
				}
			}

			// try app handler
            if( !bOk ) appHandler.acknowledgeResults(cid);

			// delete neg and job conversations
		    try
		    {
			  // get the Neg ID from this job ID
			  // TODO replace delete job and neg comv code with calls to Auth
			  strJobConvID = cid;
			  if( strJobConvID.length() < 1 ) throw new Exception("Invalid job ID");
			  if( strJobConvID.indexOf("--") == -1 || strJobConvID.indexOf("--") == strJobConvID.length() ) throw new Exception("Invalid job ID (parse)");
			  strNegID = strJobConvID.substring( strJobConvID.indexOf("--")+2 );
			  logger.log( Level.INFO,"Removing both neg ID "+strNegID+" and job ID "+strJobConvID+" now we are finished with them" );

			  // delete conversation ID's
              mNegHandler.deleteConversation( strJobConvID );
              mNegHandler.deleteConversation( strNegID );
		    }
            catch( RemoteException rex ) {
                  logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
                  throw rex; // rethrow new Remote exceptions generated by the neg handler
            }
            catch ( Throwable th )
            {
                  logger.log( Level.SEVERE,"Invocation: Throwable",th);
                  throw new RemoteException( "Major application executer failure (server side)",th );
            }
      }

      public void restart(String cid) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

            if (recoverySupported) {
                  recoveryHandler.restart(cid);
            }
      }

      public DataHandler checkpointDownloadAttachment(String cid, String fileName) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

            if (recoverySupported) {
                  return recoveryHandler.checkpointDownloadAttachment(cid, fileName);
            }
            return null;
      }

      public void checkpointUploadAttachment(String cid, DataHandler dataHandler) throws RemoteException {

            logger.log(Level.FINEST, "Started.\n");

            // conversation authorization check
            if( !queryAuthorization( cid ) ) throw new RemoteException("Authorization failed for conversation "+cid);

            if (recoverySupported) {
                  recoveryHandler.checkpointUploadAttachment(cid, dataHandler);
            }
      }

      // IT Innovation QoS negotiation operations

	/* return a job ID given a neg ID.
	 * TODO at present the neg conv ID state is deleted. This should be replaced later in project.
	 * @param strNegConvID negotiation conv ID
	 * @return job ID or null if none available
	 */
      public String getJobCID( String strNegConvID ) throws RemoteException
      {
		String strID;
            try
            {
                  logger.log( Level.INFO,"Invocation: getJobCID "+strNegConvID);
                  strID = mNegHandler.getJobCID( strNegConvID );

				  // return new job ID
                  return strID;
            }
            catch( RemoteException rex ) {
                  logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
                  throw rex; // rethrow new Remote exceptions generated by the neg handler
            }
            catch ( Throwable th )
            {
                  logger.log( Level.SEVERE,"Invocation: Throwable",th);
                  throw new RemoteException( "Major application executer failure (server side)",th );
            }
      }

      /* return a negotiation ID given an account ID
      * @param strAccountConvID account conv ID
      * @return neg ID or null if none available
      */
      public String getNegCID( String strAccountConvID ) throws RemoteException
      {
            try
		{
			logger.log( Level.INFO,"Invocation: getNegCID "+strAccountConvID);
			return mNegHandler.getNegCID( strAccountConvID );
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
      }

	/* return the WSLA template for this service
	 * @param strNegConvID negotiation conv ID
	 * @return wsla template in string format, or null on error
	 */
      public String getWSLA(String strNegConvID) throws RemoteException
	{
		String strWSLA;

		// conversation authorization check
		if( !queryAuthorization( strNegConvID ) ) throw new RemoteException("Authorization failed for conversation "+strNegConvID);

		try
		{
			logger.log( Level.INFO,"Invocation: getWSLA "+strNegConvID+" for service "+ServiceInfo.getServiceName());
			if( !mNegHandler.queryAuthorization( strNegConvID ) ) throw new RemoteException("Unauthorized conversation "+strNegConvID);
			strWSLA = mNegHandler.getWSLA( strNegConvID,ServiceInfo.getServiceName() );
			return strWSLA;
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
      }

	/* upload the request desc file
	 * @param strNegConvID negotiation conv ID
	 * @param dataHandler data handler from which file can be obtained
	 */
      public void uploadRequestDesc(String strNegConvID, DataHandler dataHandler) throws RemoteException {
		// conversation authorization check
		if( !queryAuthorization( strNegConvID ) ) throw new RemoteException("Authorization failed for conversation "+strNegConvID);

		try
		{
			logger.log( Level.INFO,"Invocation: uploadRequestDesc "+strNegConvID+", filename "+dataHandler.getName());
                  mNegHandler.uploadRequestDesc( strNegConvID,dataHandler.getName() );
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
      }

	/* process an auction inform message (starts the auction)
	 * @param strNegConvID negotiation conv ID
	 * @param arrayMessage FIPA mesage string as a byte array (base64binary used for transport encoding but decoded at this stage)
	 */
      public void auctionInform( String strNegConvID, byte[] arrayMessage ) throws RemoteException
	{
		String strMessage;
		byte[] arrayBytes;

		// conversation authorization check
		if( !queryAuthorization( strNegConvID ) ) throw new RemoteException("Authorization failed for conversation "+strNegConvID);

		try
		{
			logger.log( Level.INFO,"Invocation: auctionInform "+strNegConvID);
			if( !mNegHandler.queryAuthorization( strNegConvID ) ) throw new RemoteException("Unauthorized conversation "+strNegConvID);
			strMessage = new String( arrayMessage );
			mNegHandler.auctionInform( strNegConvID, strMessage );
			return;
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
      }

	/* process an auction cfp message (call for proposals)
	 * @param strNegConvID negotiation conv ID
	 * @param arrayMessage FIPA mesage string as a byte array (base64binary used for transport encoding but decoded at this stage)
	 */
	public void auctionCFP( String strNegConvID, byte[] arrayMessage ) throws RemoteException
	{
		String strMessage;

		// conversation authorization check
		if( !queryAuthorization( strNegConvID ) ) throw new RemoteException("Authorization failed for conversation "+strNegConvID);

		try
		{
			logger.log( Level.INFO,"Invocation: auctionCFP "+strNegConvID);
			strMessage = new String( arrayMessage );
			mNegHandler.auctionCFP( strNegConvID, strMessage );
			return;
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
	}

	/* process an auction propose message (i.e. collect proposal from client)
	 * @param strNegConvID negotiation conv ID
	 * @return byte array containing the WSLA proposal as a string
	 */
	public byte[] auctionPropose( String strNegConvID ) throws RemoteException
	{
		String strWSLA;

		// conversation authorization check
		if( !queryAuthorization( strNegConvID ) ) throw new RemoteException("Authorization failed for conversation "+strNegConvID);

		try
		{
			logger.log( Level.INFO,"Invocation: auctionPropose "+strNegConvID);
			strWSLA = mNegHandler.auctionPropose( strNegConvID );

			return strWSLA.getBytes();
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
	}

	/* process an auction accept proposal message (i.e. accept a proposal if it's still valid)
	 * @param strNegConvID negotiation conv ID
	 * @param arrayMessage FIPA mesage string as a byte array (base64binary used for transport encoding but decoded at this stage)
	 */
	public void auctionAcceptProposal( String strNegConvID, byte[] arrayMessage ) throws RemoteException
	{
		String strMessage;

		// conversation authorization check
		if( !queryAuthorization( strNegConvID ) ) throw new RemoteException("Authorization failed for conversation "+strNegConvID);

		try
		{
			logger.log( Level.INFO,"Invocation: auctionAcceptProposal "+strNegConvID);
			strMessage = new String( arrayMessage );
			mNegHandler.auctionAcceptProposal( strNegConvID, strMessage );
			return;
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
	}

	/* process an auction reject proposal message (i.e. reject proposal and finish auction)
	 * @param strNegConvID negotiation conv ID
	 * @param arrayMessage FIPA mesage string as a byte array (base64binary used for transport encoding but decoded at this stage)
	 */
	public void auctionRejectProposal( String strNegConvID, byte[] arrayMessage ) throws RemoteException
	{
		String strMessage;

		// conversation authorization check
		if( !queryAuthorization( strNegConvID ) ) throw new RemoteException("Authorization failed for conversation "+strNegConvID);

		try
		{
			logger.log( Level.INFO,"Invocation: auctionRejectProposal "+strNegConvID);
			strMessage = new String( arrayMessage );
			mNegHandler.auctionRejectProposal( strNegConvID, strMessage );

                  // delete old neg conversation. This will not normally be deleted here, rather all neg and account
                  // conversations will be deleted by acknowledge results. However, at this stage of the project it
                  // needs to be deleted here.
                  mNegHandler.deleteConversation( strNegConvID );

			return;
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
	}

	/* process an auction request message (i.e. exchange contarcts after an excepted bid)
	 * @param strNegConvID negotiation conv ID
	 * @param arrayMessage FIPA mesage string as a byte array (base64binary used for transport encoding but decoded at this stage)
	 * @return byte array containing a signed WSLA proposal
	 */
	public byte[] auctionRequest( String strNegConvID, byte[] arrayMessage ) throws RemoteException
	{
		String strSignedWSLA, strMessage;

		// conversation authorization check
		if( !queryAuthorization( strNegConvID ) ) throw new RemoteException("Authorization failed for conversation "+strNegConvID);

		try
		{
			logger.log( Level.INFO,"Invocation: auctionRequest "+strNegConvID);
			strMessage = new String( arrayMessage );
			strSignedWSLA = mNegHandler.auctionRequest( strNegConvID, strMessage );
			return strSignedWSLA.getBytes();
		}
		catch( RemoteException rex ) {
			logger.log( Level.SEVERE,"Invocation: Remote exception ",rex);
			throw rex; // rethrow new Remote exceptions generated by the neg handler
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"Invocation: Throwable",th);
			throw new RemoteException( "Major application executer failure (server side)",th );
		}
	}

	// method to check authorization. This just checks conversation exists. Later this will invoke the conversation
	// authorization module.
	private boolean queryAuthorization( String strConvID )
	{
		try
		{
			return mNegHandler.queryAuthorization( strConvID );
		}
		catch ( Throwable th )
		{
			logger.log( Level.SEVERE,"queryAuthorization failed",th);
			return false;
		}
	}
}
