FileDocCategorySizeDatePackage
StatelessSessionContainer.javaAPI DocGlassfish v2 API32610Tue Jul 24 05:01:32 BST 2007com.sun.ejb.containers

StatelessSessionContainer

public final class StatelessSessionContainer extends BaseContainer implements com.sun.ejb.spi.stats.StatelessSessionBeanStatsProvider
This class provides container functionality specific to stateless SessionBeans. At deployment time, one instance of the StatelessSessionContainer is created for each stateless SessionBean type (i.e. deployment descriptor) in a JAR.

The 3 states of a Stateless EJB (an EJB can be in only 1 state at a time): 1. POOLED : ready for invocations, no transaction in progress 2. INVOKING : processing an invocation 3. DESTROYED : does not exist

This container services invocations using a pool of EJB instances. An instance is returned to the pool immediately after the invocation completes, so the # of instances needed = # of concurrent invocations.

A Stateless Bean can hold open DB connections across invocations. Its assumed that the Resource Manager can handle multiple incomplete transactions on the same connection.

Fields Summary
private static final Logger
_logger
private static com.sun.enterprise.util.LocalStringManagerImpl
localStrings
private static final int
POOLED
private static final int
INVOKING
private static final int
DESTROYED
private static final int
LOW_WATER_MARK
private static final byte[]
statelessInstanceKey
private Method
homeCreateMethod
private Method
localHomeCreateMethod
private EJBLocalObjectImpl
theEJBLocalObjectImpl
private EJBLocalObjectImpl
theEJBLocalBusinessObjectImpl
private EJBObjectImpl
theEJBObjectImpl
private EJBObject
theEJBObject
private EJBObject
theEJBStub
private EJBObjectImpl
theRemoteBusinessObjectImpl
private Remote
theRemoteBusinessObject
private Map
theRemoteBusinessStubs
private com.sun.enterprise.webservice.EjbRuntimeEndpointInfo
webServiceEndpoint
private boolean
isPoolClosed
protected AbstractPool
pool
private com.sun.enterprise.deployment.runtime.IASEjbExtraDescriptors
iased
private com.sun.enterprise.deployment.runtime.BeanCacheDescriptor
beanCacheDes
private com.sun.enterprise.deployment.runtime.BeanPoolDescriptor
beanPoolDes
private Server
svr
private Config
cfg
private EjbContainer
ejbContainer
private PoolProperties
poolProp
Constructors Summary
StatelessSessionContainer(EjbDescriptor desc, ClassLoader loader)
This constructor is called from the JarManager when a Jar is deployed.

exception
Exception on error


                          
        
	 
    
        super(desc, loader);


        try {
            // get the ejbCreate method for stateless beans
            if ( hasLocalHomeView ) {
                localHomeCreateMethod = 
                    localHomeIntf.getMethod("create", NO_PARAMS);
            }
            if ( hasRemoteHomeView ) {
                homeCreateMethod = 
                    homeIntf.getMethod("create", NO_PARAMS);
            }
        } catch (Exception ex) {
            if(_logger.isLoggable(Level.SEVERE)) {
                _logger.log(Level.SEVERE,
                    "ejb.get_ejbcreate_method_exception",logParams);
                _logger.log(Level.SEVERE,"",ex);
            }
            throw ex;
        }

        EjbSessionDescriptor ed = (EjbSessionDescriptor)desc;
        iased = ed.getIASEjbExtraDescriptors();
        if( iased != null) {
            beanPoolDes = iased.getBeanPool();
        }
        try {
            ServerContext sc = ApplicationServer.getServerContext();
            //ROB: config changes
            //svr = ServerBeansFactory.getServerBean(sc.getConfigContext());
            cfg = ServerBeansFactory.getConfigBean(sc.getConfigContext());
        }  catch (ConfigException ex) {
            ex.printStackTrace();
        }
	   //ROB: config changes
        //ejbContainer = svr.getEjbContainer();
 	   ejbContainer = cfg.getEjbContainer(); 

        super.setMonitorOn(ejbContainer.isMonitoringEnabled());

        super.createCallFlowAgent(ComponentType.SLSB);
    
Methods Summary
protected ComponentContext_getContext(Invocation inv)
Called from preInvoke which is called from the EJBObject for local and remote invocations.

        try {
            SessionContextImpl sessionCtx = 
                (SessionContextImpl) pool.getObject(null);
            sessionCtx.setState(INVOKING);
            return sessionCtx;
        } catch (Exception ex) {
            throw new EJBException(ex);
        }
    
