org.jactr.entry.iterative.IterativeMain.java Source code

Java tutorial

Introduction

Here is the source code for org.jactr.entry.iterative.IterativeMain.java

Source

/*
 * Created on Apr 11, 2007 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.entry.iterative;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.locks.ReadWriteLock;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.antlr.runtime.tree.CommonTree;
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.ModelEvent;
import org.jactr.core.model.event.ModelListenerAdaptor;
import org.jactr.core.runtime.ACTRRuntime;
import org.jactr.core.runtime.controller.IController;
import org.jactr.core.runtime.event.IACTRRuntimeListener;
import org.jactr.io.environment.EnvironmentParser;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * @author developer
 */
public class IterativeMain {
    /**
     * logger definition
     */
    static private final Log LOGGER = LogFactory.getLog(IterativeMain.class);

    static private final long SECONDS = 1000;

    static private final long MINUTES = SECONDS * 60;

    static private final long HOURS = MINUTES * 60;

    private boolean _aggressiveGC = true;

    static private String duration(long startTime, long stopTime) {
        long delta = stopTime - startTime;
        long h = delta / HOURS;
        long m = (delta - h * HOURS) / MINUTES;
        long s = (delta - h * HOURS - m * MINUTES) / SECONDS;
        long ms = delta - h * HOURS - m * MINUTES - s * SECONDS;
        StringBuilder sb = new StringBuilder("" + h);
        sb.append(":");
        if (m < 10)
            sb.append("0");
        sb.append(m).append(":");
        if (s < 10)
            sb.append("0");
        sb.append(s).append(".");
        if (ms < 100)
            sb.append("0");
        if (ms < 10)
            sb.append("0");
        sb.append(ms);
        return sb.toString();
    }

