package org.mobicents.slee.runtime.eventrouter.routingtask;
import java.util.Iterator;
import javax.transaction.SystemException;
import org.apache.log4j.Logger;
import org.mobicents.slee.runtime.activity.ActivityContext;
import org.mobicents.slee.runtime.activity.ActivityContextFactory;
import org.mobicents.slee.runtime.activity.ActivityContextHandle;
import org.mobicents.slee.runtime.sbbentity.SbbEntity;
import org.mobicents.slee.runtime.sbbentity.SbbEntityFactory;
import org.mobicents.slee.runtime.transaction.SleeTransactionManager;
public class ActivityEndEventPostProcessor {
private static final Logger logger = Logger.getLogger(ActivityEndEventPostProcessor.class);
private static final HandleRollback handleRollback = new HandleRollback();
private static final HandleSbbRollback handleSbbRollback = new HandleSbbRollback();
/**
*
* Execute cascading remove on any root sbb entities whose attachment count
* has gone to zero after activity end event has detached the sbbs. If the
* activity end event is a received event for the sbb then this would be
* handled in the previous slee originated invocation sequence. It's done
* here in the case that the sbb is attached to the ac and so needs to be
* detached but activity end event is not one of it's received events. So
* this is a SLEE Originated Invocation Sequence containing at most one SLEE
* Originated Invocation of type "Remove Only"
*
* @param ach the {@link ActivityContext} id of the activity which is ending
* @return
* @throws SystemException
*/
public void process(ActivityContextHandle ach,SleeTransactionManager txMgr, ActivityContextFactory acf) throws SystemException {
if (logger.isDebugEnabled()) {
logger.debug("Handling an activity end event on AC "+ ach);
}
boolean loopAgain = false;
Iterator<?> iter = null;
do {
boolean invokeSbbRolledBack = false;
Exception caught = null;
SbbEntity rootSbbEntity = null;
SbbEntity sbbEntity = null;
ActivityContext ac = null;
String sbbEntityId = null;
try {
// 1. start a new tx for each sbb entity attached
txMgr.begin();
// 2. load ac
ac = (ActivityContext) acf.getActivityContext(ach);
// 3. get sbbs attached, once is enough since when activity ended no new attachments can be done
if (iter == null) {
iter = ac.getSbbAttachmentSet().iterator();
}
if (iter.hasNext()) {
// 4.1. load next sbb entity
sbbEntityId = (String) iter.next();
try {
sbbEntity = SbbEntityFactory.getSbbEntity(sbbEntityId);
} catch (Exception e) {
// silently ignore, the sbb entity may be removed concurrently, we don't care
}
if (logger.isDebugEnabled()) {
logger.debug("Dettaching sbb entity " + sbbEntityId + " on handle activity end event for ac " + ach);
}
if (sbbEntity != null) {
// 4.2. if sbb entity found then detach from ac
sbbEntity.afterACDetach(ach);
// 4.3. get the sbb entity root
if (sbbEntity.isRootSbbEntity()) {
rootSbbEntity = sbbEntity;
} else {
try {
rootSbbEntity = SbbEntityFactory.getSbbEntity(sbbEntity.getRootSbbId());
} catch (Exception e) {
// silently ignore, the sbb entity may be removed concurrently, we don't care
}
}
if (rootSbbEntity != null && rootSbbEntity.getAttachmentCount() == 0) {
// 4.4. claim root sbb entity if its attach count is 0
if (logger.isDebugEnabled()) {
logger.debug("Removing root sbb entity "+sbbEntity.getRootSbbId()+" because AC attachement count is now 0.");
}
SbbEntityFactory.removeSbbEntity(rootSbbEntity,true);
}
}
}
// 5. raise flag to another loop if there is another sbb entity to detach the AC
loopAgain = iter.hasNext();
if (!loopAgain) {
// 6. there are no more sbb entities, lets use this tx to remove the AC
acf.removeActivityContext(ac);
}
} catch (Exception e) {
logger.error("Failure while handling ActivityEndEvent for ac with handle "+ach, e);
caught = e;
loopAgain = true;
} finally {
if (rootSbbEntity != null) {
invokeSbbRolledBack = handleRollback.handleRollback(null,caught,rootSbbEntity.getSbbComponent().getClassLoader(),txMgr);
}
try {
txMgr.commit();
// We may need to run sbbRolledBack
if (invokeSbbRolledBack) {
try {
if (rootSbbEntity != null) {
handleSbbRollback.handleSbbRolledBack(rootSbbEntity, null, null, null, rootSbbEntity.getSbbComponent().getClassLoader(), true, txMgr,false);
}
} catch (Exception ex) {
logger.error("problem in handleSbbRolledBack processing! ",ex);
}
}
} catch (Exception ex) {
logger.error("Problem committing transaction!", ex);
// reset flag to do another round, ac removal must be ensured
loopAgain = true;
}
}
} while (loopAgain);
}
}