com.sun.ejb.containers.AbstractSingletonContainer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project for IBM JDK
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 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.
*/
package com.sun.ejb.containers;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.NoSuchEJBException;
import javax.ejb.NoSuchObjectLocalException;
import javax.ejb.RemoveException;
import com.sun.ejb.ComponentContext;
import com.sun.ejb.Container;
import com.sun.ejb.EjbInvocation;
import com.sun.ejb.InvocationInfo;
import com.sun.ejb.containers.util.pool.ObjectFactory;
import com.sun.ejb.monitoring.stats.EjbMonitoringStatsProvider;
import com.sun.ejb.monitoring.stats.SingletonBeanStatsProvider;
import com.sun.enterprise.admin.monitor.callflow.ComponentType;
import com.sun.enterprise.deployment.LifecycleCallbackDescriptor;
import com.sun.enterprise.deployment.LifecycleCallbackDescriptor.CallbackType;
import com.sun.enterprise.deployment.MethodDescriptor;
import com.sun.enterprise.security.SecurityManager;
import com.sun.enterprise.util.Utility;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.ejb.deployment.descriptor.EjbDescriptor;
import org.glassfish.ejb.startup.SingletonLifeCycleManager;
public abstract class AbstractSingletonContainer
extends BaseContainer {
private static final byte[] singletonInstanceKey = {0, 0, 0, 1};
// All Singleton EJBs have the same instanceKey
// Note: the first byte of instanceKey must be left empty.
// Note : Singletons do not support the legacy EJB 2.x RemoteHome/LocalHome
// client views.
private EJBLocalObjectImpl theEJBLocalBusinessObjectImpl = null;
private EJBLocalObjectImpl theOptionalEJBLocalBusinessObjectImpl = null;
// Data members for Remote business view. Any objects representing the
// Remote business interface are not subtypes of EJBObject.
private EJBObjectImpl theRemoteBusinessObjectImpl = null;
private Map theRemoteBusinessStubs =
new HashMap();
// Information about a web service ejb endpoint. Used as a conduit
// between webservice runtime and ejb container. Contains a Remote
// servant used by jaxrpc to call web service business method.
//TODO private EjbRuntimeEndpointInfo webServiceEndpoint;
protected ObjectFactory singletonCtxFactory;
private SingletonLifeCycleManager lcm;
protected AtomicBoolean singletonInitialized = new AtomicBoolean(false);
// used to protect against synchronous loopback calls during Singleton init
private boolean initializationInProgress = false;
// Set to true if Singleton failed to complete its initialization successfully.
// If true, Singleton is not accessible.
protected boolean singletonInitializationFailed = false;
protected volatile ComponentContext singletonCtx;
private InvocationInfo postConstructInvInfo;
private InvocationInfo preDestroyInvInfo;
/**
* This constructor is called from the JarManager when a Jar is deployed.
* @exception Exception on error
*/
protected AbstractSingletonContainer(EjbDescriptor desc, ClassLoader loader, SecurityManager sm)
throws Exception {
super(ContainerType.SINGLETON, desc, loader, sm);
super.createCallFlowAgent(ComponentType.SLSB);
// Tx attribute for PostConstruct/PreDestroy methods can only be specified using
// a PostConstruct/PreDestroy method defined on the bean class. If nothing is
// specified, the CMT default is for the method to run within a transaction. We
// actually use TX_REQUIRES_NEW to force the transaction manager to always suspend
// any existing transaction in the case that the Singleton instance is initialized
// lazily as a side effect of an invocation. Like timeout methods, from the
// developer's perspective there is never an inflowing transaction to a Singleton
// PostConstruct or PreDestroy method.
postConstructInvInfo = new InvocationInfo();
postConstructInvInfo.ejbName = ejbDescriptor.getName();
postConstructInvInfo.methodIntf = MethodDescriptor.LIFECYCLE_CALLBACK;
postConstructInvInfo.txAttr = getTxAttrForLifecycleCallback(ejbDescriptor.getPostConstructDescriptors());;
preDestroyInvInfo = new InvocationInfo();
preDestroyInvInfo.ejbName = ejbDescriptor.getName();
preDestroyInvInfo.methodIntf = MethodDescriptor.LIFECYCLE_CALLBACK;
preDestroyInvInfo.txAttr = getTxAttrForLifecycleCallback(ejbDescriptor.getPreDestroyDescriptors());
}
public String getMonitorAttributeValues() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("SINGLETON ").append(ejbDescriptor.getName());
sbuf.append("]");
return sbuf.toString();
}
@Override
protected EjbInvocation createEjbInvocation(Object ejb, ComponentContext ctx) {
EjbInvocation inv = super.createEjbInvocation(ejb, ctx);
setResourceHandler(inv);
return inv;
}
@Override
protected EjbInvocation createEjbInvocation() {
EjbInvocation inv = super.createEjbInvocation();
setResourceHandler(inv);
return inv;
}
private void setResourceHandler(EjbInvocation inv) {
// Singletons can not store the underlying resource list
// in the context impl since that is shared across many
// concurrent invocations. Instead, set the resource
// handler on the invocation to provide a different
// resource List for each Singleton invocation.
inv.setResourceHandler(SimpleEjbResourceHandlerImpl.getResourceHandler(transactionManager));
}
protected void initializeHome()
throws Exception
{
super.initializeHome();
if ( isRemote ) {
if( hasRemoteBusinessView ) {
theRemoteBusinessObjectImpl =
instantiateRemoteBusinessObjectImpl();
for(RemoteBusinessIntfInfo next :
remoteBusinessIntfInfo.values()) {
java.rmi.Remote stub = next.referenceFactory.
createRemoteReference(singletonInstanceKey);
theRemoteBusinessStubs.put
(next.generatedRemoteIntf.getName(), stub);
theRemoteBusinessObjectImpl.setStub
(next.generatedRemoteIntf.getName(), stub);
}
}
}
if ( isLocal ) {
if( hasLocalBusinessView ) {
theEJBLocalBusinessObjectImpl =
instantiateEJBLocalBusinessObjectImpl();
}
if (hasOptionalLocalBusinessView) {
theOptionalEJBLocalBusinessObjectImpl =
instantiateOptionalEJBLocalBusinessObjectImpl();
}
}
createBeanPool();
registerMonitorableComponents();
}
private void createBeanPool() {
this.singletonCtxFactory = new SingletonContextFactory();
}
private int getTxAttrForLifecycleCallback(
Set lifecycleCallbackDescriptors) throws Exception {
return getTxAttrForLifecycleCallback(lifecycleCallbackDescriptors,
Container.TX_REQUIRES_NEW, Container.TX_NOT_SUPPORTED);
}
protected void registerMonitorableComponents() {
super.registerMonitorableComponents();
_logger.log(Level.FINE, "[Singleton Container] registered monitorable");
}
protected EjbMonitoringStatsProvider getMonitoringStatsProvider(
String appName, String modName, String ejbName) {
// TODO - which stats provider to use?
return new SingletonBeanStatsProvider(getContainerId(), appName, modName, ejbName);
}
public void onReady() {
}
public EJBObjectImpl createRemoteBusinessObjectImpl()
throws CreateException, RemoteException
{
// No access check since this is an internal operation.
ejbProbeNotifier.ejbBeanCreatedEvent(getContainerId(),
containerInfo.appName, containerInfo.modName,
containerInfo.ejbName);
return theRemoteBusinessObjectImpl;
}
/**
*
*/
public EJBObjectImpl createEJBObjectImpl()
throws CreateException, RemoteException
{
throw new CreateException("EJB 2.x Remote view not supported on Singletons");
}
/**
* Called during client creation request through EJB LocalHome view.
*/
public EJBLocalObjectImpl createEJBLocalObjectImpl()
throws CreateException
{
throw new CreateException("EJB 2.x Local view not supported on Singletons");
}
/**
* Called during internal creation of session bean
*/
public EJBLocalObjectImpl createEJBLocalBusinessObjectImpl(boolean localBeanView)
throws CreateException
{
// No access checks needed because this is called as a result
// of an internal creation, not a user-visible create method.
return (localBeanView)
? theOptionalEJBLocalBusinessObjectImpl
: theEJBLocalBusinessObjectImpl;
}
// Doesn't apply to Singletons
protected void removeBean(EJBLocalRemoteObject ejbo, Method removeMethod,
boolean local)
throws RemoveException, EJBException, RemoteException
{
throw new EJBException("Not applicable to Singletons");
}
/**
* Force destroy the EJB should be a no-op for singletons.
* After Initialization completes successfully, runtime exceptions
* during invocations on the Singleton do not result in the instance
* being destroyed.
*/
protected void forceDestroyBean(EJBContextImpl sc) {
}
/**
* Not applicable to Singletons
*/
protected EJBObjectImpl getEJBObjectImpl(byte[] instanceKey) {
return null;
}
EJBObjectImpl getEJBRemoteBusinessObjectImpl(byte[] instanceKey) {
return theRemoteBusinessObjectImpl;
}
/**
* Not applicable to Singletons
*/
protected EJBLocalObjectImpl getEJBLocalObjectImpl(Object key) {
return null;
}
/**
* Called from EJBLocalObjectImpl.getLocalObject() while deserializing
* a local business object reference.
*/
EJBLocalObjectImpl getEJBLocalBusinessObjectImpl(Object key) {
return theEJBLocalBusinessObjectImpl;
}
/**
* Called from EJBLocalObjectImpl.getLocalObject() while deserializing
* a local business object reference.
*/
EJBLocalObjectImpl getOptionalEJBLocalBusinessObjectImpl(Object key) {
return theOptionalEJBLocalBusinessObjectImpl;
}
public void setSingletonLifeCycleManager(SingletonLifeCycleManager lcm) {
this.lcm = lcm;
}
protected void checkInit() {
if( singletonInitializationFailed ) {
throw new NoSuchEJBException("Singleton " + ejbDescriptor.getName() + " is unavailable " +
"because its original initialization failed.");
}
if (! singletonInitialized.get()) {
//Note: NEVER call instantiateSingletonInstance() directly from here
// The following starts all dependent beans as well
//
//Also, it is OK to call the following by concurrent threads
lcm.initializeSingleton(this);
}
}
// Called from SingletonLifeCycleManager to initialize a Singleton as part of the
// eager loading and @DependsOn sequence
public ComponentContext instantiateSingletonInstance() {
if (! singletonInitialized.get()) {
synchronized (this) {
if (! singletonInitialized.get()) {
// All other locks must be grabbed first. This check prevents
// synchronous loopback attempts during Singleton PostConstruct
if( initializationInProgress ) {
throw new EJBException("Illegal synchronous loopback call during Singleton " +
ejbDescriptor.getName() + " initialization would have resulted in deadlock");
}
initializationInProgress = true;
ClassLoader originalCCL = null;
try {
// This may be happening on the base container initialization thread
// rather than on an invocation thread so set the CCL
originalCCL = Utility.setContextClassLoader(loader);
//The following may throw exception
singletonCtx = (ComponentContext) singletonCtxFactory.create(null);
//this allows _getContext() to proceed
singletonInitialized.set(true);
} finally {
if( originalCCL != null ) {
Utility.setContextClassLoader(originalCCL);
}
}
}
}
}
return singletonCtx;
}
@Override
protected EJBContextImpl _constructEJBContextImpl(Object instance) {
return new SingletonContextImpl(instance, this);
}
private SingletonContextImpl createSingletonEJB()
throws CreateException
{
EjbInvocation ejbInv = null;
SingletonContextImpl context;
// Track whether initialization got as far as preInvokeTx.
// Needed for adequate error handling in the face of an initialization
// exception.
boolean initGotToPreInvokeTx = false;
try {
// a dummy invocation will be created by the BaseContainer to support
// possible AroundConstruct interceptors
context = (SingletonContextImpl) createEjbInstanceAndContext();
Object ejb = context.getEJB();
// this allows JNDI lookups from setSessionContext, ejbCreate
ejbInv = createEjbInvocation(ejb, context);
invocationManager.preInvoke(ejbInv);
// Perform injection right after where setSessionContext
// would be called. This is important since injection methods
// have the same "operations allowed" permissions as
// setSessionContext.
injectEjbInstance(context);
if ( isRemote ) {
if( hasRemoteBusinessView ) {
context.setEJBRemoteBusinessObjectImpl
(theRemoteBusinessObjectImpl);
}
}
if ( isLocal ) {
if( hasLocalBusinessView ) {
context.setEJBLocalBusinessObjectImpl
(theEJBLocalBusinessObjectImpl);
}
if( hasOptionalLocalBusinessView ) {
context.setOptionalEJBLocalBusinessObjectImpl
(theOptionalEJBLocalBusinessObjectImpl);
}
}
// Call preInvokeTx directly. InvocationInfo containing tx
// attribute must be set prior to calling preInvoke
ejbInv.transactionAttribute = postConstructInvInfo.txAttr;
ejbInv.invocationInfo = postConstructInvInfo;
initGotToPreInvokeTx = true;
preInvokeTx(ejbInv);
context.setInstanceKey(singletonInstanceKey);
intercept(CallbackType.POST_CONSTRUCT, context);
} catch ( Throwable th ) {
if (ejbInv != null) {
ejbInv.exception = th;
}
singletonInitializationFailed = true;
CreateException creEx = new CreateException("Initialization failed for Singleton " +
ejbDescriptor.getName());
creEx.initCause(th);
throw creEx;
} finally {
initializationInProgress = false;
if (ejbInv != null) {
try {
invocationManager.postInvoke(ejbInv);
if( initGotToPreInvokeTx ) {
postInvokeTx(ejbInv);
}
} catch(Exception pie) {
if (ejbInv.exception != null) {
_logger.log(Level.WARNING, "Exception during Singleton startup postInvoke ", pie);
} else {
ejbInv.exception = pie;
singletonInitializationFailed = true;
CreateException creEx = new CreateException("Initialization failed for Singleton " +
ejbDescriptor.getName());
creEx.initCause(pie);
throw creEx;
}
}
}
}
// Set the state to POOLED after ejbCreate so that
// EJBContext methods not allowed will throw exceptions
context.setState(EJBContextImpl.BeanState.POOLED);
context.touch();
return context;
}
protected void doTimerInvocationInit(EjbInvocation inv, Object primaryKey)
throws Exception {
if( isRemote ) {
// @@@ Revisit setting ejbObject in invocation.
// What about if bean doesn't expose a remote or local view?
// How is inv.ejbObject used in timer invocation ?
//TODO inv.ejbObject = theEJBObjectImpl;
inv.isLocal = false;
} else {
// inv.ejbObject =
inv.isLocal = true;
}
}
public boolean userTransactionMethodsAllowed(ComponentInvocation inv) {
boolean utMethodsAllowed = false;
if( isBeanManagedTran ) {
if( inv instanceof EjbInvocation ) {
EjbInvocation ejbInv = (EjbInvocation) inv;
AbstractSessionContextImpl sc = (AbstractSessionContextImpl) ejbInv.context;
// Allowed any time after dependency injection
utMethodsAllowed = (sc.getInstanceKey() != null);
}
}
return utMethodsAllowed;
}
/**
* Check if the given EJBObject/LocalObject has been removed.
* @exception NoSuchObjectLocalException if the object has been removed.
*/
protected void checkExists(EJBLocalRemoteObject ejbObj)
{
// Doesn't apply to Singletons
}
protected void afterBegin(EJBContextImpl context) {
// Singleton SessionBeans cannot implement SessionSynchronization!!
// EJB2.0 Spec 7.8.
}
protected void beforeCompletion(EJBContextImpl context) {
// Singleton SessionBeans cannot implement SessionSynchronization!!
// EJB2.0 Spec 7.8.
}
protected void afterCompletion(EJBContextImpl ctx, int status) {
// Singleton SessionBeans cannot implement SessionSynchronization!!
}
// default
public boolean passivateEJB(ComponentContext context) {
return false;
}
// default
public void activateEJB(Object ctx, Object instanceKey) {}
/** TODO
public void appendStats(StringBuffer sbuf) {
sbuf.append("\nSingletonContainer: ")
.append("CreateCount=").append(statCreateCount).append("; ")
.append("RemoveCount=").append(statRemoveCount).append("; ")
.append("]");
}
**/
protected void doConcreteContainerShutdown(boolean appBeingUndeployed) {
ClassLoader originalCCL = null;
try {
originalCCL = Utility.setContextClassLoader(loader);
// Shutdown the singleton instance if it hasn't already been shutdown.
if (singletonCtxFactory != null) {
singletonCtxFactory.destroy(singletonCtx);
}
/*TODO
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 ( hasRemoteBusinessView ) {
for(RemoteBusinessIntfInfo next :
remoteBusinessIntfInfo.values()) {
next.referenceFactory.destroyReference
(theRemoteBusinessObjectImpl.getStub
(next.generatedRemoteIntf.getName()),
theRemoteBusinessObjectImpl.getEJBObject
(next.generatedRemoteIntf.getName()));
}
}
} catch(Throwable t) {
_logger.log(Level.FINE, "Exception during Singleton shutdown", t);
} finally {
singletonCtxFactory = null;
Utility.setContextClassLoader(originalCCL);
}
}
public long getMethodReadyCount() {
return 0; //TODO FIXME
}
protected class SingletonContextFactory
implements ObjectFactory
{
public Object create(Object param) {
try {
return createSingletonEJB();
} catch (CreateException ex) {
throw new EJBException(ex);
}
}
public void destroy(Object obj) {
SingletonContextImpl singletonCtx = (SingletonContextImpl) obj;
// Note: Singletons cannot have incomplete transactions
// in progress. So it is ok to destroy the EJB.
// Only need to cleanup and destroy bean (andd call @PreDestroy)
// if it successfully completed initialization.
if ( singletonCtx != null ) {
Object sb = singletonCtx.getEJB();
// Called from pool implementation to reduce the pool size.
// So we need to call @PreDestroy and mark context as destroyed
singletonCtx.setState(EJBContextImpl.BeanState.DESTROYED);
EjbInvocation ejbInv = null;
try {
// NOTE : Context class-loader is already set by Pool
ejbInv = createEjbInvocation(sb, singletonCtx);
invocationManager.preInvoke(ejbInv);
singletonCtx.setInEjbRemove(true);
// Call preInvokeTx directly. InvocationInfo containing tx
// attribute must be set prior to calling preInvoke
ejbInv.transactionAttribute = preDestroyInvInfo.txAttr;
ejbInv.invocationInfo = preDestroyInvInfo;
preInvokeTx(ejbInv);
intercept(CallbackType.PRE_DESTROY, singletonCtx);
} catch ( Throwable t ) {
if( ejbInv != null ) {
ejbInv.exception = t;
}
_logger.log(Level.FINE, "ejbRemove exception", t);
} finally {
singletonCtx.setInEjbRemove(false);
if( ejbInv != null ) {
invocationManager.postInvoke(ejbInv);
try {
postInvokeTx(ejbInv);
} catch(Exception pie) {
_logger.log(Level.FINE, "singleton postInvokeTx exception", pie);
}
}
}
cleanupInstance(singletonCtx);
singletonCtx.deleteAllReferences();
}
}
} // SessionContextFactory{}
//Methods for StatelessSessionBeanStatsProvider
public int getMaxPoolSize() {
return 1;
}
public int getSteadyPoolSize() {
return 1;
}
//The inner class ResourceHandlerImpl has been moved into its own (top level) class called
// SimpleEjbResourceHandlerImpl because it is now used by EjbInvocation.clone() method also.
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy