package org.mobicents.slee.runtime.eventrouter.routingtask;
import javax.slee.ActivityContextInterface;
import javax.slee.RolledBackContext;
import javax.transaction.SystemException;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.ServiceComponent;
import org.mobicents.slee.container.service.Service;
import org.mobicents.slee.container.service.ServiceFactory;
import org.mobicents.slee.runtime.activity.ActivityContext;
import org.mobicents.slee.runtime.eventrouter.DeferredEvent;
import org.mobicents.slee.runtime.eventrouter.RolledBackContextImpl;
import org.mobicents.slee.runtime.sbb.SbbObject;
import org.mobicents.slee.runtime.sbb.SbbObjectPool;
import org.mobicents.slee.runtime.sbb.SbbObjectState;
import org.mobicents.slee.runtime.sbbentity.SbbEntity;
import org.mobicents.slee.runtime.sbbentity.SbbEntityFactory;
import org.mobicents.slee.runtime.transaction.SleeTransactionManager;
public class HandleSbbRollback {
private static final Logger logger = Logger.getLogger(HandleSbbRollback.class);
private final SleeContainer sleeContainer = SleeContainer.lookupFromJndi();
/**
*
* @param sbbEntity
* The sbb entity - optional - if the invocation sequence does
* not have a target sbb entity this is null
* @param sbbObject
* The sbb object - optional this is only specified if the
* invocation sequence does not have a target sbb entity
* @param eventObject
* The slee event - only specified if the transaction that rolled
* back tried to deliver an event
* @param aci
* The aci where the event was fired - only specified if the transaction that rolled
* back tried to deliver an event
* @param contextClassLoader
* @param removeRolledBack
*
*
*/
public void handleSbbRolledBack(SbbEntity sbbEntity, SbbObject sbbObject, DeferredEvent de, ActivityContextInterface aci,
ClassLoader contextClassLoader,
boolean removeRolledBack,SleeTransactionManager txMgr, boolean keepSbbEntityIfTxRollbacks) {
// Sanity checks
if ((sbbEntity == null && sbbObject == null)
|| (sbbEntity != null && sbbObject != null)) {
logger
.error("Illegal State! Only one of sbbEntity or SbbObject can be specified");
return;
}
/*
* Depending on whether exceptions were thrown during the invocation
* sequence we may need to invoke the sbbRolledBack method This must be
* done on a different sbb object and a new transaction See Spec. Sec.
* 9.12.2 for details
*/
if (logger.isDebugEnabled()) {
logger.debug("Invoking sbbRolledBack");
}
ClassLoader oldClassLoader = Thread.currentThread()
.getContextClassLoader();
boolean createERTD = false;
try {
// Only start new tx if there's a target sbb entity (6.10.1)
if (sbbEntity != null) {
txMgr.begin();
if(EventRoutingTransactionData.getFromTransactionContext()==null){
createERTD = true;
EventRoutingTransactionData ertd= new EventRoutingTransactionData(de,aci);
ertd.putInTransactionContext();
}
// we have to refresh the sbb entity by reading it frmo the
// cache
try {
sbbEntity = SbbEntityFactory.getSbbEntity(sbbEntity.getSbbEntityId());
} catch (Exception e) {
// sbb entity does not exists, recreate it
if (sbbEntity.isRootSbbEntity()) {
ServiceComponent serviceComponent = sleeContainer.getComponentRepositoryImpl().getComponentByID(sbbEntity.getServiceId());
final Service service = ServiceFactory.getService(serviceComponent);
sbbEntity = service.addChild(sbbEntity.getServiceConvergenceName());
}
else {
sbbEntity = SbbEntityFactory.createSbbEntity(sbbEntity.getSbbId(), sbbEntity.getServiceId(), sbbEntity.getParentSbbEntityId(), sbbEntity.getParentChildRelation(), sbbEntity.getRootSbbId(), sbbEntity.getServiceConvergenceName());
}
if(keepSbbEntityIfTxRollbacks) {
// recreate attachment too
ActivityContext ac = ((org.mobicents.slee.runtime.activity.ActivityContextInterface)aci).getActivityContext();
if (ac.attachSbbEntity(sbbEntity.getSbbEntityId())) {
sbbEntity.afterACAttach(ac.getActivityContextHandle());
}
}
else {
// the sbb entity recreated should not be kept
txMgr.setRollbackOnly();
}
}
}
RolledBackContext rollbackContext = new RolledBackContextImpl(
de!=null?de.getEvent():null,
aci, removeRolledBack);
Thread.currentThread().setContextClassLoader(contextClassLoader);
if (sbbEntity != null) {
// We invoke the callback method a *different* sbb object 9.12.2
// and 6.10.1
if (logger.isDebugEnabled()) {
logger
.debug("Invoking sbbRolledBack on different sbb object");
}
SbbObjectPool pool = sbbEntity.getObjectPool();
// Get rid of old object (if any) first
if (sbbEntity.getSbbObject() != null) {
// This was set to DOES_NOT_EXIST here because
// unsetSbbContext
// should not be called in this case.
sbbEntity.getSbbObject().setState(
SbbObjectState.DOES_NOT_EXIST);
pool.invalidateObject(sbbEntity.getSbbObject());
}
sbbEntity.assignSbbObject();
sbbObject = sbbEntity.getSbbObject();
sbbObject.sbbLoad();
}
if (logger.isDebugEnabled()) {
logger.debug("Invoking sbbRolledBack");
}
// We only invoke this on objects in the ready state 6.10.1
// E.g. if an exception was thrown from a sbbCreate then there will
// be no sbb entity
// and the the sbbobject won't be in the ready state so we invoke it
if (sbbObject.getState() == SbbObjectState.READY)
sbbObject.sbbRolledBack(rollbackContext);
if (sbbEntity != null) {
sbbObject.sbbStore();
try {
if (txMgr.getRollbackOnly()) {
txMgr.rollback();
}
else {
if(createERTD)
{
EventRoutingTransactionData.getFromTransactionContext().removeFromTransactionContext();
}
txMgr.commit();
}
} catch (SystemException ex) {
throw new RuntimeException("tx manager System Failure ", ex);
}
}
} catch (Exception e) {
// If an exception is thrown here we just log it and don't retry
if (sbbObject != null && sbbEntity != null) {
sbbObject = sbbEntity.getSbbObject();
sbbObject.setState(SbbObjectState.DOES_NOT_EXIST);
}
logger
.error(
"Exception thrown in attempting to invoke sbbRolledBack",
e);
sbbObject.sbbExceptionThrown(e);
} finally {
try {
if (txMgr.getTransaction() != null) {
try {
if (txMgr.getRollbackOnly()) {
txMgr.rollback();
}
else {
txMgr.commit();
}
} catch (SystemException ex) {
throw new RuntimeException("tx manager System Failure ", ex);
}
}
} catch (Exception e2) {
logger.error("Failed to commit transaction", e2);
throw new RuntimeException("Failed to commit tx ", e2);
}
finally {
Thread.currentThread().setContextClassLoader(oldClassLoader);
}
}
}
}