    /**
     * load the environment file from url
     * 
     * @param url
     * @return
     */
    public Document loadEnvironment(URL url) throws IOException, SAXException, ParserConfigurationException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder parser = factory.newDocumentBuilder();
        Document doc = parser.parse(url.openStream());
        return doc;
    }

    public void iteration(final int index, int total, Document environment, URL envURL,
            final Collection<IIterativeRunListener> listeners, final PrintWriter log)
            throws TerminateIterativeRunException {

        ExecutorServices.initialize();

        if (LOGGER.isDebugEnabled()) {
            long totalMem = Runtime.getRuntime().totalMemory();
            long freeMem = Runtime.getRuntime().freeMemory();
            LOGGER.debug("Running iteration " + index + "/" + total + " [" + freeMem / 1024 + "k free : "
                    + (totalMem - freeMem) / 1024 + "k used of " + totalMem / 1024 + "k]");
        }

        for (IIterativeRunListener listener : listeners)
            try {
                listener.preLoad(index, total);
            } catch (Exception e) {
                LOGGER.error("listener " + listener + " threw an exception ", e);
            }

        /*
         * first we use the environment to load all the model descriptors
         */
        EnvironmentParser ep = new EnvironmentParser();
        Collection<CommonTree> modelDescriptors = ep.getModelDescriptors(environment, envURL);

        for (IIterativeRunListener listener : listeners)
            try {
                listener.preBuild(index, total, modelDescriptors);
            } catch (TerminateIterativeRunException tire) {
                throw tire;
            } catch (Exception e) {
                LOGGER.error("listener " + listener + " threw an exception ", e);
            }

        /*
         * now we actually do that vodoo that we do to set up the environment this
         * will build the models, instruments, and set up common reality..
         */
        ep.process(environment, modelDescriptors);

        modelDescriptors.clear();

        ACTRRuntime runtime = ACTRRuntime.getRuntime();

        Collection<IModel> models = runtime.getModels();

        for (IModel model : models)
            model.addListener(new ModelListenerAdaptor() {

                long startTime = 0;

                long simStartTime = 0;

                boolean closed = false;

                @Override
                public void modelStarted(ModelEvent event) {
                    startTime = event.getSystemTime();
                    simStartTime = (long) (event.getSimulationTime() * 1000);
                }

                protected String header(ModelEvent event) {
                    StringBuilder sb = new StringBuilder("  <model name=\"");
                    sb.append(event.getSource()).append("\" simulated=\"");
                    sb.append(duration(simStartTime, (long) (event.getSimulationTime() * 1000)));
                    sb.append("\" actual=\"");
                    sb.append(duration(startTime, event.getSystemTime()));
                    sb.append("\" factor=\"");

                    double factor = (event.getSimulationTime() * 1000 - simStartTime)
                            / (event.getSystemTime() - startTime);
                    NumberFormat format = NumberFormat.getNumberInstance();
                    format.setMaximumFractionDigits(3);
                    sb.append(format.format(factor)).append("\"");
                    return sb.toString();
                }

                @Override
                public void modelStopped(ModelEvent event) {
                    if (!closed)
                        synchronized (log) {
                            log.println(header(event) + "/>");
                        }
                }

                @Override
                public void exceptionThrown(ModelEvent event) {
                    synchronized (log) {
                        closed = true;
                        log.println(header(event) + ">");
                        event.getException().printStackTrace(log);
                        log.println("  </model>");

                        for (IIterativeRunListener listener : listeners)
                            try {
                                listener.exceptionThrown(index, event.getSource(), event.getException());
                            } catch (TerminateIterativeRunException tire) {

                            }

                        /*
                         * from here we try to stop the runtime, but do not block.. that
                         * would be disasterous
                         */
                        IController controller = ACTRRuntime.getRuntime().getController();
                        controller.stop();
                    }
                }

            }, ExecutorServices.INLINE_EXECUTOR);

        for (IIterativeRunListener listener : listeners)
            try {
                listener.preRun(index, total, models);
            } catch (TerminateIterativeRunException tire) {
                throw tire;
            } catch (Exception e) {
                LOGGER.error("listener " + listener + " threw an exception ", e);
            }

        try {
            /*
             * start 'er up!
             */
            IController controller = runtime.getController();

            /*
             * we do the model check in case the listener is monkeying around with the
             * models (adding, removing) the controller will not ever complete if no
             * models are executed.
             */
            if (models.size() != 0)
                try {
                    controller.start().get();
                    controller.complete().get();
                } catch (InterruptedException ie) {
                    LOGGER.error("Interrupted while waiting for completion", ie);
                }

            /*
             * all done - time to notify and clean up
             */
            for (IIterativeRunListener listener : listeners)
                try {
                    listener.postRun(index, total, models);
                } catch (TerminateIterativeRunException tire) {
                    throw tire;
                } catch (Exception e) {
                    LOGGER.error("listener " + listener + " threw an exception ", e);
                }
        } catch (TerminateIterativeRunException tire) {
            throw tire;
        } catch (Throwable e) {
            throw new RuntimeException("Failed to run iteration " + index + " ", e);
        } finally {
            cleanUp(runtime);
        }
    }

    protected void cleanUp(ACTRRuntime runtime) {

        if (runtime.getConnector().isRunning())
            try {
                runtime.getConnector().stop();
            } catch (Exception e) {
                LOGGER.error("Failed to cleanly stop reality connector ", e);
            }

        Collection<IModel> models = new ArrayList<IModel>(runtime.getModels());
        for (IModel model : models)
            try {
                runtime.removeModel(model);
            } catch (Exception e) {
                LOGGER.error("Could not remove " + model, e);
            }

        if (runtime.getModels().size() != 0)
            if (LOGGER.isErrorEnabled())
                LOGGER.error("Not all models were removed " + runtime.getModels());

        /*
         * remove any runtime listeners that were installed
         */
        for (IACTRRuntimeListener runtimeListener : runtime.getListeners())
            runtime.removeListener(runtimeListener);

        /*
         * kill the executors
         */
        ExecutorServices.shutdown(10000);

        /*
         * now dipose
         */
        for (IModel model : models) {
            ReadWriteLock lock = model.getLock();
            lock.writeLock().lock();
            try {
                model.dispose();
            } catch (Exception e) {
                LOGGER.error("Could not dispose of " + model, e);
            } finally {
                lock.writeLock().unlock();
            }
        }

        runtime.setOnStart(null);
        runtime.setOnStop(null);
        runtime.setApplicationData(null);
        runtime.setController(null);
    }

    protected Collection<IIterativeRunListener> createListeners(Document document) {
        ArrayList<IIterativeRunListener> listeners = new ArrayList<IIterativeRunListener>();
        NodeList nl = document.getElementsByTagName("iterative-listener");
        for (int i = 0; i < nl.getLength(); i++)
            try {
                IIterativeRunListener listener = (IIterativeRunListener) EnvironmentParser
                        .instantiate((Element) nl.item(i), "IIterativeRunListener");
                listeners.add(listener);
            } catch (Exception e) {
                LOGGER.error("Could not create run listener from " + nl.item(i), e);
            }
        return listeners;
    }

    protected int getIterations(Document document) {
        NodeList nl = document.getElementsByTagName("iterative");
        if (nl.getLength() != 1)
            throw new RuntimeException("Must specify the iterative tag");
        try {
            return Integer.parseInt(((Element) nl.item(0)).getAttribute("iterations"));
        } catch (NumberFormatException nfe) {
            throw new RuntimeException("iterative tag must have iterations attribute");
        }
    }

    /**
     * @param url
     * @param listener
     * @param iterations
     * @throws Exception
     */
    public void run(URL url) {
        Collection<IIterativeRunListener> listeners = Collections.EMPTY_LIST;

        try {
            Document environment = loadEnvironment(url);
            int iterations = getIterations(environment);
            listeners = createListeners(environment);

            String id = System.getProperty("iterative-id");
            if (id == null)
                id = "";
            else
                id = "-" + id;

            File rootDir = new File(System.getProperty("user.dir"));
            PrintWriter log = new PrintWriter(new FileWriter("iterative-log" + id + ".xml"));
            log.println("<iterative-run total=\"" + iterations + "\">");

            DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG);

            boolean shouldExit = false;

            for (IIterativeRunListener listener : listeners)
                try {
                    listener.start(iterations);
                } catch (TerminateIterativeRunException tire) {
                    shouldExit = true;
                } catch (Exception e) {
                    if (LOGGER.isErrorEnabled())
                        LOGGER.error(listener + " threw an exception on start ", e);
                }

            long startTime = System.currentTimeMillis();

            for (int i = 1; i <= iterations; i++) {
                if (shouldExit)
                    break;

                /*
                 * create a new working directory
                 */
                File workingDir = new File(rootDir, "run-" + i);
                workingDir.mkdirs();

                ACTRRuntime.getRuntime().setWorkingDirectory(workingDir);

                log.println(" <run itr=\"" + i + "\" start=\"" + format.format(new Date()) + "\">");

                try {
                    /*
                     * let's do it.
                     */
                    if (_aggressiveGC)
                        System.gc();

                    iteration(i, iterations, environment, url, listeners, log);

                    if (_aggressiveGC)
                        System.gc();
                } catch (TerminateIterativeRunException tire) {
                    shouldExit = true;
                } catch (Exception e1) {
                    log.print(" <exception><![CDATA[");
                    e1.printStackTrace(log);
                    log.print("]]></exception>");

                    for (IIterativeRunListener listener : listeners)
                        try {
                            listener.exceptionThrown(i, null, e1);
                        } catch (TerminateIterativeRunException tire) {
                            shouldExit = true;
                        } catch (Exception e2) {
                            LOGGER.error(listener + " threw an exception on exception notification ", e2);
                        }
                }

                log.println(" </run>");
                log.flush();

                if (workingDir.list().length == 0)
                    workingDir.delete();
            }

            String duration = duration(startTime, System.currentTimeMillis());

            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Total running time : " + duration);

            log.println(" <duration value=\"" + duration + "\"/>");
            log.println("</iterative-run>");
            log.close();
        } catch (Exception e) {
            LOGGER.error("Failed to run fully", e);
            for (IIterativeRunListener listener : listeners)
                try {
                    // we ignore the return value here since we're exiting anyway
                    listener.exceptionThrown(0, null, e);
                } catch (TerminateIterativeRunException tire) {
                    // silently swallow since we're already exiting
                } catch (Exception e2) {
                    LOGGER.error(listener + " threw an exception during exception notification ", e2);
                }

        } finally {
            for (IIterativeRunListener listener : listeners)
                try {
                    listener.stop();
                } catch (Exception e) {
                    LOGGER.error(listener + " threw an exception on stop ", e);
                }
        }
    }

    static public void main(String[] args) {
        try {
            URL url = new URL(args[0]);
            IterativeMain entryPoint = new IterativeMain();
            entryPoint.run(url);
        } catch (Exception e) {
            LOGGER.error("Could not run", e);
        }
    }
}