public voidactivateEJB(java.lang.Object ctx, java.lang.Object instanceKey)

voidafterBegin(EJBContextImpl context)

        // Stateless SessionBeans cannot implement SessionSynchronization!!
        // EJB2.0 Spec 7.8.
    
voidafterCompletion(EJBContextImpl ctx, int status)

        // Stateless SessionBeans cannot implement SessionSynchronization!!
        // EJB2.0 Spec 7.8.

        // We dissociate the transaction from the bean in releaseContext above
    
public voidappendStats(java.lang.StringBuffer sbuf)

	sbuf.append("\nStatelessContainer: ")
	    .append("CreateCount=").append(statCreateCount).append("; ")
	    .append("RemoveCount=").append(statRemoveCount).append("; ")
	    .append("]");
    
voidbeforeCompletion(EJBContextImpl context)

        // Stateless SessionBeans cannot implement SessionSynchronization!!
        // EJB2.0 Spec 7.8.
    
voidcheckExists(EJBLocalRemoteObject ejbObj)
Check if the given EJBObject/LocalObject has been removed.

exception
NoSuchObjectLocalException if the object has been removed.

        // For stateless session beans, EJBObject/EJBLocalObj are never removed.
        // So do nothing.
    
public EJBLocalObjectImplcreateEJBLocalBusinessObjectImpl()
Called during internal creation of session bean

	
        // No access checks needed because this is called as a result
        // of an internal creation, not a user-visible create method.
        return theEJBLocalBusinessObjectImpl;
    
public EJBLocalObjectImplcreateEJBLocalObjectImpl()
Called during client creation request through EJB LocalHome view.

	
        // Need to do access control check here because BaseContainer.preInvoke
        // is not called for stateless sessionbean creates.
        authorizeLocalMethod(EJBLocalHome_create);

        if ( AppVerification.doInstrument() ) {
            AppVerification.getInstrumentLogger().doInstrumentForEjb(
                ejbDescriptor, localHomeCreateMethod, null);
        }

        // For stateless EJBs, EJB2.0 Section 7.8 says that 
        // Home.create() need not do any real creation.
        // If necessary, a stateless bean is created below during getContext().
        return theEJBLocalObjectImpl;
    
public EJBObjectImplcreateEJBObjectImpl()

        // Need to do access control check here because BaseContainer.preInvoke
        // is not called for stateless sessionbean creates.
        authorizeRemoteMethod(EJBHome_create);

        if ( AppVerification.doInstrument() ) {
            AppVerification.getInstrumentLogger().doInstrumentForEjb(
                ejbDescriptor, homeCreateMethod, null);
        }

	statCreateCount++;

        // For stateless EJBs, EJB2.0 Section 7.8 says that 
        // Home.create() need not do any real creation.
        // If necessary, a stateless bean is created below during getContext().
        return theEJBObjectImpl;
    
public EJBObjectImplcreateRemoteBusinessObjectImpl()

        // No access check since this is an internal operation.

	statCreateCount++;

        return theRemoteBusinessObjectImpl;
    
private SessionContextImplcreateStatelessEJB()
called when an invocation arrives and there are no instances left to deliver the invocation to. Called from SessionContextFactory.create() !

 
        ComponentInvocation ci = null;
        SessionContextImpl context;

        try {
            // create new stateless EJB
            Object ejb = ejbClass.newInstance();

            // create SessionContext and set it in the EJB
            context = new SessionContextImpl(ejb, this);
            context.setInterceptorInstances(
                    interceptorManager.createInterceptorInstances());
            
            // this allows JNDI lookups from setSessionContext, ejbCreate
            ci = new ComponentInvocation(ejb, this, context);
            invocationManager.preInvoke(ci);

            // setSessionContext will be called without a Tx as required
            // by the spec, because the EJBHome.create would have been called
            // after the container suspended any client Tx.
            // setSessionContext is also called before context.setEJBStub
            // because the bean is not allowed to do EJBContext.getEJBObject
            if( ejb instanceof SessionBean ) {
                ((SessionBean)ejb).setSessionContext(context);
            }

            // Perform injection right after where setSessionContext
            // would be called.  This is important since injection methods
            // have the same "operations allowed" permissions as
            // setSessionContext.
            injectionManager.injectInstance(ejb, ejbDescriptor, false);
            for (Object interceptorInstance : context.getInterceptorInstances()) {
                injectionManager.injectInstance(interceptorInstance,
                        ejbDescriptor, false);
            }

            if ( isRemote ) {
                if( hasRemoteHomeView ) {
                    context.setEJBObjectImpl(theEJBObjectImpl);
                    context.setEJBStub(theEJBStub);
                }
                if( hasRemoteBusinessView ) {
                    context.setEJBRemoteBusinessObjectImpl
                        (theRemoteBusinessObjectImpl);
                }
            }
            if ( isLocal ) {
                if( hasLocalHomeView ) {
                    context.setEJBLocalObjectImpl(theEJBLocalObjectImpl);
                }
                if( hasLocalBusinessView ) {
                    context.setEJBLocalBusinessObjectImpl
                        (theEJBLocalBusinessObjectImpl);
                }
            }

            // all stateless beans have the same id and same InstanceKey
            context.setInstanceKey(statelessInstanceKey); 

            //Call ejbCreate() or @PostConstruct method
            interceptorManager.intercept(
                    CallbackType.POST_CONSTRUCT, context);

            // Set the state to POOLED after ejbCreate so that 
            // EJBContext methods not allowed will throw exceptions
            context.setState(POOLED);
        } catch ( Throwable th ) {
            _logger.log(Level.INFO, "ejb.stateless_ejbcreate_exception", th);
            CreateException creEx = new CreateException("Could not create stateless EJB");
            creEx.initCause(th);
            throw creEx;
        } finally {
            if ( ci != null ) {
                invocationManager.postInvoke(ci);
            }
        }
        context.touch();
        return context;
    
voiddoTimerInvocationInit(Invocation inv, RuntimeTimerState timerState)

        if( isRemote ) {
            inv.ejbObject = theEJBObjectImpl;
            inv.isLocal = false;
        } else {
            inv.ejbObject = theEJBLocalObjectImpl;
            inv.isLocal = true;
        }
    
voidforceDestroyBean(EJBContextImpl sc)
Force destroy the EJB. Called from postInvokeTx. Note: EJB2.0 section 18.3.1 says that discarding an EJB means that no methods other than finalize() should be invoked on it.

        if ( sc.getState() == DESTROYED )
                return;

        // mark context as destroyed
        sc.setState(DESTROYED);

        //sessionCtxPool.destroyObject(sc);
        pool.destroyObject(sc);
    
EJBLocalObjectImplgetEJBLocalBusinessObjectImpl(java.lang.Object key)
Called from EJBLocalObjectImpl.getLocalObject() while deserializing a local business object reference.

        return theEJBLocalBusinessObjectImpl;
    
EJBLocalObjectImplgetEJBLocalObjectImpl(java.lang.Object key)
Called from EJBLocalObjectImpl.getLocalObject() while deserializing a local object reference.

        return theEJBLocalObjectImpl;
    
EJBObjectImplgetEJBObjectImpl(byte[] instanceKey)
Called when a remote invocation arrives for an EJB.

        return theEJBObjectImpl;
    
EJBObjectImplgetEJBRemoteBusinessObjectImpl(byte[] instanceKey)

        return theRemoteBusinessObjectImpl;
    
public intgetMaxPoolSize()

        return (poolProp.maxPoolSize <= 0)
	    ? Integer.MAX_VALUE
	    : poolProp.maxPoolSize;
    
public longgetMethodReadyCount()

	return pool.getSize();
    
public java.lang.StringgetMonitorAttributeValues()

        StringBuffer sbuf = new StringBuffer();
        sbuf.append("STATELESS ").append(ejbDescriptor.getName());
        sbuf.append(pool.getAllAttrValues());
        sbuf.append("]");

        return sbuf.toString();
    
public intgetSteadyPoolSize()

        return (poolProp.steadyPoolSize <= 0)
	    ? 0
	    : poolProp.steadyPoolSize;
    
