package org.mobicents.slee.runtime.eventrouter; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import javax.slee.SLEEException; import javax.slee.management.SleeState; import org.apache.log4j.Logger; import org.mobicents.slee.container.LogMessageFactory; import org.mobicents.slee.container.SleeContainer; import org.mobicents.slee.runtime.activity.ActivityContextHandle; import org.mobicents.slee.runtime.eventrouter.routingtask.EventRoutingTask; /** * * @author Eduardo Martins */ public class EventRouterImpl implements EventRouter { private static Logger logger = Logger.getLogger(EventRouter.class); /** * the container's anchor object */ private final SleeContainer container; /** * the {@link EventRouterActivity} objects, which hold all runtime structures related to the activity */ private final ConcurrentHashMap<ActivityContextHandle, EventRouterActivity> activities = new ConcurrentHashMap<ActivityContextHandle, EventRouterActivity>(); /** * The array of {@link ExecutorService}s that are used to route events */ private ExecutorService[] executors; private boolean monitorPendingACAttachements; /** * the object used to manage event references */ private final DeferredEventReferencesManagement eventReferencesManagement = new DeferredEventReferencesManagement(); public EventRouterImpl(SleeContainer container, int executors, boolean monitorPendingAcAttachments) { this.container = container; final long period = 60*60*1000; container.getNonClusteredScheduler().scheduleAtFixedRate(new LocalResourcesGarbageCollectionTimerTask(), period, period, TimeUnit.MILLISECONDS); config(executors, monitorPendingAcAttachments); logger .info("Mobicents JAIN SLEE Event Router started. Event Executors: " + executors + " Monitoring Pending AC Attachments: " + monitorPendingAcAttachments); } public void routeEvent(DeferredEvent de) { if (logger.isDebugEnabled()) { logger.debug("Routing event: " + de.getEventTypeId() + " activity context " + de.getActivityContextHandle() + " address " + de.getAddress()); } if (container.getSleeState() == SleeState.STOPPED) { throw new SLEEException( "Mobicents SLEE container is in STOPPED state. Cannot route events."); } // execute routing of event de.getEventRouterActivity().getExecutorService().execute(new EventRoutingTask(de)); } public void activityEnded(ActivityContextHandle ach) { activities.remove(ach); } /* * Maps an executor to an activity * * @return */ private ExecutorService mapExecutor(ActivityContextHandle ach) { return executors[activities.size() % executors.length]; } @Override public String toString() { return "EventRouter: " + "\n+-- Executors: " + executors.length + "\n+-- Activities: " + activities.keySet(); } public void config(int eventExecutorsSize, boolean monitoringUncommittedAcAttachs) { if (container.getSleeState() != SleeState.RUNNING) { // get ridden of old executors, if any if (this.executors != null) { for (ExecutorService executorService : this.executors) { executorService.shutdown(); } } // create new ones this.executors = new ExecutorService[eventExecutorsSize]; for (int i = 0; i < eventExecutorsSize; i++) { this.executors[i] = Executors.newSingleThreadExecutor(); } this.monitorPendingACAttachements = monitoringUncommittedAcAttachs; } else { throw new IllegalStateException("can't config event router with current slee state"); } } public EventRouterActivity getEventRouterActivity(ActivityContextHandle ach) { EventRouterActivity era = activities.get(ach); if (era == null) { PendingAttachementsMonitor pendingAttachementsMonitor = null; if (monitorPendingACAttachements) { pendingAttachementsMonitor = new PendingAttachementsMonitor(); } final EventRouterActivity newEra = new EventRouterActivity(ach,pendingAttachementsMonitor,container); era = activities.putIfAbsent(ach,newEra); if (era == null) { era = newEra; era.setExecutorService(mapExecutor(ach)); } } return era; } public void resumeEventContext(EventContextImpl eventContextImpl) { new EventRoutingTask(eventContextImpl.getDeferredEvent()).run(); } public DeferredEventReferencesManagement getDeferredEventReferencesManagement() { return eventReferencesManagement; } /** * Runnable to remove event router local resources for activities that are already gone */ private class LocalResourcesGarbageCollectionTimerTask implements Runnable { /* * (non-Javadoc) * @see java.lang.Runnable#run() */ public void run() { if (logger.isDebugEnabled()) { logger.debug("Running Event Router's activities local resources garbage collection task"); } try { final Set<ActivityContextHandle> set = new HashSet<ActivityContextHandle>(activities.keySet()); if (logger.isDebugEnabled()) { logger.debug("Current Event Router's activities local resources: "+set); } set.removeAll(container.getActivityContextFactory().getAllActivityContextsHandles()); for (ActivityContextHandle ach : set) { if (logger.isDebugEnabled()) { logger.debug(LogMessageFactory.newLogMessage(ach, "Removing the event router local resources for the activity")); } activities.remove(ach); } } catch (Throwable e) { logger.error("Failure in event router activity resources garbage collection",e); } } } }