org.jactr.eclipse.runtime.launching.ACTRLaunchConfigurationUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.jactr.eclipse.runtime.launching.ACTRLaunchConfigurationUtils.java

Source

/*
 * Created on Mar 22, 2007 Copyright (C) 2001-5, 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.eclipse.runtime.launching;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.antlr.runtime.tree.CommonTree;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.eclipse.pde.core.plugin.TargetPlatform;
import org.eclipse.pde.internal.launching.IPDEConstants;
import org.jactr.eclipse.core.CorePlugin;
import org.jactr.eclipse.core.bundles.BundleUtilities;
import org.jactr.eclipse.core.bundles.descriptors.InstrumentDescriptor;
import org.jactr.eclipse.core.bundles.descriptors.IterativeListenerDescriptor;
import org.jactr.eclipse.core.bundles.descriptors.ModuleDescriptor;
import org.jactr.eclipse.core.bundles.descriptors.RuntimeTracerDescriptor;
import org.jactr.eclipse.core.bundles.descriptors.SensorDescriptor;
import org.jactr.eclipse.core.bundles.registry.InstrumentRegistry;
import org.jactr.eclipse.core.bundles.registry.IterativeListenerRegistry;
import org.jactr.eclipse.core.bundles.registry.ModuleRegistry;
import org.jactr.eclipse.core.bundles.registry.RuntimeTracerRegistry;
import org.jactr.eclipse.core.bundles.registry.SensorRegistry;
import org.jactr.eclipse.core.comp.CompilationUnitManager;
import org.jactr.eclipse.core.comp.ICompilationUnit;
import org.jactr.eclipse.runtime.RuntimePlugin;
import org.jactr.eclipse.runtime.preferences.RuntimePreferences;
import org.jactr.io.antlr3.builder.JACTRBuilder;
import org.jactr.io.antlr3.misc.ASTSupport;

/**
 * builds a valid ILaunchConfiguration for the ACTR launch environment, which
 * currently relies upon the PDE launch set up.
 * 
 * @author developer
 */
public class ACTRLaunchConfigurationUtils {

    static private final Log LOGGER = LogFactory.getLog(ACTRLaunchConfigurationUtils.class);

    /**
     * return the project defined in the configuration
     * 
     * @param configuration
     * @return project
     * @throws CoreException
     *           if project doesnt exist
     */
    static public IProject getProject(ILaunchConfiguration configuration) throws CoreException {
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        String projectName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, "");

