package org.jactr.core.runtime.controller.impl; /* * default logging */ import java.util.Collection; import java.util.HashSet; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.concurrent.ExecutorServices; import org.jactr.core.model.IModel; import org.jactr.core.model.event.IModelListener; import org.jactr.core.model.event.ModelEvent; import org.jactr.core.model.event.ModelListenerAdaptor; import org.jactr.core.runtime.ACTRRuntime; import org.jactr.core.runtime.event.ACTRRuntimeEvent; public class RuntimeState { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(RuntimeState.class); final private Collection<IModel> _startingModels; final private Collection<IModel> _activeModels; final private Collection<IModel> _inactiveModels; final private Collection<IModel> _suspendedModels; final private Lock _lock = new ReentrantLock(); public RuntimeState() { _startingModels = new HashSet<IModel>(); _activeModels = new HashSet<IModel>(); _inactiveModels = new HashSet<IModel>(); _suspendedModels = new HashSet<IModel>(); } public void clear() { try { _lock.lock(); _activeModels.clear(); _inactiveModels.clear(); _suspendedModels.clear(); _startingModels.clear(); } finally { _lock.unlock(); } } public void getRunning(Collection<IModel> running) { try { _lock.lock(); running.addAll(_activeModels); } finally { _lock.unlock(); } } public void getTerminated(Collection<IModel> terminated) { try { _lock.lock(); terminated.addAll(_inactiveModels); } finally { _lock.unlock(); } } public void getSuspended(Collection<IModel> suspended) { try { _lock.lock(); suspended.addAll(_suspendedModels); } finally { _lock.unlock(); } } /** * true if any models are currently running * * @return */ public boolean isRunning() { try { _lock.lock(); return _activeModels.size() != 0; } finally { _lock.unlock(); } } /** * true if all the models are suspended * * @return */ public boolean isSuspended() { try { _lock.lock(); return _suspendedModels.containsAll(_activeModels); } finally { _lock.unlock(); } } /** * called just before the full system starts. we use this to start up the * connector and onStart */ public void starting() { ACTRRuntime runtime = ACTRRuntime.getRuntime(); /* * connect to CR or local */ runtime.getConnector().start(); /* * and the custom start up */ Runnable runnable = runtime.getOnStart(); if (runnable != null) runnable.run(); } /** * called after all the models have started */ public void started() { /* * if there is any model, runtime start will be called once the first once * starts. If there are no models, we need to call it ourselves */ ACTRRuntime runtime = ACTRRuntime.getRuntime(); if (runtime.hasListeners() && runtime.getModels().size() == 0) runtime.dispatch(new ACTRRuntimeEvent(ACTRRuntimeEvent.Type.STARTED)); } /** * called just before a model starts to execute.. * * @param model */ public void starting(IModel model) { // boolean shouldFireStart = false; /* * we dont flag as started until the model is done with its set up */ IModelListener actualStart = new ModelListenerAdaptor() { @Override public void modelStarted(ModelEvent event) { IModel model = event.getSource(); actuallyStarted(model); /* * remove the listener */ model.removeListener(this); } }; model.addListener(actualStart, ExecutorServices.INLINE_EXECUTOR); try { _lock.lock(); _startingModels.add(model); // shouldFireStart = _startingModels.size() == 1 // && _activeModels.size() == 0; } finally { _lock.unlock(); } /* * call the runnable and connect reality.. but we dont fire the runtime * started until actuallyStarted() */ // if(shouldFireStart) // { // ACTRRuntime runtime = ACTRRuntime.getRuntime(); // // /* // * connect to CR or local // */ // runtime.getConnector().start(); // // /* // * and the custom start up // */ // Runnable runnable = runtime.getOnStart(); // if (runnable != null) runnable.run(); // } } private void actuallyStarted(IModel model) { boolean shouldFireEvent = false; try { _lock.lock(); if (_startingModels.remove(model)) _activeModels.add(model); shouldFireEvent = _activeModels.size() == 1; } finally { _lock.unlock(); } if (shouldFireEvent) { ACTRRuntime runtime = ACTRRuntime.getRuntime(); if (runtime.hasListeners()) runtime.dispatch(new ACTRRuntimeEvent(ACTRRuntimeEvent.Type.STARTED)); } } // public void started(IModel model) // { // boolean shouldFireStart = false; // // /* // * we don't mark the runtime as actually starting until there is a model // * in the running state, which means it must have connected to CR and fully // initialized // * first. // */ // IModelListener actualStart = new ModelListenerAdaptor() { // public void modelStarted(ModelEvent event) // { // IModel model = event.getSource(); // try // { // _lock.lock(); // if (_startingModels.remove(model)) _activeModels.add(model); // } // finally // { // _lock.unlock(); // } // /* // * remove the listener // */ // model.removeListener(this); // } // }; // // // // try // { // _lock.lock(); // _startingModels.add(model); // shouldFireStart = _startingModels.size() == 1; // } // finally // { // _lock.unlock(); // } // // /* // * we can fire this late because nothing will have happened in the model // * yet. If we fire early, we run the risk of duplicate start events since we // * cant run from within the lock // */ // if (shouldFireStart) // { // ACTRRuntime runtime = ACTRRuntime.getRuntime(); // // /* // * connect to CR or local // */ // runtime.getConnector().start(); // // /* // * and the custom start up // */ // Runnable runnable = runtime.getOnStart(); // if (runnable != null) runnable.run(); // // /* // * finally notify // */ // if (runtime.hasListeners()) // runtime.dispatch(new ACTRRuntimeEvent(ACTRRuntimeEvent.Type.STARTED)); // } // } public void stopped(IModel model) { ACTRRuntime runtime = ACTRRuntime.getRuntime(); boolean fireStopped = false; try { _lock.lock(); if (_activeModels.remove(model) || _startingModels.remove(model)) { _inactiveModels.add(model); fireStopped = _inactiveModels.containsAll(runtime.getModels()); } else if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format( "%s has stopped, but we have no record of it running or starting", model.getName())); } finally { _lock.unlock(); } /* * last model gets to onStop and notify */ if (fireStopped) { Exception deferred = null; /* * on stop.. */ try { if (runtime.getOnStop() != null) runtime.getOnStop().run(); } catch (Exception e) { LOGGER.error("Could not fire onStop ", e); deferred = e; } try { if (LOGGER.isDebugEnabled()) LOGGER.debug("Stopping connector"); runtime.getConnector().stop(); } catch (Exception e) { LOGGER.error("Could not stop connector ", e); deferred = e; } if (runtime.hasListeners()) runtime.dispatch(new ACTRRuntimeEvent(null, ACTRRuntimeEvent.Type.STOPPED, deferred)); } } public void suspended(IModel model) { ACTRRuntime runtime = ACTRRuntime.getRuntime(); boolean fireSuspended = false; try { _lock.lock(); if (_suspendedModels.add(model)) fireSuspended = _suspendedModels.containsAll(_activeModels); } finally { _lock.unlock(); } if (fireSuspended && runtime.hasListeners()) runtime.dispatch(new ACTRRuntimeEvent(ACTRRuntimeEvent.Type.SUSPENDED)); } public void resumed(IModel model) { ACTRRuntime runtime = ACTRRuntime.getRuntime(); boolean fireResumed = false; try { _lock.lock(); if (_suspendedModels.remove(model)) fireResumed = _suspendedModels.size() == 0; } finally { _lock.unlock(); } if (fireResumed && runtime.hasListeners()) runtime.dispatch(new ACTRRuntimeEvent(ACTRRuntimeEvent.Type.RESUMED)); } }