protected voidinitializeHome()


        super.initializeHome();

        if ( isRemote ) {

            if( hasRemoteHomeView ) {
                // Create theEJBObjectImpl
                theEJBObjectImpl = instantiateEJBObjectImpl();
                theEJBObject = (EJBObject) theEJBObjectImpl.getEJBObject();
                
                // connect the EJBObject to the ProtocolManager 
                // (creates the stub 
                // too). Note: cant do this in constructor above because 
                // containerId is not set at that time.
                theEJBStub = (EJBObject) 
                    remoteHomeRefFactory.createRemoteReference
                       (statelessInstanceKey);
                
                theEJBObjectImpl.setStub(theEJBStub);
            }

            if( hasRemoteBusinessView ) {

                theRemoteBusinessObjectImpl = 
                    instantiateRemoteBusinessObjectImpl();

                theRemoteBusinessObject = 
                    theRemoteBusinessObjectImpl.getEJBObject();
                
                for(RemoteBusinessIntfInfo next : 
                        remoteBusinessIntfInfo.values()) {
                    java.rmi.Remote stub = next.referenceFactory.
                        createRemoteReference(statelessInstanceKey);
                    theRemoteBusinessStubs.put
                        (next.generatedRemoteIntf.getName(), stub);
                    theRemoteBusinessObjectImpl.setStub
                        (next.generatedRemoteIntf.getName(), stub);
                }

            }

        }

        if ( isLocal ) {
            if( hasLocalHomeView ) {
                theEJBLocalObjectImpl = instantiateEJBLocalObjectImpl();
            }
            if( hasLocalBusinessView ) {
                theEJBLocalBusinessObjectImpl = 
                    instantiateEJBLocalBusinessObjectImpl();
            }
        }

        if( isWebServiceEndpoint ) {

            EjbBundleDescriptor bundle = 
                ejbDescriptor.getEjbBundleDescriptor();
            WebServicesDescriptor webServices = bundle.getWebServices();
            Collection myEndpoints = 
                webServices.getEndpointsImplementedBy(ejbDescriptor);
            //FindBugs [Deadstore] Long ejbId = new Long(ejbDescriptor.getUniqueId());
            
            // An ejb can only be exposed through 1 web service endpoint
            Iterator iter = myEndpoints.iterator();
            com.sun.enterprise.deployment.WebServiceEndpoint next = 
 					(com.sun.enterprise.deployment.WebServiceEndpoint) iter.next();

            Class serviceEndpointIntfClass = 
                    loader.loadClass(next.getServiceEndpointInterface());            

            if (!serviceEndpointIntfClass.isInterface()) {
                ServiceInterfaceGenerator generator = new ServiceInterfaceGenerator(loader, ejbClass);
                serviceEndpointIntfClass = WsUtil.generateAndLoad(generator, loader);
                if (serviceEndpointIntfClass==null) {
                    throw new RuntimeException("Error generating the SEI");
                }
            }
            
            Class tieClass=null;
            
            WebServiceInvocationHandler invocationHandler =
                    new WebServiceInvocationHandler(ejbClass, next,
                                                    serviceEndpointIntfClass,
                    webServiceInvocationInfoMap);
            
            
            invocationHandler.setContainer(this);
            Object servant = (Object) Proxy.newProxyInstance
                    (loader, new Class[] { serviceEndpointIntfClass },
                    invocationHandler);
            
            // starting in 2.0, there is no more generated Ties
            if (next.getTieClassName()!=null) {                
                tieClass = loader.loadClass(next.getTieClassName());                
            }
                    
            webServiceEndpoint = WebServiceEjbEndpointRegistry.getRegistry().createEjbEndpointInfo(next, this, servant, tieClass);
                                           
            WebServiceEjbEndpointRegistry.getRegistry().
                registerEjbWebServiceEndpoint(webServiceEndpoint);
        }
      
        ObjectFactory sessionCtxFactory = new SessionContextFactory();
        poolProp = new PoolProperties();
        pool= new NonBlockingPool(ejbDescriptor.getName(),
           sessionCtxFactory, poolProp.steadyPoolSize, 
           poolProp.poolResizeQuantity, poolProp.maxPoolSize, 
           poolProp.poolIdleTimeoutInSeconds, loader);

	registerMonitorableComponents();
    
booleanisIdentical(EJBObjectImpl ejbo, EJBObject other)

        if ( other == ejbo.getStub() ) {
            return true;
        }else {
            try {
                // other may be a stub for a remote object.
                // Although all stateless sessionbeans for a bean type
                // are identical, we dont know whether other is of the
                // same bean type as ejbo.
                if ( protocolMgr.isIdentical(ejbo.getStub(), other) )
                        return true;
                else
                        return false;
            } catch ( Exception ex ) {
                if(_logger.isLoggable(Level.SEVERE)) {
                    _logger.log(Level.SEVERE,"ejb.ejb_getstub_exception",
                        logParams);
                    _logger.log(Level.SEVERE,"",ex);
                }
                throw new RemoteException("Error during isIdentical.", ex);
            }
        }
    
public voidonReady()

    
public booleanpassivateEJB(ComponentContext context)

        return false;
    
protected voidregisterMonitorableComponents()

	registryMediator.registerProvider(this);
	registryMediator.registerProvider(pool);
        super.registerMonitorableComponents();
	super.populateMethodMonitorMap();
        _logger.log(Level.FINE, "[SLSB Container] registered monitorable");
    
public voidreleaseContext(Invocation inv)
Called from preInvoke which is called from the EJBObject for local and remote invocations.

        SessionContextImpl sc = (SessionContextImpl)inv.context;

        // check if the bean was destroyed
        if ( sc.getState()==DESTROYED )
            return;

            sc.setState(POOLED);

            // Stateless beans cant have transactions across invocations
            sc.setTransaction(null);
            sc.touch();

            pool.returnObject(sc);
    
voidremoveBean(EJBLocalRemoteObject ejbo, java.lang.reflect.Method removeMethod, boolean local)

        if( local ) {
            authorizeLocalMethod(BaseContainer.EJBLocalObject_remove);
        } else {
            authorizeRemoteMethod(BaseContainer.EJBObject_remove);
        }
	statRemoveCount++;
    
public voidundeploy()

        //Change the container state to ensure that all new invocations will be rejected
        super.setUndeployedState();

        try {
            if( isWebServiceEndpoint && (webServiceEndpoint != null) ) {
                String endpointAddress = 
                    webServiceEndpoint.getEndpointAddressUri();
                WebServiceEjbEndpointRegistry.getRegistry().
                    unregisterEjbWebServiceEndpoint(endpointAddress);
            }
            
            EjbBundleDescriptor desc = ejbDescriptor.getEjbBundleDescriptor();
            if (desc != null && desc.getServiceReferenceDescriptors()!= null) {
                for (Object srd : desc.getServiceReferenceDescriptors()) {
                    ClientPipeCloser.getInstance()
                    .cleanupClientPipe((ServiceReferenceDescriptor)srd);
                }
            }
            
            if ( hasRemoteHomeView ) {
                    // destroy EJBObject refs
                    // XXX invocations still in progress will get exceptions ??
                remoteHomeRefFactory.destroyReference
                    (theEJBObjectImpl.getStub(), 
                     theEJBObjectImpl.getEJBObject());
            }
            if ( hasRemoteBusinessView ) {
                for(RemoteBusinessIntfInfo next : 
                        remoteBusinessIntfInfo.values()) {
                    next.referenceFactory.destroyReference
                        (theRemoteBusinessObjectImpl.getStub
                            (next.generatedRemoteIntf.getName()),
                         theRemoteBusinessObjectImpl.getEJBObject
                            (next.generatedRemoteIntf.getName()));
                }
            }

            isPoolClosed = true;

            pool.close();

        } finally {
            super.undeploy();

            this.homeCreateMethod      = null;
            this.localHomeCreateMethod = null;
            this.theEJBLocalObjectImpl = null;
            this.theEJBObjectImpl      = null;
            this.theEJBStub            = null;
            this.pool                  = null;
            this.iased                 = null;
            this.beanCacheDes          = null;
            this.beanPoolDes           = null;
            this.svr                   = null;
            this.ejbContainer          = null;
            this.poolProp              = null;

        }
    
public booleanuserTransactionMethodsAllowed(ComponentInvocation inv)

        boolean utMethodsAllowed = false;
        if( isBeanManagedTran ) {
            if( inv instanceof Invocation ) {
                Invocation i = (Invocation) inv;
                EJBContextImpl sc = (EJBContextImpl) i.context;
                // If Invocation, only ejbRemove not allowed.
                utMethodsAllowed = !sc.isInEjbRemove();
            } else {
                // This will prevent setSessionContext/ejbCreate access
                utMethodsAllowed = false;
            }
        }
        return utMethodsAllowed;