FileDocCategorySizeDatePackage
POARemoteReferenceFactory.javaAPI DocGlassfish v2 API20762Thu May 31 22:04:14 BST 2007com.sun.enterprise.iiop

POARemoteReferenceFactory.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package com.sun.enterprise.iiop;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.net.URL;
import java.io.File;
import java.util.*;
import java.util.logging.*;
import java.lang.reflect.Method;

import javax.rmi.PortableRemoteObject;
import javax.rmi.CORBA.*;
import javax.transaction.*;
import javax.ejb.EJBHome;
import javax.ejb.EJBObject;
import javax.ejb.NoSuchObjectLocalException;
import javax.naming.*;

import org.omg.CORBA.*;
import org.omg.CORBA.portable.Delegate;
import org.omg.CosNaming.NamingContext;

import org.omg.PortableServer.POA ;
import org.omg.PortableServer.Servant ;
import org.omg.PortableServer.ServantLocator ;
import org.omg.PortableServer.ServantLocatorPackage.CookieHolder ;

import com.sun.logging.LogDomains;
import com.sun.enterprise.*;
import com.sun.enterprise.deployment.*;
import com.sun.enterprise.util.*;
import com.sun.enterprise.server.*;
import com.sun.enterprise.deployment.runtime.IASEjbExtraDescriptors;
import com.sun.ejb.*;
import com.sun.ejb.base.sfsb.util.EJBServerConfigLookup;
import com.sun.ejb.containers.StatefulSessionContainer;

import com.sun.corba.ee.spi.ior.*;
import com.sun.corba.ee.spi.extension.ServantCachingPolicy;
import com.sun.corba.ee.spi.extension.ZeroPortPolicy;
import com.sun.corba.ee.spi.extension.CopyObjectPolicy;
import com.sun.corba.ee.spi.extension.RequestPartitioningPolicy;
import com.sun.corba.ee.spi.orbutil.threadpool.ThreadPoolManager;
import com.sun.corba.ee.spi.orbutil.threadpool.NoSuchThreadPoolException;
import com.sun.corba.ee.spi.presentation.rmi.PresentationManager ;
import com.sun.corba.ee.spi.presentation.rmi.DynamicStub;
import com.sun.corba.ee.spi.presentation.rmi.StubAdapter;
import com.sun.corba.ee.spi.oa.rfm.ReferenceFactory ;
import com.sun.corba.ee.spi.oa.rfm.ReferenceFactoryManager ;

import com.sun.corba.ee.impl.orbutil.ORBConstants;
import com.sun.corba.ee.impl.naming.cosnaming.TransientNameService;
import com.sun.corba.ee.impl.util.SUNVMCID;

import com.sun.enterprise.util.Utility;
/**
 * This class implements the RemoteReferenceFactory interface for the
 * RMI/IIOP ORB with POA (Portable Object Adapter). 
 * There is one instance of the POARemoteReferenceFactory for each
 * EJB type.
 * 
 * It also implements the preinvoke/postinvoke APIs in the 
 * POA's ServantLocator interface, which are called before/after
 * every invocation (local or remote).
 * It creates a RMI-IIOP-POA object reference (a stub) for every EJBObject
 * and EJBHome in the EJB container.
 * 
 * @author Kenneth Saks
 */

