All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.enterprise.iiop.impl.POARemoteReferenceFactory Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2012 Oracle and/or its affiliates. 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_1_1.html
 * or packager/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 packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [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.
 */
// Portions Copyright [2018-2021] [Payara Foundation and/or its affiliates]

package org.glassfish.enterprise.iiop.impl;


import jakarta.ejb.NoSuchObjectLocalException;

import java.rmi.Remote;

import java.security.AccessController ;
import java.security.PrivilegedAction ;

import org.omg.CORBA.portable.Delegate;

import org.glassfish.enterprise.iiop.api.RemoteReferenceFactory;

import org.glassfish.enterprise.iiop.spi.EjbContainerFacade;
import org.glassfish.enterprise.iiop.util.S1ASThreadPoolManager;

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.deployment.EjbDescriptor;

// TODO Only needed for checkpointing
// import com.sun.ejb.base.sfsb.util.EJBServerConfigLookup;

import com.sun.corba.ee.spi.extension.ServantCachingPolicy;
import com.sun.corba.ee.spi.extension.CopyObjectPolicy;
import com.sun.corba.ee.spi.extension.RequestPartitioningPolicy;
import com.sun.corba.ee.spi.threadpool.ThreadPoolManager;

import com.sun.corba.ee.spi.presentation.rmi.PresentationManager ;

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.spi.misc.ORBConstants;
import com.sun.corba.ee.org.omg.CORBA.SUNVMCID;
import com.sun.corba.ee.spi.extension.ZeroPortPolicy;
import com.sun.corba.ee.spi.ior.IOR;
import com.sun.corba.ee.spi.ior.ObjectKey;
import com.sun.corba.ee.spi.ior.TaggedProfile;
import com.sun.corba.ee.spi.orb.ORB;

import com.sun.enterprise.util.Utility;

import org.glassfish.pfl.dynamic.codegen.spi.Wrapper ;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Level;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import javax.rmi.CORBA.Tie;
import javax.rmi.CORBA.Util;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.OBJECT_NOT_EXIST;
import org.omg.CORBA.Policy;

/**
 * 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 EjbContainerFacade container;
    private EjbDescriptor ejbDescriptor;
    private ClassLoader appClassLoader;

    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(EjbContainerFacade 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 = orb.getPresentationManager();
        this.container = container;
        this.ejbDescriptor = container.getEjbDescriptor();
        this.isRemoteHomeView = remoteHomeView;

        appClassLoader = container.getClassLoader();

        // NOTE: ReferenceFactory creation happens in setRepositoryIds.
    }

    @Override
    public int getCSIv2PolicyType() {
        return CSIv2_POLICY_TYPE;
    }

    /*
    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: {0}", typeIds[0]);
	    }

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

    @Override
    public void setRepositoryIds(Class homeIntf, Class remoteIntf)
    {
        PresentationManager.StubFactoryFactory sff = 
            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:" + " " + "{0} {1}",
                new Object[]{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();
        }
            
    }

    @Override
    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.FINE, ".createReferenceFactory->: {0} {1}",
                    new Object[]{poaId, repoid});
	    }

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

	    List policies = new ArrayList();

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

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

	    if (logger.isLoggable(Level.FINE)) {
	        logger.log(Level.FINE, ".createReferenceFactory: {0} {1}: {2}",
                    new Object[]{poaId, repoid, ejbDescriptor});

	    }

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

	    String threadPoolName = container.getUseThreadPoolId();
	    int threadPoolNumericID = 0;
	    boolean usePassByReference = container.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);
	        }
	    }

            /** TODO
            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: [{0} ==> {1}] for jndi name: {2}",
                    new Object[]{threadPoolName, threadPoolNumericID, jndiName});
                logger.log(Level.FINE, "Pass by reference: [{0}] for jndi name: {1}",
                    new Object[]{usePassByReference, usePassByReference});
            }

	    // DisableClearTextIIOP policy which sets IIOP Profile port to 0
	    // if EJB allows only SSL invocations
	    if ( ejbDescriptor.allMechanismsRequireSSL() ) {
	        if (logger.isLoggable(Level.FINE)) {
                    logger.log(Level.WARNING,
                        ".createReferenceFactory: {0} {1}: adding ZeroPortPolicy",
                        new Object[]{poaId, repoid});
	        }
                if (!GlassFishORBManager.disableSSLCheck()) {
                    policies.add(ZeroPortPolicy.getPolicy());
                }
	    }


	    if (logger.isLoggable(Level.FINE)) {
	        logger.log(Level.FINE, 
                    ".createReferenceFactory: {0} {1}: policies: {2}",
                    new Object[]{poaId, repoid, policies});
	    }

	    ReferenceFactory rf = rfm.create( poaId, repoid, policies, this ) ;
	    return rf ;
        } finally {
	    if (logger.isLoggable(Level.FINE)) {
	        logger.log(Level.WARNING, 
                    ".createReferenceFactory<-: {0} {1}",
                    new Object[]{poaId, repoid});
	    }
        }
    }


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


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

    private void setClassLoader() {
        ClassLoader cl ;
        SecurityManager sman = System.getSecurityManager() ;
        if (sman == null) {
            cl = this.getClass().getClassLoader() ;
        } else {
            cl = AccessController.doPrivileged( 
                new PrivilegedAction() {
                    @Override
                    public ClassLoader run() {
                        return this.getClass().getClassLoader() ;
                    }
                }
            ) ;
        }

        Wrapper._setClassLoader( cl ) ;
    }

    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);
                
            // Set the ClassLoader to the ClassLoader for this class,
            // which is loaded by the OSGi bundle ClassLoader for the
            // orb-iiop bundle, which depends on (among others) the
            // glassfish-corba-codegen bundle, which contains the
            // CodegenProxyStub class needed inside the makeStub call.
            setClassLoader() ;

            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.log(Level.FINE,
                "\t\tIn POARemoteReferenceFactory._createRef, repositoryId = {0}",
                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.
     */
    @Override
    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).
     * @param ejbKey 
     * @param cookieHolder
     */
    @Override
    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:{0}", 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
                    @SuppressWarnings("unchecked")
                    Tie tie = (Tie)AccessController.doPrivileged( 
                        new PrivilegedAction() {
                        @Override
                            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;
    }

    @Override
    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 previous context class loader.
        container.releaseTargetObject(target);
    }


    @Override
    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);
        }
    }

    @Override
    public boolean hasSameContainerID(org.omg.CORBA.Object obj)
	throws Exception
    {
	boolean result = false;
	try {
	    IOR ior = (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)) {
                    StringBuilder sbuf = new StringBuilder();
                    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= "
                            + "{0}; but INSTANCE_KEY_OFFSET= {1}",
                            new Object[]{oid.length, INSTANCEKEY_OFFSET});
                    }
                }
	    }
	} catch (Exception ex) {
	    logger.log(Level.FINE, "Exception while checking for same containerID", ex);
	    throw ex;
	}

	return result;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        throw new NotSerializableException();
    }

     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
         throw new NotSerializableException();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy