package org.mobicents.slee.runtime.sbbentity; import java.util.Iterator; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.slee.ServiceID; import javax.slee.management.ServiceState; import org.apache.log4j.Logger; import org.mobicents.slee.container.SleeContainer; import org.mobicents.slee.container.management.jmx.MobicentsManagement; import org.mobicents.slee.container.service.Service; import org.mobicents.slee.runtime.activity.ActivityContext; import org.mobicents.slee.runtime.activity.ActivityContextHandle; import org.mobicents.slee.runtime.eventrouter.EventRouterActivity; import org.mobicents.slee.runtime.transaction.SleeTransactionManager; public class RootSbbEntitiesRemovalTask extends TimerTask { private static final Logger logger = Logger .getLogger(RootSbbEntitiesRemovalTask.class); // static map with scheduled tasks private static ConcurrentHashMap<ServiceID, RootSbbEntitiesRemovalTask> tasksScheduled = new ConcurrentHashMap<ServiceID, RootSbbEntitiesRemovalTask>(); // number of minutes before complete removal of lingering service // sbbentities // running static timer private static Timer runningTimer = new Timer(); // the service id of the task private ServiceID serviceID; /** * Retreives the running task for the service with the specified service id. * * @param serviceID * null if no such task is scheduled * @return */ public static RootSbbEntitiesRemovalTask getTask(ServiceID serviceID) { return tasksScheduled.get(serviceID); } /** * Constructs a new instance of a timer task that removes all sbb entities * from the service with the specified service id. * * @param serviceID */ public RootSbbEntitiesRemovalTask(ServiceID serviceID) { this.serviceID = serviceID; if (tasksScheduled.putIfAbsent(this.serviceID, this) == null) { // secondsInMinute*1000*sbbEntityRemovalDelay) long executionTime = (long) (60 * 1000 * MobicentsManagement.entitiesRemovalDelay); runningTimer.schedule(this, executionTime); if (logger.isDebugEnabled()) { logger.debug(" == Service SBB Entities REMOVAL SCHEDULED FOR:" + this.serviceID + " in [" + (double) executionTime / (1000) + "] seconds =="); } } } @Override public int hashCode() { // TODO Auto-generated method stub return this.serviceID.hashCode(); } @Override public boolean equals(Object arg0) { if (arg0 != null && arg0.getClass() == this.getClass()) { return this.serviceID .equals(((RootSbbEntitiesRemovalTask) arg0).serviceID); } else { return false; } } private void removeAllSbbEntities() { if (logger.isDebugEnabled()) { logger.debug("SBB Entities REMOVAL STARTING for service " + serviceID); } this.cancel(); final SleeContainer sleeContainer = SleeContainer.lookupFromJndi(); final SleeTransactionManager sleeTransactionManager = sleeContainer.getTransactionManager(); Iterator i = null; while (true) { try { // begin transaction sleeTransactionManager.begin(); if (i == null) { // get service Service service = sleeContainer .getServiceManagement().getService(serviceID); if (service.getState() == ServiceState.INACTIVE) { i = service.getChildObj().iterator(); } else { // wrong service state, finish task break; } } if (i.hasNext()) { final String sbbEntityId = (String) i.next(); // get sbb entity SbbEntity sbbEntity = null; try { sbbEntity = SbbEntityFactory.getSbbEntity(sbbEntityId); } catch (Exception e) { // entity does not exists anymore, continue continue; } Set attachedACs = sbbEntity.getActivityContexts(); if (logger.isDebugEnabled()) { logger.debug("sbb entity "+sbbEntityId+" is attached to ACs "+attachedACs); } boolean noTransaction = !attachedACs.isEmpty(); if (noTransaction) { // close this transaction we don't need it now sleeTransactionManager.commit(); // detach the entity from activities using the activities executor service for (Object obj : attachedACs) { final ActivityContextHandle ach = (ActivityContextHandle) obj; try { EventRouterActivity era = sleeContainer.getEventRouter().getEventRouterActivity(ach); if (era != null) { Runnable r = new Runnable() { public void run() { try { sleeTransactionManager.begin(); ActivityContext ac = sleeContainer.getActivityContextFactory().getActivityContext(ach); if (ac != null) { ac.detachSbbEntity(sbbEntityId); if (logger.isDebugEnabled()) { logger.debug("sbb entity "+sbbEntityId+" is now detached from AC "+ach); } } } catch (Exception e) { // ignore if (logger.isDebugEnabled()) { logger.debug(e.getMessage(),e); } } finally { try { sleeTransactionManager.commit(); } catch (Exception e) { // ignore if (logger.isDebugEnabled()) { logger.debug(e.getMessage(),e); } } } } }; // submit and block till it is executed era.getExecutorService().submit(r).get(); } } catch (Exception e) { // ignore if (logger.isDebugEnabled()) { logger.debug(e.getMessage(),e); } } } // create transaction and reload sbb entity whch should not have any ac attached sleeTransactionManager.begin(); try { sbbEntity = SbbEntityFactory.getSbbEntity(sbbEntityId); } catch (Exception e) { // entity does not exists anymore, continue continue; } } try { // finally remove sbb entity SbbEntityFactory.removeSbbEntity(sbbEntity, false); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("error removing entity " + sbbEntity.getSbbEntityId(), ex); } } } else { // no more entities, finish task break; } } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug( "exception while removing pending root sbb entities of service " + serviceID, e); } } finally { try { sleeTransactionManager.commit(); } catch (Exception e) { if (logger.isDebugEnabled()) { logger .debug( "exception while commiting tx while removing pending root sbb entities of service " + serviceID, e); } } } } if (logger.isDebugEnabled()) { logger.debug("SBB Entities REMOVAL ENDED for service " + serviceID); } } // @Override public void run() { synchronized (this) { // remove the task from the map if (tasksScheduled.get(serviceID) == null) { return; } if (logger.isDebugEnabled()) { logger.debug("RUNNING TASK ON SERVICE UNINSTALL FOR " + serviceID); } // run the task in the executor to have it's own transactions Runnable runnable = new Runnable() { public void run() { removeAllSbbEntities(); } }; try { executorService.submit(runnable).get(); } catch (Exception e) { logger.error( "Failed to execute task to remove pending root sbb entities of " + serviceID, e); } tasksScheduled.remove(serviceID); } } private static ExecutorService executorService = Executors .newSingleThreadExecutor(); }