package org.mobicents.slee.runtime.sbb; import java.io.Serializable; import java.security.AccessController; import java.security.PrivilegedAction; import javax.slee.ActivityContextInterface; import javax.slee.CreateException; import javax.slee.RolledBackContext; import javax.slee.Sbb; import javax.slee.ServiceID; import javax.slee.TransactionRequiredLocalException; import org.apache.log4j.Logger; import org.mobicents.slee.container.SleeContainer; import org.mobicents.slee.container.SleeContainerUtils; import org.mobicents.slee.container.component.SbbComponent; import org.mobicents.slee.runtime.eventrouter.EventRouterThreadLocals; import org.mobicents.slee.runtime.eventrouter.SbbInvocationState; import org.mobicents.slee.runtime.eventrouter.routingtask.EventRoutingTransactionData; import org.mobicents.slee.runtime.sbbentity.SbbEntity; /* * Francesco Moggia * M. Ranganathan Initial version * Ralf Siedow Debugging and hacks */ /** * SbbEntity implementation object. This is the wrapper object for a concrete * SBB instance that the container keeps in memory. This is also used to track * things like child relation objects for a sbb instance that has been loaded * into the slee. * * * @author Francesco Moggia * @author M. Ranganathan * @author Ralf Siedow * @author eduardomartins * */ public class SbbObject implements Serializable { /** * */ private static final long serialVersionUID = 1L; private final static SleeContainer sleeContainer = SleeContainer .lookupFromJndi(); transient private SbbObjectState state; transient private SbbInvocationState invocationState = SbbInvocationState.NOT_INVOKING; transient static private Logger log = Logger.getLogger(SbbEntity.class); /** * the service id assigned to this object */ private final ServiceID serviceID; private transient SbbEntity sbbEntity; // My SBB concrete class private SbbConcrete sbbConcrete; /** * the sbb component */ private final SbbComponent sbbComponent; /** * The Sbb context is the object through which the Sbb interacts with the * Slee */ private SbbContextImpl sbbContext; /** * Creates a new instance of SbbObject. * * @param sbbComponent . * * */ public SbbObject(ServiceID serviceID, SbbComponent sbbComponent) { this.serviceID = serviceID; this.sbbComponent = sbbComponent; this.createConcreteClass(); // set sbb context this.sbbContext = new SbbContextImpl(this); if (sbbComponent.getAbstractSbbClassInfo().isInvokeSetSbbContext()) { if (log.isDebugEnabled()) { log.debug("---> invoking setSbbContext() for " + sbbComponent); } // before invoking setSbbContext we my need to save the service id in the // thread, so the alarm facility can retreive it boolean invokingServiceSet = EventRouterThreadLocals .getInvokingService() != null; if (!invokingServiceSet) { EventRouterThreadLocals.setInvokingService(serviceID); } try { this.sbbConcrete.setSbbContext(this.sbbContext); } finally { if (!invokingServiceSet) { EventRouterThreadLocals.setInvokingService(null); } } if (log.isDebugEnabled()) { log.debug("<--- invoked setSbbContext() for " + sbbComponent); } } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of setSbbContext(), it has no body"); } } } public void setSbbEntity(SbbEntity sbbe) { this.sbbEntity = sbbe; this.sbbConcrete.setSbbEntity(sbbe); } public ServiceID getServiceID() { return this.serviceID; } public SbbEntity getSbbEntity() throws TransactionRequiredLocalException { return sbbEntity; } /** * @return Returns the state. */ public SbbObjectState getState() { return this.state; } public SbbInvocationState getInvocationState() { return this.invocationState; } public void setSbbInvocationState(SbbInvocationState state) { this.invocationState = state; } /** * @param state * The state to set. */ public void setState(SbbObjectState state) { if (log.isDebugEnabled()) log.debug("setState: current state = " + this.getState() + " new state = " + state); this.state = state; } /** * Getter for property sbbConcrete. The sbb concrete object is an instance * of the concrete class that is instantiated by the deployer. * * @return Value of property sbbConcrete. * */ public Sbb getSbbConcrete() { return sbbConcrete; } /** * Getter for property sbbContextobj. * * @return Value of property sbbContextobj. * */ public SbbContextImpl getSbbContext() { return sbbContext; } /* * (non-Javadoc) * * @see org.mobicents.slee.runtime.SbbEntity#getSbbComponent() */ public SbbComponent getSbbComponent() { return this.sbbComponent; } /** * @see javax.slee.Sbb#unsetSbbContext() */ public void unsetSbbContext() { this.sbbContext = null; if (this.getState() != SbbObjectState.POOLED) { if (log.isDebugEnabled()) log .error("unsetSbbContext: should be called from pooled state current state is " + this.getState()); } if (sbbComponent.getAbstractSbbClassInfo().isInvokeUnsetSbbContext()) { if (log.isDebugEnabled()) log.debug("unsetSbbContext " + this.sbbComponent.getSbbID()); final ClassLoader oldClassLoader = SleeContainerUtils .getCurrentThreadClassLoader(); // FIXME - hat if the sbbDescriptor is null? // What if the sbb object is not associated with an entity // This is the case if failure occurs in sbbCreate try { final ClassLoader cl = this.sbbComponent.getClassLoader(); if (System.getSecurityManager()!=null){ AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Thread.currentThread().setContextClassLoader(cl); return null; } }); } else Thread.currentThread().setContextClassLoader(cl); if (this.sbbConcrete != null) this.sbbConcrete.unsetSbbContext(); } finally { if (System.getSecurityManager()!=null) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Thread.currentThread().setContextClassLoader( oldClassLoader); return null; } }); else Thread.currentThread().setContextClassLoader(oldClassLoader); } } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of unsetSbbContext(), it has no body"); } } } /** * An SBB object transitions from the Pooled state to the Ready state when * the SLEE selects that SBB object to process an event or to service a * logic object invocation. There are two possible transitions from the * Pooled state to the Ready state: through the sbbCreate and sbbPostCreate * methods, or through the sbbActivate method. The SLEE invokes the * sbbCreate and sbbPostCreate methods when the SBB object is assigned to a * new SBB entity that has just been created explicitly by an invocation of * the create method on a ChildRelation object or implicitly by the SLEE to * process an initial event. * * @see javax.slee.Sbb#sbbCreate() * */ public void sbbCreate() throws CreateException { if (this.getState() != SbbObjectState.POOLED) { log .warn("sbbCreate: should be pooled state was " + this.getState()); } if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbCreate()) { this.invocationState = SbbInvocationState.INVOKING_SBB_CREATE; this.sbbConcrete.sbbCreate(); this.invocationState = SbbInvocationState.NOT_INVOKING; } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbCreate(), it has no body"); } } } /** * This method may throw a javax.slee.CreateException when there is an * application level problem (rather than SLEE or system level problem). The * SLEE will propagate the CreateException unchanged to the caller that * requested the creation of the SBB entity. The caller may be the SLEE or * an SBB object. The throws clause is optional. The SLEE invokes this * method with the transaction context (see Section 9.6) used to invoke the * sbbCreate method. The SBB entity enters the Ready state when * sbbPostCreate returns normally. If sbbPost- Create returns by throwing an * exception, the SBB entity does not become Ready. * * @see javax.slee.Sbb#sbbPostCreate() * */ public void sbbPostCreate() throws CreateException { if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbPostCreate()) { this.invocationState = SbbInvocationState.INVOKING_SBB_POSTCREATE; this.sbbConcrete.sbbPostCreate(); this.invocationState = SbbInvocationState.NOT_INVOKING; } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbPostCreate(), it has no body"); } } } /** * @see javax.slee.Sbb#sbbActivate() */ public void sbbActivate() { if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbActivate()) { if (log.isDebugEnabled()) { log.debug(this.toString() + ".sbbActivate()"); } if (this.getState() != SbbObjectState.POOLED) { log.warn("wrong state -- expected POOLED was " + this.getState()); } this.sbbConcrete.sbbActivate(); } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbActivate(), it has no body"); } } } /** * @see javax.slee.Sbb#sbbPassivate() */ public void sbbPassivate() { if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbPassivate()) { if (log.isDebugEnabled()) { log.debug(this.toString() + ".sbbPassivate()"); } this.sbbConcrete.sbbPassivate(); } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbPassivate(), it has no body"); } } } /** * * @see javax.slee.Sbb#sbbLoad() */ public void sbbLoad() throws TransactionRequiredLocalException { if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbLoad()) { if (log.isDebugEnabled()) { log.debug(this.toString() + ".sbbLoad()"); } sleeContainer.getTransactionManager().mandateTransaction(); if (this.getState() != SbbObjectState.READY) { log.warn("sbbLoad called from wrong state should be READY was " + this.getState()); } this.invocationState = SbbInvocationState.INVOKING_SBB_LOAD; this.sbbConcrete.sbbLoad(); this.invocationState = SbbInvocationState.NOT_INVOKING; } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbLoad(), it has no body"); } } } /* * (non-Javadoc) * * @see javax.slee.Sbb#sbbStore() */ public void sbbStore() { if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbStore()) { if (log.isDebugEnabled()) { log.debug(this.toString() + ".sbbStore()"); } sleeContainer.getTransactionManager().mandateTransaction(); if (this.getState() != SbbObjectState.READY) { log.warn("sbbStore called from wrong state should be READY was " + this.getState()); } final ClassLoader oldClassLoader = SleeContainerUtils .getCurrentThreadClassLoader(); if (this.sbbConcrete != null) { final ClassLoader cl = this.sbbComponent.getClassLoader(); try { if (System.getSecurityManager()!=null) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Thread.currentThread().setContextClassLoader(cl); return null; } }); else Thread.currentThread().setContextClassLoader(cl); if (this.sbbConcrete != null) { this.invocationState = SbbInvocationState.INVOKING_SBB_STORE; this.sbbConcrete.sbbStore(); this.invocationState = SbbInvocationState.NOT_INVOKING; if (log.isDebugEnabled()) { log.debug("Called sbbStore!"); } } else { log.error("sbbStore not called: concrete sbb is null"); } } finally { if (System.getSecurityManager()!=null) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Thread.currentThread().setContextClassLoader( oldClassLoader); return null; } }); else Thread.currentThread() .setContextClassLoader(oldClassLoader); } } } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbStore(), it has no body"); } } } public void sbbExceptionThrown(Exception exception) { boolean invoke = sbbComponent.getAbstractSbbClassInfo().isInvokeSbbExceptionThrown(); Object eventObject = null; ActivityContextInterface aci = null; if (invoke) { EventRoutingTransactionData ertd = EventRoutingTransactionData .getFromTransactionContext(); if (ertd != null) { eventObject = ertd.getEventBeingDelivered().getEvent(); aci = ertd.getAciReceivingEvent(); } if (log.isDebugEnabled()) { log.debug(this.toString() + ".sbbExceptionThrown() : exception=" + exception + " , eventObject=" + eventObject + " , aci=" + aci); } } getSbbContext().setRollbackOnly(); if (invoke) { this.sbbConcrete.sbbExceptionThrown(exception, eventObject, aci); } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbExceptionThrown(), it has no body"); } } } public void sbbRolledBack(RolledBackContext sbbRolledBackContext) { if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbRolledBack()) { if (log.isDebugEnabled()) { log.debug(this.toString() + ".sbbRolledBack() : rolledBackContext=" + sbbRolledBackContext); } ClassLoader oldClassLoader = Thread.currentThread() .getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( this.sbbComponent.getClassLoader()); this.sbbConcrete.sbbRolledBack(sbbRolledBackContext); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbRolledBack(), it has no body"); } } } public void sbbRemove() { if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbRemove()) { if (log.isDebugEnabled()) { log.debug(this.toString() + ".sbbRemove()"); } final ClassLoader oldClassLoader = SleeContainerUtils .getCurrentThreadClassLoader(); try { final ClassLoader cl = this.sbbComponent.getClassLoader(); if (System.getSecurityManager()!=null) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Thread.currentThread().setContextClassLoader(cl); return null; } }); else Thread.currentThread().setContextClassLoader(cl); if (this.sbbConcrete != null) { this.sbbConcrete.sbbRemove(); } else { if (log.isDebugEnabled()) log .debug("sbbRemove on the concrete sbb not called: concrete sbb is null"); } } finally { if (System.getSecurityManager()!=null) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Thread.currentThread().setContextClassLoader( oldClassLoader); return null; } }); else Thread.currentThread().setContextClassLoader(oldClassLoader); } } else { if (log.isDebugEnabled()) { log.debug("Skipping invocation of sbbRemove(), it has no body"); } } } private void createConcreteClass() { try { // logger.debug(sbbDescriptor.getConcreteSbbClass()); // Concrete class of the Sbb. the concrete sbb class is the // class that implements the Sbb methods. This is obtained // from the deployment descriptor and the abstract sbb class. this.sbbConcrete = (SbbConcrete) sbbComponent.getConcreteSbbClass() .newInstance(); } catch (Exception ex) { log.error("unexpected exception creating concrete class!", ex); throw new RuntimeException( "Unexpected exception creating concrete class for " + this.sbbComponent.getSbbID(), ex); } } }