/*
* SbbLocalInterfaceImpl.java
*
* Created on June 28, 2004, 3:54 PM
*
* The Mobicents Open SLEE Project
*
* A SLEE for the People!
*
* The source code contained in this file is in in the public domain.
* It can be used in any project or product without prior permission,
* license or royalty payments. There is no claim of correctness and
* NO WARRANTY OF ANY KIND provided with this code.
*/
package org.mobicents.slee.runtime.sbb;
import javax.slee.NoSuchObjectLocalException;
import javax.slee.RolledBackContext;
import javax.slee.SLEEException;
import javax.slee.SbbLocalObject;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.TransactionRolledbackLocalException;
import javax.transaction.SystemException;
import javax.transaction.TransactionRequiredException;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.runtime.eventrouter.RolledBackContextImpl;
import org.mobicents.slee.runtime.eventrouter.routingtask.EventRoutingTransactionData;
import org.mobicents.slee.runtime.sbbentity.SbbEntity;
import org.mobicents.slee.runtime.sbbentity.SbbEntityFactory;
import org.mobicents.slee.runtime.transaction.TransactionalAction;
/**
* This is a SLEE provided interface to the Sbb object. The SLEE uses this
* interface to allow sbbs to access local methods.
*
* The following is excerpted from Slee Spec
* <p>
* An SBB may define SBB specific local interface methods in an SBB specific
* local interface. The SBB specific local interface must be public and must
* extend, either directly or indirectly, the SbbLocalObject interface. All SBBs
* have an SBB local interface. If the SBB Developer does not provide an SBB
* local interface for an SBB, then the SBB local interface of the SBB is the
* generic SbbLocalObject interface. The names of the SBB specific local
* interface methods must not begin with �sbb� or �ejb�. The SLEE provides the
* implementation of the methods defined in the SBB local interface. More
* precisely, the SLEE provides a concrete class that implements each SBB local
* interface. An SBB local object is an instance of this class. The SLEE
* provided implementations of these methods delegate invocations on an SBB
* local object that represents an SBB entity to an SBB object that represents
* the SBB entity (if the SBB entity has not been removed). The SBB Developer
* provides the implementation of SBB Developer defined local interface methods
* declared in the SBB specific extension of the SbbLocalObject interface in the
* SBB abstract class. For each method defined by the SBB Developer, there must
* be a matching method in the SBB abstract class. The matching method must
* have:
* <ul>
* <li>The same name.
* <li>The same number of arguments, and same argument and return types.
* <li>The same set of exceptions in the throws clause.
* </ul>
*
* <p>
* All SBB local objects that represent an SBB entity that does not exist are
* invalid. An attempted invocation on an invalid SBB local object marks the
* current transaction for rollback and throws a
* javax.slee.TransactionRolledbackLocalException (a subclass of javax.slee.
* SLEEException). An SBB Developer defined local interface method is a
* mandatory transactional method (see Section 9.6.1). The SLEE throws a
* javax.slee.TransactionRequiredLocalException if an SBB Developer defined
* local interface method of an SBB local object is invoked without a valid
* transaction context.
*
* <p>
* This method may also throw a javax.slee.SLEEException if the method failed
* due to a SLEE level or system level failure. If the caller of this method
* receives this exception, the caller does not know, in general, whether the
* corresponding method implementation in the SBB abstract class was invoked.
* The caller also does not know if the transaction has been marked for
* rollback. However, the caller may determine the transaction status by using
* the getRollbackOnly method (see Section 6.10.3).
* <p>
* The SBB Developer defined SBB local interface methods must not throw
* java.rmi.Remote- Exception, any subclass of RemoteException, or any
* RuntimeException. For more information on exception handling for SBB local
* object invocations, see Section 6.9.
* <p>
* Parameters to local interface methods are passed by reference.
* <p>
* Note that the SbbLocalObject does not expose the methods of the
* javax.slee.Sbb interface, event handler methods, or the various callback
* methods. These methods are used by the SLEE to manage SBB object instances,
* deliver events, and handle callbacks.
*
* @author M. Ranganathan
* @author F. Moggia
* @author eduardomartins
*/
public class SbbLocalObjectImpl implements SbbLocalObject,
SbbLocalObjectConcrete {
private ClassLoader contextClassLoader;
/** This is the Sbb entity to which the local object maps */
private String sbbEntityId;
/**
* Container where this resides -- for now this is the same location where
* the sbb resides.
*/
private SleeContainer sleeContainer;
private static final Logger logger = Logger.getLogger(SbbLocalObjectImpl.class);
private boolean rollbackOnly;
/*
* This flag is set to true if the sbb local object is removed (no longer
* valid)
*/
private boolean isRemoved;
public SbbLocalObjectImpl() {
}
public SbbEntity getSbbEntity() {
return SbbEntityFactory.getSbbEntity(this.sbbEntityId);
}
/**
* We need this in case we want to invoke some methods on the sbb using the
* local object.
*
* @return the classloader from the Descriptor.
*/
public ClassLoader getContextClassLoader() {
return this.contextClassLoader;
}
/**
* Constructor -- assume that the Sbb entity is co-located with the Sbb
* local object.
*
* @param sbbEntity --
* sbb entity for which this is a local object.
*/
public SbbLocalObjectImpl(SbbEntity sbbEntity) {
this();
this.sleeContainer = SleeContainer.lookupFromJndi();
this.contextClassLoader = sbbEntity.getSbbComponent().getClassLoader();
this.sbbEntityId = sbbEntity.getSbbEntityId();
if (sbbEntity.getSbbObject() == null){
try {
// Check if the object is in the cache or not is not
// enough to determine if sbbCreate should be called
sbbEntity.assignSbbObject();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(logger.isDebugEnabled())
logger.debug("sbbLocalObject created for sbbEntity "
+ sbbEntity.getSbbEntityId());
}
public byte getSbbPriority() throws TransactionRequiredLocalException,
NoSuchObjectLocalException, SLEEException {
sleeContainer.getTransactionManager().mandateTransaction();
if (this.rollbackOnly) {
try {
sleeContainer.getTransactionManager().setRollbackOnly();
} catch (SystemException ex) {
throw new SLEEException("unable to set rollbackOnly in transaction manager", ex);
}
throw new TransactionRolledbackLocalException(
"Unable to proceed, transaction is set to rollback");
}
if (this.isRemoved)
throw new NoSuchObjectLocalException("sbb local object is removed");
sleeContainer.getTransactionManager().mandateTransaction();
return this.getSbbEntity().getPriority();
}
public boolean isIdentical(SbbLocalObject obj)
throws TransactionRequiredLocalException, SLEEException {
sleeContainer.getTransactionManager().mandateTransaction();
// emmartins: adding checks for object state
if (this.rollbackOnly) {
try {
sleeContainer.getTransactionManager().setRollbackOnly();
} catch (SystemException ex) {
throw new SLEEException("unable to set rollbackOnly in transaction manager", ex);
}
throw new TransactionRolledbackLocalException(
"Unable to proceed, transaction is set to rollback");
}
else if (this.isRemoved) {
throw new NoSuchObjectLocalException("sbb local object is removed");
}
else {
return this.equals(obj);
}
}
public void remove() throws TransactionRequiredLocalException,
NoSuchObjectLocalException, SLEEException {
if(logger.isDebugEnabled())
logger.debug("remove() called on sbbLocalObject "
+ this.getSbbEntityId()
+ " isRollback = " + this.rollbackOnly
+ " isRemoved = " + this.isRemoved);
sleeContainer.getTransactionManager().mandateTransaction();
if (this.rollbackOnly) {
try {
sleeContainer.getTransactionManager().setRollbackOnly();
} catch (SystemException ex) {
throw new SLEEException("unable to set rollbackOnly in transaction manager", ex);
}
throw new TransactionRolledbackLocalException(
"Unable to proceed, transaction is set to rollback");
}
// Ralf: I've put this after the if(isrolledback)
if (this.isRemoved)
throw new NoSuchObjectLocalException("sbb local object is removed");
// emmartins: moved here because of test 323
SbbEntity sbbEntity = this.getSbbEntity();
sbbEntity.checkReEntrant();
if (logger.isDebugEnabled()) {
logger.debug("nonSleeInitiatedCascadingRemoval : " + sbbEntity.getSbbId()
+ " entityID = " + sbbEntityId);
}
try {
SbbEntityFactory.removeSbbEntity(sbbEntity, true);
} catch (TransactionRequiredException e1) {
throw new TransactionRequiredLocalException("Removal of the sbb entity failed", e1);
} catch (SystemException e) {
throw new RuntimeException("Removal of the sbb entity failed",e);
}
try {
if (sleeContainer.getTransactionManager().getRollbackOnly()) {
EventRoutingTransactionData ertd = EventRoutingTransactionData.getFromTransactionContext();
RolledBackContext sbbRolledBackContext = new RolledBackContextImpl(
ertd.getEventBeingDelivered().getEvent(),ertd.getAciReceivingEvent(), true);
sleeContainer.getTransactionManager()
.addAfterRollbackAction(
new RolledBackAction(sbbEntityId,
sbbRolledBackContext));
}
} catch (Exception e) {
throw new RuntimeException("Failed to check and possibly set rollback context of entity "+sbbEntityId,e);
}
// I Think this should set isRemoved only to true but then test 323
// will fail.
// :-(
// Ralf: see above
this.rollbackOnly = true;
this.isRemoved = true;
}
public void setSbbPriority(byte priority)
throws TransactionRequiredLocalException,
NoSuchObjectLocalException, SLEEException {
sleeContainer.getTransactionManager().mandateTransaction();
if (this.rollbackOnly) {
try {
sleeContainer.getTransactionManager().setRollbackOnly();
} catch (SystemException ex) {
throw new SLEEException("unable to set rollbackOnly in transaction manager", ex);
}
throw new TransactionRolledbackLocalException(
"Could not set sbb priority");
}
if (this.isRemoved)
throw new NoSuchObjectLocalException("sbb local object is removed");
this.getSbbEntity().setPriority(priority);
}
public boolean equals(Object obj) {
if (obj != null && obj.getClass() == this.getClass()) {
SbbLocalObjectImpl other = (SbbLocalObjectImpl) obj;
return this.getSbbEntityId().equals(
other.getSbbEntityId()) && this.isRemoved == other.isRemoved;
}
else {
return false;
}
}
@Override
public int hashCode() {
return this.getSbbEntityId().hashCode();
}
public String getSbbEntityId() {
return this.sbbEntityId;
}
private class RolledBackAction implements TransactionalAction {
String sbbeId;
RolledBackContext rollbackContext;
public RolledBackAction(String sbbeId,
RolledBackContext context) {
this.sbbeId = sbbeId;
this.rollbackContext = context;
}
public void execute() {
SbbEntity sbbe = null;
try {
sleeContainer.getTransactionManager().begin();
sbbe = SbbEntityFactory.getSbbEntity(sbbeId);
sbbe.sbbRolledBack(rollbackContext);
sbbe.getSbbObject().sbbStore();
sleeContainer.getTransactionManager().commit();
} catch (RuntimeException e) {
if (sbbe != null) {
sbbe.trashObject();
logger.error("Exception while executing RolledBackAction",e);
try {
if (sleeContainer.getTransactionManager().getTransaction() != null)
sleeContainer.getTransactionManager().rollback();
} catch (SystemException e1) {
logger.error(e1);
}
}
} catch (Exception e) {
if (sbbe != null) {
sbbe.trashObject();
logger.error("Exception while executing RolledBackAction",e);
try {
if (sleeContainer.getTransactionManager().getTransaction() != null)
sleeContainer.getTransactionManager().rollback();
} catch (SystemException e1) {
logger.error(e1);
}
}
}
}
}
}