        try {
            IProject sourceProject = root.getProject(projectName);
            if (sourceProject.exists() && sourceProject.isOpen())
                return sourceProject;
            else
                throw new RuntimeException("Could not get valid project from launchConfig:" + configuration);
        } catch (Exception e) {
            throw new RuntimeException("Could not get valid project from launchConfig:" + configuration, e);
        }
    }

    /**
     * return all the model files defined in the launch configuration
     * 
     * @param configuration
     * @return
     * @throws CoreException
     *           if none are defined
     */
    static public Collection<IResource> getModelFiles(ILaunchConfiguration configuration) throws CoreException {
        IProject project = getProject(configuration);
        ArrayList<IResource> resources = new ArrayList<IResource>();

        if (project == null)
            return resources;

        for (String modelFile : configuration.getAttribute(ACTRLaunchConstants.ATTR_MODEL_FILES, "").split(","))
            if (modelFile.length() > 0) {
                IResource resource = project.findMember(modelFile, false);
                if (resource != null)
                    resources.add(resource);
            }
        return resources;
    }

    /**
     * checks all the model files in the configuration for modules. if any of the
     * modules requires common reality then a sensor must have been defined. this
     * does not validate that the sensors actually meet the requirements of the
     * modules
     * 
     * @param configuration
     * @return true if it does. throws exception otherwise
     * @throws CoreException
     */
    static public boolean meetsCommonRealityRequirements(ILaunchConfiguration configuration) throws CoreException {
        boolean hasSensors = getRequiredSensors(configuration).size() != 0
                || configuration.getAttribute(ACTRLaunchConstants.ATTR_USE_EMBED_CONTROLLER, false);

        for (IResource modelFile : getModelFiles(configuration))
            for (ModuleDescriptor module : getModulesInModel(modelFile))
                if (module.requiresCommonReality() && !hasSensors)
                    throw new RuntimeException(modelFile.getName() + " requires CommonReality because of "
                            + module.getName() + ", but no sensors are configured.");
        return true;
    }

    /**
     * returns all the modules required in a specific model
     * 
     * @param modelFile
     * @return
     */
    static public Collection<ModuleDescriptor> getModulesInModel(IResource modelFile) {
        ArrayList<ModuleDescriptor> modules = new ArrayList<ModuleDescriptor>();
        Collection<ModuleDescriptor> allModules = ModuleRegistry.getRegistry()
                .getDescriptors(modelFile.getProject(), true);
        ICompilationUnit compilationUnit = CompilationUnitManager.acquire(modelFile);
        try {
            CommonTree modelTree = compilationUnit.getModelDescriptor();

            if (modelTree == null)
                throw new IllegalArgumentException(modelFile.getName() + " has errors");

            Map<String, CommonTree> extMap = ASTSupport.getMapOfTrees(modelTree, JACTRBuilder.MODULE);

            for (CommonTree extTree : extMap.values()) {
                String className = ((CommonTree) extTree.getFirstChildWithType(JACTRBuilder.CLASS_SPEC)).getText();

                for (ModuleDescriptor module : allModules)
                    if (module.getClassName().equals(className)) {
                        modules.add(module);
                        break;
                    }

                /*
                 * we might be tempted to throw an exception if there is an unresolved
                 * class, but we hold that for the runtime itself
                 */
            }

            return modules;
        } finally {
            if (compilationUnit != null)
                CompilationUnitManager.release(compilationUnit);
        }
    }

    /**
     * return all the aliases for a specific model in the configuration
     * 
     * @param modelFile
     * @param configuration
     * @return
     * @throws CoreException
     */
    static public Collection<String> getModelAliases(IResource modelFile, ILaunchConfiguration configuration)
            throws CoreException {
        String path = modelFile.getFullPath().toOSString();
        Set<String> aliases = new HashSet<String>();
        for (String alias : configuration.getAttribute(ACTRLaunchConstants.ATTR_MODEL_ALIASES + path, "")
                .split(",")) {
            alias = alias.trim();
            if (alias.length() > 0)
                aliases.add(alias);
        }
        return aliases;
    }

    /**
     * sets up the basic parameters needed for the eclipse launch. these are the
     * attributes that are set once and never need modifying
     * 
     * @param workingCopy
     */
    static public void setupPermanentAttributes(ILaunchConfigurationWorkingCopy workingCopy) throws CoreException {

        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.AUTOMATIC_VALIDATE,
                RuntimePlugin.getDefault().getPluginPreferences().getBoolean(RuntimePreferences.VERIFY_RUN_PREF));

        /*
         * First, we tell the PDE launcher that we will be running an application
         * and what that application is
         */
        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.USE_PRODUCT, false);

        if (workingCopy.getAttribute(ACTRLaunchConstants.ATTR_ITERATIONS, 0) == 0)
            workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.APPLICATION,
                    ACTRLaunchConstants.DEFAULT_APPLICATION);
        else
            workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.APPLICATION,
                    ACTRLaunchConstants.ITERATIVE_APPLICATION);

        /*
         * then we tell it where the workspace should be..
         * ${system_property:user.home}/.jactr/workspaces/${project_name} this will
         * be resolved by the launcher
         */
        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.LOCATION,
                ACTRLaunchConstants.NORMAL_WORKSPACE_LOCATION);

        /*
         * if true, we'd load ALL the bundles that are present in the current
         * environment we only want to load the required ones that we selected above
         */
        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.USE_DEFAULT, false);

        /*
         * exclude optional bundles
         */
        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.INCLUDE_OPTIONAL, false);

        /*
         * don't add everything in the workspace
         */
        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.AUTOMATIC_ADD, false);

        /*
         * 
         */
        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.DESELECTED_WORKSPACE_PLUGINS,
                (String) null);

        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Applied permanent attributes " + workingCopy);
    }

    /**
     * set up the attributes that we just apply after Apply is clicked in the
     * config dialog
     * 
     * @param workingCopy
     */
    static public void setupPersistentAttributes(ILaunchConfigurationWorkingCopy workingCopy) throws CoreException {
        /*
         * we will use the default configuration location, which should be the
         * current environment's.. the name is RUNTYPE:runName..
         */
        IProject project = getProject(workingCopy);
        String configName = workingCopy.getName();

        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.CONFIG_USE_DEFAULT_AREA, false);
        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.CONFIG_LOCATION,
                ACTRLaunchConstants.NORMAL_CONFIGURATION_LOCATION + project.getName() + "/" + configName);

        /*
         * what about core logging? that needs to be set up by the tab but for now..
         */
        boolean logging = workingCopy.getAttribute(ACTRLaunchConstants.ATTR_DEBUG_CORE_ENABLED, false);

        if (logging) {
            IResource logFile = project.findMember(workingCopy.getAttribute(
                    ACTRLaunchConstants.ATTR_DEBUG_CORE_LOG_CONF, ACTRLaunchConstants.DEFAULT_CORE_LOG_CONF));
            if (logFile != null && logFile.exists()) {
                StringBuilder vmArg = new StringBuilder(" -Dorg.apache.commons.logging.log=");
                vmArg.append(workingCopy.getAttribute(ACTRLaunchConstants.ATTR_DEBUG_CORE_LOGGER,
                        ACTRLaunchConstants.DEFAULT_CORE_LOGGER));
                vmArg.append(" -Dlog4j.configuration=");
                try {
                    URI uri = logFile.getRawLocationURI();
                    vmArg.append(uri.toURL()).append(" ").append(
                            workingCopy.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, ""));

                    workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, vmArg.toString());
                } catch (Exception e) {
                    CorePlugin.debug("failed to transform url " + logFile, e);
                    logging = false;
                }
            } else
                logging = false;
        }

        if (!logging)
            workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS,
                    "-Dorg.apache.commons.logging.log=org.apache.commons.logging.impl.SimpleLog "
                            + workingCopy.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, ""));

        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Applied persistent attributes " + workingCopy);
    }

    /**
     * set up the information that is set strictly for the immediate launch. this
     * includes the working directory, environment file, program args
     * 
     * @param workingCopy
     * @param mode
     * @param environmentFile
     */
    static public void setupTemporaryAttributes(ILaunchConfigurationWorkingCopy workingCopy, String mode,
            IResource environmentFile) throws CoreException {
        StringBuilder arguments = new StringBuilder();

        /*
         * make sure no splash screen is shown
         */
        arguments.append("-name jACTR -nosplash ");

        /**
         * here's a mac specific bit of code
         * https://bugs.eclipse.org/bugs/show_bug.cgi?id=133072. The deal is that
         * eclipse (SWT) needs -ws carbon to run correctly. However if this is
         * provided, Swing/AWT calls will result in deadlock. The PDE tools
         * automatically add the -ws option, unless
         * IPDEUIConstants.APPEND_ARGS_EXPLICITLY is true (i.e. the program added it
         * already). So, if this is the mac, we explicitly add the program args,
         * excluding -ws. <br>
         * <br>
         * This works fine since we are launching within eclipse. If we were to
         * build a standalone app, on the mac, we'd need to add
         * --launcher.secondThread to the command line so to achieve a similar
         * effect.
         */
        if (TargetPlatform.getWS().equals("carbon") || TargetPlatform.getWS().equals("cocoa")) {
            workingCopy.setAttribute(IPDEConstants.APPEND_ARGS_EXPLICITLY, true);
            // arguments.append("--launcher.secondThread ");
            arguments.append("-os ").append(TargetPlatform.getOS()).append(" ");
            arguments.append("-arch ").append(TargetPlatform.getOSArch()).append(" ");
        }

        if (workingCopy.getType().getIdentifier().equals("org.jactr.eclipse.runtime.launching.cr"))
            arguments.append(ACTRLaunchConstants.DEFAULT_CR_RUN_ARG);
        else if (workingCopy.getAttribute(ACTRLaunchConstants.ATTR_ITERATIONS, 0) != 0)
            arguments.append(ACTRLaunchConstants.ITERATIVE_APPLICATION_ARG);
        else if (ILaunchManager.DEBUG_MODE.equals(mode))
            arguments.append(ACTRLaunchConstants.DEFAULT_APPLICATION_DEBUG_ARG);
        else
            arguments.append(ACTRLaunchConstants.DEFAULT_APPLICATION_RUN_ARG);

        arguments.append(" ");

        try {
            URI uri = environmentFile.getRawLocationURI();
            arguments.append(uri.toURL()).append(" ")
                    .append(workingCopy.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, ""));

            workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
                    arguments.toString());
        } catch (Exception e) {
            throw new CoreException(new Status(IStatus.ERROR, RuntimePlugin.PLUGIN_ID,
                    "Could not get a valid url from " + environmentFile, e));
        }

        /*
         * working directory - where the JVM is run from
         */
        workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
                environmentFile.getParent().getLocation().toOSString());

        /*
         * now for the fun.. we need to get the plugin dependencies. first we get
         * the dependencies for the application.. we do this temporarily because..
         * well, things change.
         */

        Set<String> workspace = new TreeSet<String>();
        Set<String> target = new TreeSet<String>();
        computeBundleDependencies(workingCopy, workspace, target);

        StringBuilder workspaceBundles = new StringBuilder();
        StringBuilder targetBundles = new StringBuilder();
        for (String bundle : workspace)
            workspaceBundles.append(bundle).append(",");
        for (String bundle : target)
            targetBundles.append(bundle).append(",");

        if (workspaceBundles.length() > 0)
            workspaceBundles.delete(workspaceBundles.length() - 1, workspaceBundles.length());

        if (targetBundles.length() > 0)
            targetBundles.delete(targetBundles.length() - 1, targetBundles.length());

        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.SELECTED_WORKSPACE_PLUGINS,
                workspaceBundles.toString());
        workingCopy.setAttribute(org.eclipse.pde.launching.IPDELauncherConstants.SELECTED_TARGET_PLUGINS,
                targetBundles.toString());

        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Applied temporary attributes " + workingCopy);
    }

    /**
     * snag all the sensors that are defined in this configuration
     * 
     * @param configuration
     * @return
     * @throws CoreException
     */
    static public Collection<SensorDescriptor> getRequiredSensors(ILaunchConfiguration configuration)
            throws CoreException {
        IProject project = getProject(configuration);
        ArrayList<SensorDescriptor> descriptors = new ArrayList<SensorDescriptor>();
        Collection<SensorDescriptor> installed = SensorRegistry.getRegistry().getDescriptors(project, true);

        String sensors = configuration.getAttribute(ACTRLaunchConstants.ATTR_COMMON_REALITY_SENSORS, "");
        for (String sensor : sensors.split(","))
            for (SensorDescriptor desc : installed)
                if (desc.getClassName().equals(sensor))
                    descriptors.add(desc);
        return descriptors;
    }

    static public Collection<IterativeListenerDescriptor> getRequiredListeners(ILaunchConfiguration configuration)
            throws CoreException {
        IProject project = getProject(configuration);

        ArrayList<IterativeListenerDescriptor> descriptors = new ArrayList<IterativeListenerDescriptor>();
        Collection<IterativeListenerDescriptor> installed = IterativeListenerRegistry.getRegistry()
                .getDescriptors(project, true);

        String sensors = configuration.getAttribute(ACTRLaunchConstants.ATTR_ITERATIVE_LISTENERS, "");

        for (String listener : sensors.split(","))
            for (IterativeListenerDescriptor desc : installed)
                if (desc.getClassName().equals(listener))
                    descriptors.add(desc);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Launch configuration for " + project.getName() + " : " + configuration.getAttributes());
            LOGGER.debug("Required sensors : " + sensors);
            LOGGER.debug("Returning : " + descriptors);
        }

        return descriptors;
    }

    /**
     * return all the instruments that are required in this configuration
     * 
     * @param configuration
     * @return
     * @throws CoreException
     */
    static public Collection<InstrumentDescriptor> getRequiredInstruments(ILaunchConfiguration configuration)
            throws CoreException {
        IProject project = getProject(configuration);
        ArrayList<InstrumentDescriptor> descriptors = new ArrayList<InstrumentDescriptor>();

        Collection<InstrumentDescriptor> installed = InstrumentRegistry.getRegistry().getDescriptors(project, true);

        String instruments = configuration.getAttribute(ACTRLaunchConstants.ATTR_INSTRUMENTS, "");
        for (String instrument : instruments.split(","))
            for (InstrumentDescriptor desc : installed)
                if (desc.getClassName().equals(instrument))
                    descriptors.add(desc);
        return descriptors;
    }

    static public Collection<RuntimeTracerDescriptor> getRequiredTracers(ILaunchConfiguration configuration)
            throws CoreException {
        IProject project = getProject(configuration);
        ArrayList<RuntimeTracerDescriptor> descriptors = new ArrayList<RuntimeTracerDescriptor>();

        Collection<RuntimeTracerDescriptor> installed = RuntimeTracerRegistry.getRegistry().getDescriptors(project,
                true);

        String instruments = configuration.getAttribute(ACTRLaunchConstants.ATTR_TRACERS, "");

        for (String instrument : instruments.split(","))
            for (RuntimeTracerDescriptor desc : installed)
                if (desc.getClassName().equals(instrument))
                    descriptors.add(desc);

        return descriptors;
    }

    @SuppressWarnings("unchecked")
    static public void computeBundleDependencies(ILaunchConfigurationWorkingCopy configuration,
            Set<String> workspaceBundles, Set<String> targetBundles) throws CoreException {
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        String projectName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, "");
        IProject sourceProject = null;

        if (projectName.length() != 0)
            sourceProject = root.getProject(projectName);

        // IProject project = root.getProject(configuration.getAttribute(
        // LaunchConfigurationConstants.ACTR_PROJECT, ""));

        Collection<String> appDependencies = null;

        if (configuration.getAttribute(ACTRLaunchConstants.ATTR_ITERATIONS, 0) == 0)
            appDependencies = BundleUtilities.getDependencies(ACTRLaunchConstants.DEFAULT_APPLICATION_BUNDLE);
        else
            appDependencies = BundleUtilities.getDependencies(ACTRLaunchConstants.ITERATIVE_APPLICATION_BUNDLE);

        Collection<String> currentDependencies = Collections.EMPTY_SET;

        if (sourceProject != null && sourceProject.exists())
            currentDependencies = BundleUtilities.getDependencies(sourceProject);

        Collection<String> uniqueDependencies = new TreeSet<String>();
        for (String bundleId : appDependencies)
            uniqueDependencies.add(bundleId);

        for (String bundleId : currentDependencies)
            uniqueDependencies.add(bundleId);

        /*
         * now for the sensors
         */
        for (SensorDescriptor sensor : getRequiredSensors(configuration))
            for (String bundleId : BundleUtilities.getDependencies(sensor.getContributor()))
                uniqueDependencies.add(bundleId);

        /*
         * and instruments
         */
        for (InstrumentDescriptor instrument : getRequiredInstruments(configuration))
            for (String bundleId : BundleUtilities.getDependencies(instrument.getContributor()))
                uniqueDependencies.add(bundleId);

        /*
         * now we determine where they are coming from, we preference workspace
         * plugins over installed ones so that you can self-host
         */
        for (IPluginModelBase modelBase : PluginRegistry.getWorkspaceModels()) {
            String pluginId = modelBase.getPluginBase(true).getId();

            // not entirely clear how to get the project from the model..
            // this matters because if the project is closed, we shouldn't use it
            // IProject requiredProject = root.getProject();
            // if (requiredProject.isAccessible())
            if (pluginId != null && uniqueDependencies.remove(pluginId))
                workspaceBundles.add(pluginId);
        }

        /*
         * and the rest we assume are targets
         */
        targetBundles.addAll(uniqueDependencies);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("workspace : " + workspaceBundles.toString());
            LOGGER.debug("target : " + targetBundles.toString());
        }
    }
}