package org.trianacode; import org.apache.commons.logging.Log; import org.trianacode.config.Locations; import org.trianacode.config.ModuleClassLoader; import org.trianacode.config.PropertyLoader; import org.trianacode.config.TrianaProperties; import org.trianacode.config.cl.ArgumentParser; import org.trianacode.config.cl.ArgumentParsingException; import org.trianacode.config.cl.TrianaOptions; import org.trianacode.discovery.ResolverRegistry; import org.trianacode.discovery.ToolMetadataResolver; import org.trianacode.enactment.logging.Loggers; import org.trianacode.error.ErrorTracker; import org.trianacode.error.SystemOutErrorListener; import org.trianacode.http.HTTPServices; import org.trianacode.taskgraph.TaskGraphManager; import org.trianacode.taskgraph.databus.DataBus; import org.trianacode.taskgraph.databus.DataBusInterface; import org.trianacode.taskgraph.interceptor.Interceptor; import org.trianacode.taskgraph.interceptor.InterceptorChain; import org.trianacode.taskgraph.proxy.ProxyFactory; import org.trianacode.taskgraph.ser.Base64ObjectDeserializer; import org.trianacode.taskgraph.ser.ObjectDeserializationManager; import org.trianacode.taskgraph.tool.*; import org.trianacode.taskgraph.util.ExtensionFinder; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * This class represents an instance of Triana and allows arguments to be passed to it and properties for * defining the various parameters that Triana can accept. * <p/> * All references are now NON STATIC and propagated these through the many classes that expected * static references. Also configured this so that it can accept * command line arguments (need to be defined) and it now creates all of the necessary classes required by * an instance e.g. properties. * * @author Andrew Harrison, rewrite by Ian T, rewrite and Andrew H * @version 1.0.0 Jul 22, 2010 */ public class TrianaInstance { private static Log log = Loggers.CONFIG_LOGGER; private ThreadPoolExecutor executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 5, Runtime.getRuntime().availableProcessors() * 20, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(Runtime.getRuntime().availableProcessors() * 20)); private HTTPServices httpServices; private ToolResolver toolResolver; private ErrorTracker errorTracker; private Map<Class, Set<Object>> extensions = new HashMap<Class, Set<Object>>(); private TrianaProperties props; private PropertyLoader propertyLoader; //private DiscoverTools discoveryTools; private ToolTable toolTable; private ArgumentParser parser; private List<Class> extensionClasses = new ArrayList<Class>(); private List<String> extraToolboxes = new ArrayList<String>(); private List<String> modulePaths = new ArrayList<String>(); private boolean runServer = false; private boolean reresolve = false; private boolean suppressDefaultToolboxes = false; public TrianaInstance() throws IOException { this(null); } /** * Creates am instance of Triana. * * @param args command line arguments * @throws Exception */ public TrianaInstance(String[] args) throws IOException { errorTracker = ErrorTracker.getErrorTracker(); errorTracker.addErrorListener(new SystemOutErrorListener()); executorService.allowCoreThreadTimeOut(true); if (args == null) { args = new String[0]; } this.parser = new ArgumentParser(args); try { parser.parse(); } catch (ArgumentParsingException e) { throw new RuntimeException("cannot read arguments"); } this.runServer = TrianaOptions.hasOption(parser, TrianaOptions.SERVER_OPTION); this.reresolve = TrianaOptions.hasOption(parser, TrianaOptions.RESOLVE_THREAD_OPTION); List<String> toolboxes = TrianaOptions.getOptionValues(parser, TrianaOptions.EXTRA_TOOLBOXES_OPTION); if (toolboxes != null) { this.extraToolboxes.addAll(toolboxes); } List<String> modules = TrianaOptions.getOptionValues(parser, TrianaOptions.EXTRA_MODULES_OPTION); if (modules != null) { this.modulePaths.addAll(modules); } String existing = Locations.getDefaultConfigFile(); File f = new File(existing); if (!f.exists()) { propertyLoader = new PropertyLoader(this, null); } else { Properties p = new Properties(); FileInputStream fin = new FileInputStream(f); p.load(fin); fin.close(); propertyLoader = new PropertyLoader(this, p); } props = propertyLoader.getProperties(); // This is to give the option to only load toolboxes given at the command line. No defaults to be selected. if (TrianaOptions.hasOption(parser, TrianaOptions.SUPPRESS_DEFAULT_TOOLBOXES)) { System.out.println("Default toolboxes suppressed"); props.put(TrianaProperties.TOOLBOX_SEARCH_PATH_PROPERTY, ""); suppressDefaultToolboxes = true; } } public void init(TrianaInstanceProgressListener progress, boolean resolve) throws IOException { if (progress != null) { progress.setProgressSteps(4); progress.showCurrentProgress("Initializing Engine"); } //load modules first - this just adds stuff to the class path initModules(modulePaths); initExtensions(extensionClasses); toolResolver = new ToolResolver(props, suppressDefaultToolboxes); toolTable = new ToolTableImpl(toolResolver); ProxyFactory.initProxyFactory(); TaskGraphManager.initTaskGraphManager(props); TaskGraphManager.initToolTable(toolTable); initObjectDeserializers(); httpServices = new HTTPServices(); if (runServer) { toolResolver.addToolListener(httpServices.getWorkflowServer()); httpServices.startServices(toolResolver); //discoveryTools = new DiscoverTools(toolResolver, httpServices.getHttpEngine(), props); } if (resolve) { if (progress != null) { progress.showCurrentProgress("Searching for local tools"); } try { toolResolver.resolve(reresolve, extraToolboxes); } catch (Throwable throwable) { System.out.println("Error in toolResolver.resolve()" + throwable.getCause().toString()); } } if (progress != null && runServer) { progress.showCurrentProgress("Started Discovery and HTTP Services"); } new ShutdownHook().createHook(); if (progress != null) { progress.showCurrentProgress("Triana Initialization complete"); } } public void init(boolean resolve) throws IOException { init(null, resolve); } public void init() throws IOException { init(null, true); } public void resolve() { toolResolver.resolve(reresolve, extraToolboxes); } public ToolResolver getToolResolver() { return toolResolver; } public HTTPServices getHttpServices() { return httpServices; } public TrianaProperties getProperties() { return props; } // public DiscoverTools getDiscoveryTools() { // return discoveryTools; // } public ToolTable getToolTable() { return toolTable; } public void addExtensionClass(Class cls) { this.extensionClasses.add(cls); } public void addExtensionClasses(Class... clss) { for (Class cls : clss) { this.extensionClasses.add(cls); } } public void addExtraToolbox(String toolbox) { extraToolboxes.add(toolbox); } public void addExtraToolboxes(String... toolboxes) { for (String toolbox : toolboxes) { extraToolboxes.add(toolbox); } } public void addModulePath(String path) { if (!modulePaths.contains(path)) { modulePaths.add(path); } } private void initModules(List<String> modulePaths) { ClassLoaders.addClassLoader(ModuleClassLoader.getInstance()); String moduleRoot = props.getProperty(TrianaProperties.MODULE_SEARCH_PATH_PROPERTY); if (moduleRoot != null) { File f = new File(moduleRoot); if (f.exists() && f.isDirectory()) { File[] files = f.listFiles(new FileFilter() { @Override public boolean accept(File file) { return file.isDirectory() && !file.getName().startsWith(".") && !file.getName().equals("CVS"); } }); for (File file : files) { loadModule(file.getAbsolutePath()); } } } for (String modulePath : modulePaths) { loadModule(modulePath); } } public void loadModule(String path) { File file = new File(path); if (file.exists() && file.isDirectory()) { try { ModuleClassLoader.getInstance().addModule(file.toURI().toURL()); } catch (Exception e) { log.error(e); } } } public boolean isRunServer() { return runServer; } public void setRunServer(boolean runServer) { this.runServer = runServer; } public boolean isReresolve() { return reresolve; } public void setReresolve(boolean reresolve) { this.reresolve = reresolve; } private void initExtensions(List<Class> exten) { List ext = new ArrayList<Class>(); ext.add(Interceptor.class); ext.add(ToolMetadataResolver.class); ext.add(DataBusInterface.class); ext.add(ToolboxLoader.class); if (exten != null) { for (Class aClass : exten) { if (!ext.contains(aClass)) { ext.add(aClass); } } } extensions = ExtensionFinder.services(ext); Set<Class> keys = extensions.keySet(); // System.out.println(Arrays.toString(keys.toArray())); for (Class key : keys) { if (key.equals(Interceptor.class)) { Set<Object> exts = extensions.get(key); for (Object o : exts) { Interceptor e = (Interceptor) o; InterceptorChain.register(e); } } else if (key.equals(ToolMetadataResolver.class)) { Set<Object> exts = extensions.get(key); for (Object o : exts) { ToolMetadataResolver e = (ToolMetadataResolver) o; ResolverRegistry.registerResolver(e); } } else if (key.equals(DataBusInterface.class)) { Set<Object> exts = extensions.get(key); for (Object o : exts) { DataBusInterface e = (DataBusInterface) o; DataBus.registerDataBus(e); } } else if (key.equals(ToolboxLoader.class)) { Set<Object> exts = extensions.get(key); for (Object o : exts) { ToolboxLoader e = (ToolboxLoader) o; ToolboxLoaderRegistry.registerLoader(e); } } } } private static void initObjectDeserializers() { ObjectDeserializationManager.registerObjectDeserializer(Base64ObjectDeserializer.BASE64_OBJECT_DESERIALIZER, new Base64ObjectDeserializer()); } public Map<Class, Set<Object>> getExtensions() { return Collections.unmodifiableMap(extensions); } public Set<Object> getExtensions(Class cls) { Set<Object> exts = extensions.get(cls); if (exts != null) { return Collections.unmodifiableSet(exts); } return new HashSet<Object>(); } public void execute(Runnable runnable) { executorService.execute(runnable); } public ErrorTracker getErrorTracker() { return errorTracker; } public void shutdown(int exitCode) { toolResolver.shutdown(); httpServices.stopServices(); executorService.shutdown(); if (exitCode > -1) { System.exit(exitCode); } } private class ShutdownHook extends Thread { private void add() { try { Method shutdownHook = java.lang.Runtime.class .getMethod("addShutdownHook", new Class[]{java.lang.Thread.class}); shutdownHook.invoke(Runtime.getRuntime(), new Object[]{this}); } catch (Exception e) { e.printStackTrace(); } } public void createHook() { add(); } public void run() { Loggers.LOGGER.info("TrianaInstance$ShutdownHook.run ENTER"); try { toolResolver.shutdown(); // if (discoveryTools != null) { // discoveryTools.shutdown(); // } executorService.shutdown(); } catch (Exception e) { e.printStackTrace(); } try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } Loggers.LOGGER.info("TrianaInstance$ShutdownHook.run EXIT"); } } }