/** * Copyright (C) 2001-3, Anthony Harrison anh23@pitt.edu 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; import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.ExecutionException; import java.util.concurrent.locks.ReadWriteLock; import org.antlr.runtime.tree.CommonTree; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.PosixParser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.concurrent.ExecutorServices; import org.jactr.core.logging.Logger; import org.jactr.core.logging.impl.DefaultModelLogger; import org.jactr.core.model.IModel; import org.jactr.core.runtime.ACTRRuntime; import org.jactr.core.runtime.controller.DefaultController; import org.jactr.core.runtime.controller.IController; import org.jactr.io.IOUtilities; import org.jactr.io.antlr3.compiler.CompilationWarning; import org.jactr.io.antlr3.misc.CommonTreeException; import org.jactr.io.environment.EnvironmentParser; /** * jACT-R start up application Usage: jactr --compile modelFile.jactr execution: * jactr --environment environment.env jactr --run modelFile.compiled jactr * --run modelFile.compiled --onStart class --onStop class jactr --log exit * codes: -3 unknown -2 compilation error -1 configuration error 0 success * * @author harrison * @created July 19, 2001 */ public class Main { static private final Log LOGGER = LogFactory.getLog(Main.class); /** * @param cmd */ public Main() { } /** * create the deafault environment for a run.. possibly setting up the * onStart/Stop * * @return */ public ACTRRuntime configureRuntime(ACTRRuntime runtime, CommandLine cmd) { // now we try to attach the onStart onStop if (cmd.hasOption('s')) { String className = cmd.getOptionValue('s'); try { Class runnableClass = getClass().getClassLoader().loadClass(className); Runnable runner = (Runnable) runnableClass.newInstance(); runtime.setOnStart(runner); } catch (Exception e) { LOGGER.error("Could not load the onStart class " + className, e); System.err.println("Could not load the onStart class " + className); e.printStackTrace(System.err); System.exit(-1); } } if (cmd.hasOption('p')) { String className = cmd.getOptionValue('p'); try { Class runnableClass = getClass().getClassLoader().loadClass(className); Runnable runner = (Runnable) runnableClass.newInstance(); runtime.setOnStop(runner); } catch (Exception e) { LOGGER.error("Could not load the onStop class " + className, e); System.err.println("Could not load the onStop class " + className); e.printStackTrace(System.err); System.exit(-1); } } return runtime; } /** * set up the logging for the models * * @param cmd * @return */ public ACTRRuntime configureLogging(ACTRRuntime runtime, CommandLine cmd) { if (cmd.hasOption('l')) for (IModel model : runtime.getModels()) { /* * route all the named logs to System.out */ DefaultModelLogger dml = new DefaultModelLogger(); // and attach to the available models model.install(dml); String[] logs = cmd.getOptionValues('l'); for (String logName : logs) { Logger.Stream.valueOf(logName); dml.setParameter(logName, "out"); } } return runtime; } public void waitForRuntime(ACTRRuntime runtime) { IController controller = runtime.getController(); try { controller.complete().get(); } catch (InterruptedException ie) { LOGGER.error(ie); } catch (ExecutionException e) { // TODO Auto-generated catch block LOGGER.error("Main.waitForRuntime threw ExecutionException : ", e); } } public void run(ACTRRuntime runtime) { IController controller = runtime.getController(); if (controller == null) { controller = new DefaultController(); runtime.setController(controller); } try { controller.start().get(); } catch (InterruptedException e) { // TODO Auto-generated catch block LOGGER.error("Main.run threw InterruptedException : ", e); } catch (ExecutionException e) { // TODO Auto-generated catch block LOGGER.error("Main.run threw ExecutionException : ", e); } } public void cleanUp(ACTRRuntime runtime) { if (runtime.getConnector().isRunning()) try { runtime.getConnector().stop(); } catch (Exception e) { LOGGER.error("Failed to shutdown connector ", e); } /* * detach the current controller before we exit */ runtime.setController(null); /* * and clean up */ ArrayList<IModel> toDispose = new ArrayList<IModel>(); for (IModel model : new ArrayList<IModel>(runtime.getModels())) { runtime.removeModel(model); toDispose.add(model); } /* * will kill the background threads.. */ ExecutorServices.shutdown(0); /* * and dispose. Why not dispose with the remove? listeners may still be * active even after the runtime has stopped. We dispose after the service * has been shutdown, making sure that all work has been completed */ for (IModel model : toDispose) { ReadWriteLock lock = model.getLock(); lock.writeLock().lock(); try { model.dispose(); } catch (Exception e) { LOGGER.error(String.format("Failed to dispose of %s cleanly. ", model), e); } finally { lock.writeLock().unlock(); } } } public ACTRRuntime createRuntime(URL environmentConfigFile) throws Exception { EnvironmentParser parser = new EnvironmentParser(); parser.parse(environmentConfigFile); return ACTRRuntime.getRuntime(); } public ACTRRuntime createRuntime(CommandLine cmd) throws Exception { ACTRRuntime runtime = null; if (cmd.hasOption('e')) { String envFile = cmd.getOptionValue('e'); File fp = new File(envFile); runtime = createRuntime(fp.toURL()); } return runtime; } /** * compile the models * * @param cmd */ public void compile(CommandLine cmd) { boolean error = false; if (cmd.hasOption('c')) { String[] sourceModelFiles = cmd.getOptionValues('c'); for (String source : sourceModelFiles) { ArrayList<Exception> warnings = new ArrayList<Exception>(); ArrayList<Exception> errors = new ArrayList<Exception>(); CommonTree md = null; try { URL url = new File(source).toURL(); md = IOUtilities.loadModelFile(url, warnings, errors); // compile error = !IOUtilities.compileModelDescriptor(md, warnings, errors); dumpExceptions(source, warnings); dumpExceptions(source, errors); } catch (Exception e) { LOGGER.error("Could not load " + source, e); System.err.println("Could not load " + source); e.printStackTrace(System.err); error = true; } } } if (error) System.exit(-2); } protected void dumpExceptions(String sourceFile, Collection<Exception> exceptions) { for (Exception e : exceptions) { StringBuilder builder = new StringBuilder(); builder.append("("); builder.append(sourceFile); if (e instanceof CommonTreeException) { CommonTreeException ae = (CommonTreeException) e; CommonTree node = ae.getStartNode(); builder.append(":"); builder.append(node.getLine()); builder.append(","); builder.append(node.getCharPositionInLine()); builder.append(") "); if (ae instanceof CompilationWarning) builder.append(" Warning : "); else builder.append(" Error : "); } else builder.append(") Error : "); builder.append(e.getMessage()); System.err.println(builder.toString()); } } public ACTRRuntime loadModels(ACTRRuntime runtime, CommandLine cmd) { boolean error = false; if (cmd.hasOption('r')) { String[] compiledModelFiles = cmd.getOptionValues('r'); for (String modelFile : compiledModelFiles) try { URL url = new File(modelFile).toURL(); Collection<Exception> warnings = new ArrayList<Exception>(); Collection<Exception> errors = new ArrayList<Exception>(); CommonTree md = IOUtilities.loadModelFile(url, warnings, errors); // compile IOUtilities.compileModelDescriptor(md, warnings, errors); // construct IModel model = IOUtilities.constructModel(md, warnings, errors); if (warnings.size() != 0) { System.err.println(modelFile + " has warnings"); dumpExceptions(modelFile, warnings); } if (errors.size() == 0) runtime.addModel(model); else { System.err.println(modelFile + " has errors"); dumpExceptions(modelFile, errors); } } catch (Exception e) { LOGGER.error("Could not load model from " + modelFile, e); System.err.println("Could not load model from " + modelFile); e.printStackTrace(System.err); error = true; } } if (error) System.exit(-3); return runtime; } /** * The main program for the jactr class * * @param argv * The command line arguments * @since */ public static void main(String[] argv) { try { Options options = new Options(); options.addOption(OptionBuilder.create("h")); options.addOption(OptionBuilder.create('c')); options.addOption(OptionBuilder.create('e')); options.addOption(OptionBuilder.create('r')); options.addOption(OptionBuilder.create('s')); options.addOption(OptionBuilder.create('p')); options.addOption(OptionBuilder.create('l')); CommandLineParser parser = new PosixParser(); CommandLine cmd = parser.parse(options, argv); Main env = new Main(); /* * compile */ if (cmd.hasOption('c')) env.compile(cmd); else if (cmd.hasOption('e') || cmd.hasOption('r')) { ExecutorServices.initialize(); ACTRRuntime runtime = env.configureLogging(env.loadModels( env.configureRuntime(env.createRuntime(cmd), cmd), cmd), cmd); if (cmd.hasOption('r')) env.run(runtime); env.waitForRuntime(runtime); env.cleanUp(runtime); } else { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("jactr", options); System.exit(0); } } catch (Exception e) { LOGGER.error("Main exception ", e); e.printStackTrace(); System.exit(-3); } System.exit(0); } }