/*
 * @(#)POALocalCRDImpl.java	1.25 05/11/17
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.sun.corba.se.impl.protocol;

import org.omg.CORBA.SystemException;
import org.omg.CORBA.OBJ_ADAPTER ;
import org.omg.CORBA.UNKNOWN ;
import org.omg.CORBA.CompletionStatus ;

import org.omg.CORBA.portable.ServantObject;

import com.sun.corba.se.pept.protocol.ClientRequestDispatcher;

import com.sun.corba.se.spi.protocol.LocalClientRequestDispatcher;
import com.sun.corba.se.spi.protocol.LocalClientRequestDispatcherFactory;
import com.sun.corba.se.spi.protocol.ForwardException ;

import com.sun.corba.se.spi.oa.ObjectAdapter;
import com.sun.corba.se.spi.oa.OAInvocationInfo ;
import com.sun.corba.se.spi.oa.OADestroyed;

import com.sun.corba.se.spi.orb.ORB;

import com.sun.corba.se.spi.ior.IOR ;

import com.sun.corba.se.spi.logging.CORBALogDomains ;

import com.sun.corba.se.impl.logging.POASystemException ;
import com.sun.corba.se.impl.logging.ORBUtilSystemException ;

public class POALocalCRDImpl extends LocalClientRequestDispatcherBase
{
    private ORBUtilSystemException wrapper ;
    private POASystemException poaWrapper ;

    public POALocalCRDImpl( ORB orb, int scid, IOR ior)
    {
	super( (com.sun.corba.se.spi.orb.ORB)orb, scid, ior );
	wrapper = ORBUtilSystemException.get( orb, 
	    CORBALogDomains.RPC_PROTOCOL ) ;
	poaWrapper = POASystemException.get( orb, 
	    CORBALogDomains.RPC_PROTOCOL ) ;
    }

    private OAInvocationInfo servantEnter( ObjectAdapter oa ) throws OADestroyed
    {
	oa.enter() ;

	OAInvocationInfo info = oa.makeInvocationInfo( objectId ) ;
	orb.pushInvocationInfo( info ) ;

	return info ;
    }

    private void servantExit( ObjectAdapter oa ) 
    {
	try {
	    oa.returnServant();
	} finally {
	    oa.exit() ;
	    orb.popInvocationInfo() ; 
	}
    }

    // Look up the servant for this request and return it in a 
    // ServantObject.  Note that servant_postinvoke is always called
    // by the stub UNLESS this method returns null.  However, in all
    // cases we must be sure that ObjectAdapter.getServant and
    // ObjectAdapter.returnServant calls are paired, as required for
    // Portable Interceptors and Servant Locators in the POA.
    // Thus, this method must call returnServant if it returns null.
    public ServantObject servant_preinvoke(org.omg.CORBA.Object self,
                                           String operation,
                                           Class expectedType) 
    {
	ObjectAdapter oa = oaf.find( oaid ) ;
	OAInvocationInfo info = null ;

	try {
	    info = servantEnter( oa ) ;
	    info.setOperation( operation ) ;
        } catch ( OADestroyed ex ) {
            // Destroyed POAs can be recreated by normal adapter activation.
            // So just reinvoke this method.
            return servant_preinvoke(self, operation, expectedType);
	}

        try {
	    try {
		oa.getInvocationServant( info );
		if (!checkForCompatibleServant( info, expectedType ))
		    return null ;
	    } catch (Throwable thr) {
		// Cleanup after this call, then throw to allow
		// outer try to handle the exception appropriately.
		servantExit( oa ) ;
		throw thr ;
	    }
        } catch ( ForwardException ex ) {
	    /* REVISIT
	    ClientRequestDispatcher csub = (ClientRequestDispatcher)
		StubAdapter.getDelegate( ex.forward_reference ) ;
	    IOR ior = csub.getIOR() ;
	    setLocatedIOR( ior ) ;
	    */
	    RuntimeException runexc = new RuntimeException("deal with this.");
	    runexc.initCause( ex ) ;
	    throw runexc ;
        } catch ( ThreadDeath ex ) {
	    // ThreadDeath on the server side should not cause a client
	    // side thread death in the local case.  We want to preserve
	    // this behavior for location transparency, so that a ThreadDeath
	    // has the same affect in either the local or remote case.
	    // The non-colocated case is handled in iiop.ORB.process, which
	    // throws the same exception.
	    throw wrapper.runtimeexception( ex ) ;
        } catch ( Throwable t ) {
            if (t instanceof SystemException)
		throw (SystemException)t ;

	    throw poaWrapper.localServantLookup( t ) ;
        } 

	if (!checkForCompatibleServant( info, expectedType )) {
	    servantExit( oa ) ;
	    return null ;
	}

        return info;
    }

    public void servant_postinvoke(org.omg.CORBA.Object self,
                                   ServantObject servantobj) 
    {
        ObjectAdapter oa = orb.peekInvocationInfo().oa() ; 
	servantExit( oa ) ;	
    }
}

// End of file.
