/*
 *  ServerPool.java v0.10 20-DEC-1999
 *  Copyright (c) TKK/TLM/Calypso
 *  Author: Alexey Mednonogov
 */

package codec.server;

import java.io.*;
import java.util.*;

import codec.*;
import codec.adapt.*;
import codec.convert.*;
import codec.debug.*;
import codec.dyntree.*;
import codec.export.*;
import codec.orb.*;
import codec.pco.*;
import codec.server.*;
import codec.client.*;
import codec.visit.*;
import codec.build.*;

/** Class for handling Server objects. It registers and deregisters Servers
 *  located in SUT and calls Server operations. */
final public class ServerPool {

    /** Associate PCO and Server identified by IOR file location. 
     *  @param <code>asp</code> contains pSREG_RFILE PDU. */
    public static void registerRefFile(String pcoName, com.t3.ot.pco.ASP asp)
    {
        // Extract refFile from ASP:
        String refFile = AspConverter.extractRefFile(asp);

        if (refFile == null) {

			System.err.println("ServerPool::registerRefFile(): " +
				"Can't extract IOR file location from PDU.");
            AspConverter.throwFatalException(pcoName);
            return;
		}

        String ior = null;
        try {
            FileInputStream file = new FileInputStream(refFile);
            BufferedReader in = 
                new BufferedReader(new InputStreamReader(file));
            ior = in.readLine();
            file.close();
        }
        catch(IOException ex)
        {
            System.err.println("ServerPool::registerRefFile(): Can't " +
                "open file containing IOR: " + ex.getMessage());
            AspConverter.throwFatalException(pcoName);
            return;
        }

        org.omg.CORBA.Object object = null;
        try {
            object = CorbaServer.getCodecObject().getOrbGeneric().
                getORB().string_to_object(ior);
		}
        catch (org.omg.CORBA.SystemException se) { object = null; }
  
        if (object == null) {

            System.err.println("ServerPool::registerRefFile(): " +
                "Invalid IOR file format: " + refFile);
            AspConverter.throwFatalException(pcoName);
            return;
        }
        CorbaServer.getCodecObject().getCorbaObjectPool().
            deregister(pcoName);
        CorbaServer.getCodecObject().getCorbaObjectPool().
            register(object, pcoName, CorbaObject.PCO_TYPE_SERVER);

        AspConverter.throwRecoverableException(pcoName);
    }

    /** Associate PCO and Server identified by stringified IOR. 
     *  @param <code>asp</code> contains pSREG_IOR PDU. */
    public static void registerIOR(String pcoName, com.t3.ot.pco.ASP asp) {

        // Extract IOR from ASP:
        String ior = AspConverter.extractIOR(asp);

        if (ior == null) {

			System.err.println("ServerPool::registerIOR(): " +
				"Can't extract object IOR from PDU.");
            AspConverter.throwFatalException(pcoName);
            return;
		}

        org.omg.CORBA.Object object = null;
		try {
            object = CorbaServer.getCodecObject().getOrbGeneric().
                getORB().string_to_object(ior);
		}
        catch (org.omg.CORBA.SystemException se) { object = null; }

        if (object == null) {

            System.err.println("ServerPool::registerIOR(): " +
                "Invalid IOR format: " + ior);
            AspConverter.throwFatalException(pcoName);
            return;
        }
        CorbaServer.getCodecObject().getCorbaObjectPool().
            deregister(pcoName);
        CorbaServer.getCodecObject().getCorbaObjectPool().
            register(object, pcoName, CorbaObject.PCO_TYPE_SERVER);

        AspConverter.throwRecoverableException(pcoName);
    }

