/* * JBoss, Home of Professional Open Source * Copyright 2011, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.mobicents.slee.runtime.activity; import java.util.Map; import org.apache.log4j.Logger; import org.mobicents.slee.container.SleeContainer; import org.mobicents.slee.container.activity.ActivityContextHandle; import org.mobicents.slee.container.transaction.TransactionContext; import org.mobicents.slee.container.transaction.TransactionalAction; /** * Manages references of activity contexts * @author martins * */ public class ActivityContextReferencesHandler { private static final Logger LOGGER = Logger.getLogger(ActivityContextReferencesHandler.class); private final ActivityContextImpl ac; private final static SleeContainer sleeContainer = ActivityContextImpl.sleeContainer; private final TransactionContext txContext; private TxRefCounter txRefCounter; @SuppressWarnings({ "unchecked", "rawtypes" }) public ActivityContextReferencesHandler(ActivityContextImpl ac) { this.ac = ac; txContext = sleeContainer.getTransactionManager().getTransactionContext(); if (txContext != null) { // there is a tx // cancels any ref check queued, it will be checked in the end of tx ac.getLocalActivityContext().setActivityReferencesCheck(null); Map txContextData = txContext.getData(); ActivityContextHandle ach = ac.getActivityContextHandle(); txRefCounter = (TxRefCounter) txContextData.get(ach); if (txRefCounter == null) { // lets init tx ref counter txRefCounter = new TxRefCounter(); txContextData.put(ach,txRefCounter); // and schedule ref check before tx is completed txContext.getBeforeCommitActions().add(new TxActivityReferencesCheck()); } } } public void nameReferenceCreated() { if (txContext == null) { // cancel any task queued to check if ac is unreferenced ac.getLocalActivityContext().setActivityReferencesCheck(null); } else { // we have tx, just increment tx ref counter txRefCounter.nameRefs++; } } public void nameReferenceRemoved() { if (txContext == null) { checkReferences(); } else { // we have tx, just decrement tx ref counter txRefCounter.nameRefs--; } } public void sbbeReferenceCreated(boolean fromEventDelivery) { if (txContext == null) { // cancel any task queued to check if ac is unreferenced ac.getLocalActivityContext().setActivityReferencesCheck(null); } else { // we have tx, just increment tx ref counter if (fromEventDelivery) { // reset is used when delivering event, cause we know that the // sbb entity is attached to the ac, but that ref can already be // accounted in initial event processing txRefCounter.sbbeRefs = 1; } else { txRefCounter.sbbeRefs++; } } } public void sbbeReferenceRemoved() { if (txContext == null) { checkReferences(); } else { // we have tx, just decrement tx ref counter txRefCounter.sbbeRefs--; } } public void eventReferenceCreated() { if (txContext == null) { // cancel any task queued to check if ac is unreferenced ac.getLocalActivityContext().setActivityReferencesCheck(null); } else { // we have tx, just increment tx ref counter txRefCounter.eventRefs++; } } public void timerReferenceCreated() { if (txContext == null) { // cancel any task queued to check if ac is unreferenced ac.getLocalActivityContext().setActivityReferencesCheck(null); } else { // we have tx, just increment tx ref counter txRefCounter.timerRefs++; } } public void timerReferenceRemoved() { if (txContext == null) { checkReferences(); } else { // we have tx, just decrement tx ref counter txRefCounter.timerRefs--; } } public void checkReferences() { final boolean traceLog = LOGGER.isTraceEnabled(); if (traceLog) { LOGGER.trace("checkReferences(), wrt "+ac); } final LocalActivityContextImpl localAC = ac.getLocalActivityContext(); Runnable r = new Runnable() { @Override public void run() { if (localAC.getActivityReferencesCheck() == this) { localAC.setActivityReferencesCheck(null); if (traceLog) { LOGGER.trace("Now checking for no references, wrt "+localAC.getActivityContextHandle()); } // check was not canceled ActivityContextImpl ac = localAC.getActivityContext(); if (ac != null && !ac.isEnding() && ac.isSbbAttachmentSetEmpty() && ac.isAttachedTimersEmpty() && ac.isNamingBindingEmpty()) { // invoke activity callback ac.activityUnreferenced(); } } else { if (traceLog) { LOGGER.trace("Canceled check for no references, wrt "+localAC.getActivityContextHandle()+", activity references increased or another check was queued."); } } } }; if (traceLog) { LOGGER.trace("Queueing check for no references, wrt "+localAC.getActivityContextHandle()); } localAC.setActivityReferencesCheck(r); localAC.getExecutorService().execute(r); } private static class TxRefCounter { int nameRefs = 0; int sbbeRefs = 0; int eventRefs = 0; int timerRefs = 0; } private class TxActivityReferencesCheck implements TransactionalAction { private boolean firstStage = true; @Override public void execute() { if (firstStage) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Tx check 1st stage for no references, wrt "+ac.getActivityContextHandle()); } firstStage = false; txContext.getAfterRollbackActions().add(this); if (txRefCounter.nameRefs > 0 || txRefCounter.sbbeRefs > 0 || txRefCounter.eventRefs > 0 || txRefCounter.timerRefs > 0) { // more refs added than removed, if tx commits return; } txContext.getAfterCommitActions().add(this); } else { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Tx check 2nd stage for no references, wrt "+ac.getActivityContextHandle()); } checkReferences(); } } } }