org.jactr.core.runtime.DefaultModelRunner.java Source code

Java tutorial

Introduction

Here is the source code for org.jactr.core.runtime.DefaultModelRunner.java

Source

/*
 * Created on Oct 21, 2006 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu
 * (jactr.org) This library 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 library 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
 * library; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
package org.jactr.core.runtime;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.NumberFormat;
import java.util.concurrent.ExecutorService;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.buffer.IActivationBuffer;
import org.jactr.core.logging.Logger;
import org.jactr.core.model.ICycleProcessor;
import org.jactr.core.model.IModel;
import org.jactr.core.model.ModelTerminatedException;
import org.jactr.core.model.basic.BasicModel;
import org.jactr.core.model.event.ModelEvent;
import org.jactr.core.queue.TimedEventQueue;

/**
 * basic model runner, handles all events except disconnected which will be
 * handled by the controller
 * 
 * @author developer
 */
public class DefaultModelRunner implements Runnable {
    /**
     * logger definition
     */
    static private final Log LOGGER = LogFactory.getLog(DefaultModelRunner.class);

    protected ExecutorService _service;

    protected BasicModel _model;

    protected ICycleProcessor _cycleRunner;

    private NumberFormat _format;

    public DefaultModelRunner(ExecutorService service, IModel model, ICycleProcessor cycleRunner) {
        if (!(model instanceof BasicModel))
            throw new RuntimeException(
                    getClass().getSimpleName() + " only supports subclasses of " + BasicModel.class.getName());
        _model = (BasicModel) model;
        _cycleRunner = cycleRunner;
        _service = service;

        _format = NumberFormat.getNumberInstance();
        _format.setMaximumFractionDigits(3);
        _format.setMinimumFractionDigits(3);
    }

    protected void startUp() {

        /**
         * this will connect, and once it has gotten the go ahead to initialize from
         * common reality, it will call model.initialize(). we then block until it
         * gets the start command
         */
        ACTRRuntime.getRuntime().getConnector().connect(_model);

        ACTRRuntime.getRuntime().getClock(_model).setTimeShift(_model.getAge());

        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Shifted clock to " + _model.getAge());

        /**
         * let anyone who depends on commonreality know that we have connected
         */
        _model.dispatch(new ModelEvent(_model, ModelEvent.Type.CONNECTED));
    }

    protected void shutDown(Exception deferred) {

        try {
            _model.dispatch(new ModelEvent(_model, ModelEvent.Type.STOPPED, deferred));

            double age = ACTRRuntime.getRuntime().getClock(_model).getTime();
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Set model age to " + age);
            _model.setAge(age);

            ACTRRuntime.getRuntime().getConnector().disconnect(_model);
            Thread.currentThread().setName("dead-" + _model.getName());
        } catch (Exception e) {
            deferred = e;
        } finally {
            _model.dispatch(new ModelEvent(_model, ModelEvent.Type.DISCONNECTED, deferred));
        }
    }

    protected void preEventFiring() {

    }

    protected boolean firePendingEvents(double now) {
        /*
         * fire all the events that may have transpired by now
         */
        TimedEventQueue queue = _model.getTimedEventQueue();
        boolean anyFired = false;
        while (queue.fireExpiredEvents(now))
            anyFired = true;
        return anyFired;
    }

    protected void postEventFiring() {

    }

    /**
     * run a single cycle of the model
     * 
     * @return
     */
    protected double cycle(boolean eventsHaveFired) {
        return _cycleRunner.cycle(_model, eventsHaveFired);
    }

    /**
     * wait for the clock to reach this time
     * 
     * @param waitForTime
     * @throws InterruptedException
     */
    protected double waitForClock(double waitForTime) throws InterruptedException {
        if (Double.isNaN(waitForTime))
            return 0;

        double rtn = ACTRRuntime.getRuntime().getClock(_model).waitForTime(waitForTime);

        return rtn;
    }

    /**
     * called before blocking on waitForClock
     */
    protected void preClock() {

    }

    /**
     * called after waitForClock returns
     */
    protected void postClock(double currentSimulatedTime) {

    }

    /**
     * called before each cycle starts
     */
    protected void preCycle(double currentSimulatedTime) {

    }

    /**
     * called after each cycle
     */
    protected void postCycle(double nextTime) {

    }

    /**
     * run the model in loop
     * 
     * @param clock
     */
    protected void runModelLoop() {
        try {
            double startTime = waitForClock(_model.getAge());
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Starting @ " + startTime + " age:" + _model.getAge());

            /*
             * signal the start to the runtime and the model
             */
            _model.dispatch(new ModelEvent(_model, ModelEvent.Type.STARTED));

            double nextTime = startTime;

            while (!_service.isShutdown() && !Double.isNaN(nextTime)) {
                /*
                 * fire the time event
                 */
                if (Logger.hasLoggers(_model))
                    Logger.log(_model, Logger.Stream.TIME, _format.format(nextTime));

                preEventFiring();

                boolean eventsHaveFired = firePendingEvents(nextTime);

                postEventFiring();

                preCycle(nextTime);

                if (LOGGER.isDebugEnabled())
                    LOGGER.debug("set age to " + nextTime);
                _model.setAge(nextTime);

                nextTime = cycle(eventsHaveFired);

                postCycle(nextTime);

                if (!Double.isNaN(nextTime)) {
                    preClock();
                    nextTime = waitForClock(nextTime);
                    postClock(nextTime);
                } else
                    postClock(Double.NaN);
            }
        } catch (ModelTerminatedException mte) {
            // perfectly normal
        } catch (InterruptedException ie) {
            // perfectly normal
        } finally {
            /*
             * pop all the buffer contents
             */
            for (IActivationBuffer buffer : _model.getActivationBuffers())
                buffer.clear();
        }
    }

    public void run() {
        Exception deferred = null;
        try {
            startUp();
            runModelLoop();
        } catch (Exception e) {
            deferred = e;
            if (LOGGER.isErrorEnabled())
                LOGGER.error("Model:" + _model + " has thrown an exception", e);

            if (Logger.hasLoggers(_model)) {
                /*
                 * build the message..
                 */
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                Logger.log(_model, Logger.Stream.EXCEPTION, sw.toString());
            }

            try {
                _model.dispatch(new ModelEvent(_model, e));
            } catch (Exception e2) {
                // just in case
            }
        } finally {
            shutDown(deferred);
        }
    }
}