    /** Associate PCO and Server identified by location in Naming Service. 
     *  @param <code>asp</code> contains pSREG_NSERV PDU. */
    public static void registerNaming(String pcoName, com.t3.ot.pco.ASP asp) {

        org.omg.CORBA.Object object = null;

        // Extract location of object in Naming Service from ASP:
        String[] nsLocation = AspConverter.extractNamingContext(pcoName, asp);

		// Check whether location has been extracted successfully. If not,
		// then Tester side is already notified of that by Exception PDU:
		if (nsLocation == null) return;

        // Resolve object from the Naming Service:
        try 
        {
        org.omg.CosNaming.NameComponent[] objectName = 
            new org.omg.CosNaming.NameComponent[nsLocation.length];

        for (int i = 0; i < nsLocation.length; i++) {
            objectName[i] = new org.omg.CosNaming.NameComponent();
            objectName[i].id = nsLocation[i];
            objectName[i].kind = "";
        }
        
        object = CorbaServer.getCodecObject().getOrbGeneric().
            getNamingContext().resolve(objectName);
        }
        catch (org.omg.CosNaming.NamingContextPackage.NotFound ex)
        {
            System.err.println("ServerPool::registerNaming(): " +
                "CORBA object was not found in Naming Service.");
            AspConverter.throwFatalException(pcoName);
            return;
        }
        catch (org.omg.CosNaming.NamingContextPackage.CannotProceed ex)
        {
            System.err.println("ServerPool::registerNaming(): Could " + 
                "not proceed with registration through Naming Service.");
            AspConverter.throwFatalException(pcoName);
            return;

        }
        catch (org.omg.CosNaming.NamingContextPackage.InvalidName ex)
        {
            System.err.println("ServerPool::registerNaming(): Naming " + 
                "context extracted from PDU points to invalid name.");
            AspConverter.throwFatalException(pcoName);
            return;
        }

        if (object == null) {
            System.err.println("ServerPool::registerNaming(): " +
                "Invalid name binding.");
            AspConverter.throwFatalException(pcoName);
            return;
        }
        CorbaServer.getCodecObject().getCorbaObjectPool().
            deregister(pcoName);
        CorbaServer.getCodecObject().getCorbaObjectPool().
            register(object, pcoName, CorbaObject.PCO_TYPE_SERVER);

        AspConverter.throwRecoverableException(pcoName);
    }

    /** Invoke operation of registered Server object. If operation is not
     * declared as 'oneway', method uses asynchronous invocation and still
     * does not block. Method will respond to Tester with pREPLY PDU or
     * pRAISE PDU by itself if needed.
     * @param <code>asp</code> contains pCALL PDU. */
    public static void callOperation(String pcoName, com.t3.ot.pco.ASP asp) {

		ServantRequest servantRequest = null;
		org.omg.CORBA.Contained opAttrDef = null;
		int opAttrDefClass = 0;

        try {
			ServerCallVisitor visitor =
				new ServerCallVisitor(pcoName, asp);
			asp.accept(visitor);
			servantRequest = visitor.getServantRequest();
			opAttrDef = visitor.getOpAttrDef();
			opAttrDefClass = visitor.getOpAttrDefClass();
		}
		catch (VisitorInvalidFormat vif) {
			System.err.println("ServerPool::callOperation(): " +
                "Call PDU has invalid format. Reason: " + 
                vif.getMessage());
            AspConverter.throwFatalException(pcoName);
            return;
		}
		catch (VisitorPcoUnreg vpu) {
			System.err.println("ServerPool::callOperation(): " +
                "Call PDU is sent through unregistered PCO which " +
                "does not refer to any CORBA object.");
            AspConverter.throwFatalException(pcoName);
            return;
		}
		catch (VisitorNotServer vns) {
			System.err.println("ServerPool::callOperation(): " +
                "Call PDU is sent through registered PCO which " +
                "does not refer to Server object.");
            AspConverter.throwFatalException(pcoName);
            return;
		}
		catch (VisitorOperationUndef vou) {
			System.err.println("ServerPool::callOperation(): " +
                "Call PDU name refers to operation not found in " +
                "Interface Repository.");
            AspConverter.throwFatalException(pcoName);
            return;
		}
		catch (VisitorAttributeUndef vau) {
			System.err.println("ServerPool::callOperation(): " +
                "Call PDU name refers to attribute not found in " +
                "Interface Repository.");
            AspConverter.throwFatalException(pcoName);
            return;
		}
		catch (com.t3.ot.misc.OtException oe) {
			System.err.println("ServerPool::callOperation(): " +
                "OtException caught.");
            AspConverter.throwFatalException(pcoName);
            return;
		}

        org.omg.CORBA.Request request = servantRequest.getRequest();

        // Invoke operation (i.e. perform DII invocation):
        if ((opAttrDefClass == ServerCallVisitor.DEF_OPERATION) &&
			(((org.omg.CORBA.OperationDef) opAttrDef).mode() == 
			 org.omg.CORBA.OperationMode.OP_ONEWAY)) {

            // Operation mode is declared as oneway:
            request.send_oneway();
            return;
        }

        // Operation mode is declared as normal, performing
        // asynchronous invocation:
        request.send_deferred();
		CodecObject codec = CorbaServer.getCodecObject();
        codec.getServantRequestPool().register(servantRequest);
    }

    /** Handle the operation response from Server object. Method will respond
     *  to Tester with pREPLY PDU or pRAISE PDU by itself if needed. */
    public static void operResponse(ServantRequest servantRequest) {

		ServerReplyBuilder builder = new ServerReplyBuilder();
		builder.construct(servantRequest);
		AspConverter.sendASP(servantRequest.getPcoName(), builder.getAsp());
    }
}