public final class POARemoteReferenceFactory extends org.omg.CORBA.LocalObject 
			implements RemoteReferenceFactory, ServantLocator
{
    static final int PASS_BY_VALUE_ID = 0;
    static final int PASS_BY_REFERENCE_ID = 1;

    static final int OTS_POLICY_TYPE = SUNVMCID.value + 123; 
    static final int CSIv2_POLICY_TYPE = SUNVMCID.value + 124; 
    static final int REQUEST_DISPATCH_POLICY_TYPE = SUNVMCID.value + 125; 
    static final int SFSB_VERSION_POLICY_TYPE = SUNVMCID.value + 126; 
    
    private static final java.util.logging.Logger logger =
		java.util.logging.Logger.getLogger(LogDomains.CORBA_LOGGER);
    private static final int GET_TIE_EXCEPTION_CODE = 9999;

    private Container container;
    private EjbDescriptor ejbDescriptor;

    private ORB orb;
    private POAProtocolMgr protocolMgr;
    private PresentationManager presentationMgr;

    private ReferenceFactory ejbHomeReferenceFactory ;
    private PresentationManager.StubFactory ejbHomeStubFactory;
    private String ejbHomeRepositoryId;

    private ReferenceFactory ejbObjectReferenceFactory ;
    private PresentationManager.StubFactory ejbObjectStubFactory;
    private String ejbObjectRepositoryId;

    private String remoteBusinessIntf;
    
    // true if remote home view.  false if remote business view.
    // Used when getting target object for an invocation.
    private boolean isRemoteHomeView;

    private String poaId_EJBHome;
    private String poaId_EJBObject;

    // The EJB key format with field-name(size in bytes): 
    // -----------------------------------------
    // | EJB ID(8) | INSTANCEKEY | INSTANCEKEY | 
    // |           | LENGTH(4)   |   (unknown) |
    // -----------------------------------------
    // The following are the offsets for the fields in the EJB key.
    static final int EJBID_OFFSET = 0;
    private static final int INSTANCEKEYLEN_OFFSET = 8;
    private static final int INSTANCEKEY_OFFSET = 12;
 


    POARemoteReferenceFactory(Container container, POAProtocolMgr protocolMgr, 
			      ORB orb, boolean remoteHomeView, String id) {
    
	this.protocolMgr = protocolMgr;
	this.orb = orb;
        this.poaId_EJBHome   = id + "-EJBHome";
        this.poaId_EJBObject = id + "-EJBObject";
        this.presentationMgr = 
            ((com.sun.corba.ee.spi.orb.ORB) orb).getPresentationManager();
	this.container = container;
	this.ejbDescriptor = container.getEjbDescriptor();
        this.isRemoteHomeView = remoteHomeView;

	ClassLoader loader = container.getClassLoader();

	// NOTE: ReferenceFactory creation happens in setRepositoryIds.
	
	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.FINE, 
		       "POARemoteReferenceFactory:"
		       + " " + poaId_EJBHome
		       + " " + poaId_EJBObject
		       + " " + ejbDescriptor);
	}
    }

    private String getRepositoryId(Class c) throws Exception {

        // Using PresentationManager to get repository ID will always work,
        // independent of whether we have generated static RMI-IIOP stubs.

        PresentationManager.ClassData cData = presentationMgr.getClassData(c);
        String[] typeIds = cData.getTypeIds();  

	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.FINE, ".getRepositoryId: " + typeIds[0]);
	}

        // Repository id is always 1st element in array.
        return typeIds[0];
    }

    public void setRepositoryIds(Class homeIntf, Class remoteIntf)
    {

        ClassLoader appClassLoader = container.getClassLoader();

        PresentationManager.StubFactoryFactory sff = 
            ((com.sun.corba.ee.spi.orb.ORB) orb).getStubFactoryFactory();

        // Home
        ejbHomeStubFactory = 
            sff.createStubFactory( homeIntf.getName(), false,
                                   "", null, appClassLoader);
        String[] ejbHomeTypeIds = ejbHomeStubFactory.getTypeIds();
        ejbHomeRepositoryId = ejbHomeTypeIds[0];

        ejbObjectStubFactory = 
	    sff.createStubFactory( remoteIntf.getName(), false,
				   "", null, appClassLoader);
        String[] ejbObjectTypeIds = ejbObjectStubFactory.getTypeIds();
        ejbObjectRepositoryId = ejbObjectTypeIds[0];

	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.FINE, 
		       ".setRepositoryIds:"
		       + " " + ejbHomeRepositoryId
		       + " " + ejbObjectRepositoryId);
	}

	try {
	
	    ejbHomeReferenceFactory 
		= createReferenceFactory(poaId_EJBHome, ejbHomeRepositoryId);
	    ejbObjectReferenceFactory 
		= createReferenceFactory(poaId_EJBObject, ejbObjectRepositoryId);
	} catch (Exception e) {
	    throw new RuntimeException(e);
	}

        if( !isRemoteHomeView ) {
            remoteBusinessIntf = remoteIntf.getName();
        }
            
    }

    public void cleanupClass(Class clazz) {

        try {
            presentationMgr.flushClass(clazz);
        } catch(Exception e) {
            logger.log(Level.FINE, "cleanupClass error", e);
        }
    }

    private ReferenceFactory createReferenceFactory(String poaId, String repoid ) throws Exception {
      try {
	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.WARNING, 
		       ".createReferenceFactory->: " + poaId + " " + repoid);
	}

	ReferenceFactoryManager rfm = 
	    (ReferenceFactoryManager)orb.resolve_initial_references(
		ORBConstants.REFERENCE_FACTORY_MANAGER ) ;

	List<Policy> policies = new ArrayList<Policy>();

	// Servant caching for local RMI-IIOP invocation performance
        policies.add(ServantCachingPolicy.getPolicy());

	// OTS Policy
	policies.add(new OTSPolicy());

	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.WARNING, 
		       ".createReferenceFactory: " + poaId + " " + repoid
		       + ": " + ejbDescriptor);
	}

	// CSIv2 Policy
	policies.add(new CSIv2Policy(ejbDescriptor));

	IASEjbExtraDescriptors extraDesc
	    = ejbDescriptor.getIASEjbExtraDescriptors();
	String threadPoolName = extraDesc.getUseThreadPoolId();
	int threadPoolNumericID = 0;
	boolean usePassByReference = extraDesc.getPassByReference();

	if (usePassByReference) {
	    policies.add(new CopyObjectPolicy(PASS_BY_REFERENCE_ID));
	}

	if (threadPoolName != null) {
	    ThreadPoolManager threadPoolManager
		= S1ASThreadPoolManager.getThreadPoolManager();
	    try {
		threadPoolNumericID = threadPoolManager.getThreadPoolNumericId(
		    threadPoolName);
		policies.add(new RequestPartitioningPolicy(threadPoolNumericID));
	    } catch (Exception ex) {
                logger.log(Level.WARNING, "Not using threadpool-request-partitioning...", ex);
	    }
	}

    logger.log(Level.INFO, "POARemoteRefFactory checking if SFSBVersionPolicy need to be added");
    EJBServerConfigLookup ejbConfigLookup =
        new EJBServerConfigLookup(ejbDescriptor);
    boolean addSFSBVersionPolicy = EJBServerConfigLookup.needToAddSFSBVersionInterceptors();
    logger.log(Level.INFO, "POARemoteRefFactory addSFSBVersionPolicy? " + addSFSBVersionPolicy);
    if (addSFSBVersionPolicy) {
        if (container instanceof StatefulSessionContainer) {
            StatefulSessionContainer sfsbCon = (StatefulSessionContainer) container;
            if (sfsbCon.isHAEnabled()) {
                policies.add(new SFSBVersionPolicy(ejbDescriptor.getUniqueId()));
            }
        }
    }


	if (logger.isLoggable(Level.FINE)) {
	    String jndiName = ejbDescriptor.getJndiName();
	    logger.log(Level.FINE, "Using Thread-Pool: ["
		+ threadPoolName + " ==> " + threadPoolNumericID
		+ "] for jndi name: " + jndiName);
	    logger.log(Level.FINE, "Pass by reference: ["
		+ usePassByReference
		+ "] for jndi name: " + usePassByReference);
	}

	// DisableClearTextIIOP policy which sets IIOP Profile port to 0 
	// if EJB allows only SSL invocations
	CSIV2TaggedComponentInfo ctc = new CSIV2TaggedComponentInfo(orb);
	Set iorDescSet = ejbDescriptor.getIORConfigurationDescriptors();
        if ( ctc.allMechanismsRequireSSL(iorDescSet) ) {
	    if (logger.isLoggable(Level.FINE)) {
		logger.log(Level.WARNING, 
			   ".createReferenceFactory: " + poaId + " " + repoid
			   + ": adding ZeroPortPolicy");
	    }
	    policies.add(ZeroPortPolicy.getPolicy());
        }

	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.WARNING, 
		       ".createReferenceFactory: " + poaId + " " + repoid
		       + ": policies: " + policies);
	}
	ReferenceFactory rf = rfm.create( poaId, repoid, policies, this ) ;
	return rf ;

      } finally {
	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.WARNING, 
		       ".createReferenceFactory<-: " + poaId + " " + repoid);
	}
      }
    }


    public java.rmi.Remote createRemoteReference(byte[] instanceKey)
    {
	return createRef(instanceKey, ejbObjectReferenceFactory,
	    ejbObjectStubFactory, ejbObjectRepositoryId );
    }


    public EJBHome createHomeReference(byte[] homeKey)
    {
	return (EJBHome)createRef(homeKey, ejbHomeReferenceFactory,
	    ejbHomeStubFactory, ejbHomeRepositoryId ) ;
    }

    private Remote createRef(byte[] instanceKey, ReferenceFactory rf, 
	PresentationManager.StubFactory stubFactory, String repoid )
    {
	try {
  	    PresentationManager.StubFactory stubFact = stubFactory;
	    org.omg.CORBA.Object ref = _createRef(rf, instanceKey,repoid);

	    org.omg.CORBA.Object stub = stubFact.makeStub();
            Delegate delegate = StubAdapter.getDelegate(ref);
            StubAdapter.setDelegate(stub, delegate);               

	    return (Remote) stub;

	} catch(Exception e) {
            logger.log(Level.SEVERE, "iiop.createreference_exception",
                       e.toString());

	    throw new RuntimeException("Unable to create reference ",e);
	}
    }

    // NOTE: The repoid is only needed for logging.
    private org.omg.CORBA.Object _createRef( ReferenceFactory rf, 
	byte[] instanceKey, String repoid ) throws Exception {

        if ( logger.isLoggable(Level.FINE) ) {
	    logger.info("\t\tIn POARemoteReferenceFactory._createRef, " +
                        "repositoryId = " + repoid);
        }

         // Create the ejbKey using EJB's unique id + instanceKey
        byte[] ejbKey = createEJBKey(ejbDescriptor.getUniqueId(), 
                                     instanceKey);
        
	org.omg.CORBA.Object obj = rf.createReference( ejbKey ) ;

        return obj;
    }
   
    private byte[] createEJBKey(long ejbId, byte[] instanceKey)
    {
	byte[] ejbkey = new byte[INSTANCEKEY_OFFSET+instanceKey.length];

	Utility.longToBytes(ejbId, ejbkey, EJBID_OFFSET);
	Utility.intToBytes(instanceKey.length, ejbkey, INSTANCEKEYLEN_OFFSET);
	System.arraycopy(instanceKey, 0, ejbkey, INSTANCEKEY_OFFSET, 
							    instanceKey.length);
	return ejbkey;
    }



    /**
     * Disconnect an EJBObject or EJBHome from the ORB.
     */
    public void destroyReference(Remote remoteRef, Remote remoteObj)
    {
	// Note: the POAs have the NON_RETAIN policy so they dont maintain
	// any state for objects. We only need to unexport the object from
	// the RMI/IIOP machinery.
	// The following call also does tie.deactivate() for the remoteObj's tie
	try {
	    Util.unexportObject(remoteObj);
	} catch ( RuntimeException ex ) {
	    // A bug in Util.unexportObject causes this exception 
	    // Ignore it.
	} catch ( java.lang.Exception nsoe ){
	    // eat it and ignore it.
	}
    }


    /**
     * This is the implementation of ServantLocator.preinvoke()
     * It is called from the POA before every remote invocation.
     * Return a POA Servant (which is the RMI/IIOP Tie for EJBObject/EJBHome).
     */
    public Servant preinvoke(byte[] ejbKey, POA adapter, String operation,
                                CookieHolder cookieHolder)
                throws org.omg.PortableServer.ForwardRequest
    {
	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.FINE,"In preinvoke for operation:" + operation);
	}

	// get instance key
	int keyLen = Utility.bytesToInt(ejbKey, INSTANCEKEYLEN_OFFSET);
	byte[] instanceKey = new byte[keyLen];
	System.arraycopy(ejbKey, INSTANCEKEY_OFFSET, instanceKey, 0, keyLen);

        Servant servant = null;
        try {
            while ( servant == null ) {
		// get the EJBObject / EJBHome
	        Remote targetObj = 
                    container.getTargetObject(instanceKey, 
                                              (isRemoteHomeView ? null :
                                               remoteBusinessIntf));

                // This could be null in rare cases for sfsbs and entity 
                // beans.  It would be preferable to push the retry logic
                // within the sfsb container and entity container 
                // implementations of getTargetObject, but for now let's keep
                // the looping logic the same as it has always been.
                if( targetObj != null ) {
                    // get the Tie which is the POA Servant
		    //fix for bug 6484935
		    Tie tie = (Tie)java.security.AccessController.doPrivileged(
						new java.security.PrivilegedAction() {
                        public Tie run()  {
			    return presentationMgr.getTie();
			}
		    });
                    tie.setTarget(targetObj);
                    servant = (Servant) tie;
                }
            }
        } catch (NoSuchObjectLocalException e) {
            logger.log(Level.SEVERE,"iiop.gettie_exception", e);
            throw new OBJECT_NOT_EXIST( GET_TIE_EXCEPTION_CODE,
					CompletionStatus.COMPLETED_NO);
        } catch (RuntimeException e) {
            logger.log(Level.SEVERE,"iiop.runtime_exception", e);
	    throw e;
	}
        return servant;
    }

    public void postinvoke(byte[] ejbKey, POA adapter, String operation,
                            java.lang.Object cookie, Servant servant)
    {
	Remote target = null;
	if ( servant != null ) {
	    target = ((Tie)servant).getTarget();
        }
        // Always release, since that restores the previous context class
        // loader. 
	container.releaseTargetObject(target);
    }


    public void destroy() {
        try {

	    ejbHomeReferenceFactory.destroy() ;
	    ejbObjectReferenceFactory.destroy() ;
	    ejbHomeReferenceFactory = null ;
	    ejbObjectReferenceFactory = null ;

            container = null;
            ejbDescriptor = null;

            orb = null;
            protocolMgr = null;

        } catch (Throwable th) {
            logger.log(Level.SEVERE, "Exception during "
                       + "POARemoteRefFactory::destroy()", th);
        }
    }

    public boolean hasSameContainerID(org.omg.CORBA.Object obj)
	throws Exception
    {
	boolean result = false;
	try {
	    IOR ior = ((com.sun.corba.ee.spi.orb.ORB)orb).getIOR(obj, false);
	    java.util.Iterator iter = ior.iterator();

	    byte[] oid = null;
	    if (iter.hasNext()) {
		TaggedProfile profile = (TaggedProfile) iter.next();
		ObjectKey objKey = profile.getObjectKey();
		oid = objKey.getId().getId();
	    }

	    if ((oid != null) && (oid.length > INSTANCEKEY_OFFSET)) {
		long cid = Utility.bytesToLong(oid, EJBID_OFFSET);
		//To be really sure that is indeed a ref generated
		//  by our container we do the following checks
		int keyLen = Utility.bytesToInt(oid, INSTANCEKEYLEN_OFFSET);
		if (oid.length == keyLen + INSTANCEKEY_OFFSET) {
		    result = (cid == ejbDescriptor.getUniqueId());
		}
		if (logger.isLoggable(Level.FINE)) {
		    StringBuffer sbuf = new StringBuffer();
		    sbuf.append("hasSameContainerID() result: ").append(result)
			.append("; because ==> oid.length: ").append(oid.length)
			.append("; instance-key-length: ").append(keyLen)
			.append("; expected oid.length: ")
			.append(keyLen).append("+").append(INSTANCEKEY_OFFSET)
			.append("; myContainrID: ")
			.append(ejbDescriptor.getUniqueId())
			.append("; obj.containerID: ")
			.append(cid);
		    logger.log(Level.FINE, sbuf.toString());
		}
	    } else {
		if (logger.isLoggable(Level.FINE)) {
		    if (oid == null) {
			logger.log(Level.FINE, "hasSameContainerID() failed because oid=null");
		    } else {
			logger.log(Level.FINE, "hasSameContainerID() failed because "
				+ "oid.length= " + oid.length
				+ "; but INSTANCE_KEY_OFFSET= " + INSTANCEKEY_OFFSET);
		    }
		}
	    }
	} catch (Exception ex) {
	    logger.log(Level.FINE, "Exception while checking for same containerID", ex);
	    throw ex;
	}
	return result;
    }

}