All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.bnd.build.ProjectLauncher Maven / Gradle / Ivy

There is a newer version: 2.0.0.20130123-133441
Show newest version
package aQute.bnd.build;

import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.jar.*;

import aQute.bnd.service.RepositoryPlugin.Strategy;
import aQute.lib.osgi.*;
import aQute.libg.command.*;
import aQute.libg.generics.*;

/**
 * A Project Launcher is a base class to be extended by launchers. Launchers are
 * JARs that launch a framework and install a number of bundles and then run the
 * framework. A launcher jar must specify a Launcher-Class manifest header. This
 * class is instantiated and cast to a LauncherPlugin. This plug in is then
 * asked to provide a ProjectLauncher. This project launcher is then used by the
 * project to run the code. Launchers must extend this class.
 * 
 */
public abstract class ProjectLauncher {
	private final Project						project;
	private long								timeout				= 0;
	private final Collection			classpath			= new ArrayList();
	private List						runbundles			= Create.list();
	private final List					runvm				= new ArrayList();
	private Map					runproperties;
	private Command								java;
	private Map>	runsystempackages;
	private final List					activators			= Create.list();
	private File								storageDir;
	private final List					warnings			= Create.list();
	private final List					errors				= Create.list();

	private boolean								trace;
	private boolean								keep;
	private int									framework;

	public final static int						SERVICES			= 10111;
	public final static int						NONE				= 20123;

	// MUST BE ALIGNED WITH LAUNCHER
	public final static int						OK					= 0;
	public final static int						WARNING				= -1;
	public final static int						ERROR				= -2;
	public final static int						TIMEDOUT			= -3;
	public final static int						UPDATE_NEEDED		= -4;
	public final static int						CANCELED			= -5;
	public final static int						DUPLICATE_BUNDLE	= -6;
	public final static int						RESOLVE_ERROR		= -7;
	public final static int						ACTIVATOR_ERROR		= -8;
	public final static int						CUSTOM_LAUNCHER		= -128;

	public final static String					EMBEDDED_ACTIVATOR	= "Embedded-Activator";

	public ProjectLauncher(Project project) throws Exception {
		this.project = project;

		updateFromProject();
	}

	/**
	 * Collect all the aspect from the project and set the local fields from
	 * them. Should be called
	 * 
	 * @throws Exception
	 */
	protected void updateFromProject() throws Exception {
		// pkr: could not use this because this is killing the runtests.
		// project.refresh();
		runbundles.clear();
		Collection run = project.getRunbundles();
		
		for (Container container : run) {
			File file = container.getFile();
			if (file != null && (file.isFile() || file.isDirectory())) {
				runbundles.add(file.getAbsolutePath());
			} else {
				warning("Bundle file \"%s\" does not exist", file.getAbsolutePath());
			}
		}

		if (project.getRunBuilds()) {
			File[] builds = project.build();
			if (builds != null)
				for (File file : builds)
					runbundles.add(file.getAbsolutePath());
		}

		Collection runpath = project.getRunpath();
		runsystempackages = project.parseHeader(project.getProperty(Constants.RUNSYSTEMPACKAGES));
		framework = getRunframework(project.getProperty(Constants.RUNFRAMEWORK));
		trace = Processor.isTrue(project.getProperty(Constants.RUNTRACE));

		timeout = Processor.getDuration(project.getProperty(Constants.RUNTIMEOUT), 0);
		trace = Processor.isTrue(project.getProperty(Constants.RUNTRACE));

		// For backward compatibility with bndtools launcher
		List fws = project.getBundles(Strategy.HIGHEST, project.getProperty("-runfw"), "-runfw");
		runpath.addAll(fws);

		for (Container c : runpath) {
			addClasspath(c);
		}

		runvm.addAll(project.getRunVM());
		runproperties = project.getRunProperties();

		storageDir = project.getRunStorage();
		if (storageDir == null) {
			storageDir = new File(project.getTarget(), "fw");
		}
	}

	private int getRunframework(String property) {
		if (Constants.RUNFRAMEWORK_NONE.equalsIgnoreCase(property))
			return NONE;
		else if (Constants.RUNFRAMEWORK_SERVICES.equalsIgnoreCase(property))
			return SERVICES;

		return SERVICES;
	}

	public void addClasspath(Container container) throws Exception {
		if (container.getError() != null) {
			project.error("Cannot launch because %s has reported %s", container.getProject(),
					container.getError());
		} else {
			Collection members = container.getMembers();
			for (Container m : members) {
				String path = m.getFile().getAbsolutePath();
				if (!classpath.contains(path)) {
					classpath.add(path);

					Manifest manifest = m.getManifest();
					if (manifest != null) {
						Map> exports = project.parseHeader(manifest
								.getMainAttributes().getValue(Constants.EXPORT_PACKAGE));
						for (Map.Entry> e : exports.entrySet()) {
							if (!runsystempackages.containsKey(e.getKey()))
								runsystempackages.put(e.getKey(), e.getValue());
						}

						// Allow activators on the runpath. They are called
						// after
						// the framework is completely initialized wit the
						// system
						// context.
						String activator = manifest.getMainAttributes()
								.getValue(EMBEDDED_ACTIVATOR);
						if (activator != null)
							activators.add(activator);
					}
				}
			}
		}
	}

	public void addRunBundle(String f) {
		runbundles.add(f);
	}

	public Collection getRunBundles() {
		return runbundles;
	}

	public void addRunVM(String arg) {
		runvm.add(arg);
	}

	public Collection getRunpath() {
		return classpath;
	}

	public Collection getClasspath() {
		return classpath;
	}

	public Collection getRunVM() {
		return runvm;
	}

	public Collection getArguments() {
		return Collections.emptySet();
	}

	public Map getRunProperties() {
		return runproperties;
	}
	
	public File getStorageDir() {
		return storageDir;
	}

	public abstract String getMainTypeName();

	public abstract void update() throws Exception;

	public int launch() throws Exception {
		prepare();
		java = new Command();
		java.add(project.getProperty("java", "java"));
		java.add("-cp");
		java.add(Processor.join(getClasspath(), File.pathSeparator));
		java.addAll(getRunVM());
		java.add(getMainTypeName());
		java.addAll(getArguments());
		if (timeout != 0)
			java.setTimeout(timeout + 1000, TimeUnit.MILLISECONDS);

		int result = java.execute(System.in, System.out, System.err);
		if (result == Integer.MIN_VALUE)
			return TIMEDOUT;

		reportResult(result);
		return result;
	}

	protected void reportResult(int result) {
		switch (result) {
		case OK:
			project.trace("Command terminated normal %s", java);
			break;
		case TIMEDOUT:
			project.error("Launch timedout: %s", java);
			break;

		case ERROR:
			project.error("Launch errored: %s", java);
			break;

		case WARNING:
			project.warning("Launch had a warning %s", java);
			break;
		default:
			project.warning("Unknown code %d from launcher: %s", result, java);
			break;
		}
	}

	public void setTimeout(long timeout, TimeUnit unit) {
		this.timeout = unit.convert(timeout, TimeUnit.MILLISECONDS);
	}

	public long getTimeout() {
		return this.timeout;
	}

	public void cancel() {
		java.cancel();
	}

	public Map> getSystemPackages() {
		return runsystempackages;
	}

	public void setKeep(boolean keep) {
		this.keep = keep;
	}

	public boolean isKeep() {
		return keep;
	}

	public void setTrace(boolean level) {
		this.trace = level;
	}

	public boolean getTrace() {
		return this.trace;
	}

	/**
	 * Should be called when all the changes to the launchers are set. Will
	 * calculate whatever is necessary for the launcher.
	 * 
	 * @throws Exception
	 */
	public abstract void prepare() throws Exception;

	public Project getProject() {
		return project;
	}

	public boolean addActivator(String e) {
		return activators.add(e);
	}

	public Collection getActivators() {
		return Collections.unmodifiableCollection(activators);
	}

	/**
	 * Either NONE or SERVICES to indicate how the remote end launches. NONE
	 * means it should not use the classpath to run a framework. This likely
	 * requires some dummy framework support. SERVICES means it should load the
	 * framework from the claspath.
	 * 
	 * @return
	 */
	public int getRunFramework() {
		return framework;
	}

	public void setRunFramework(int n) {
		assert n == NONE || n == SERVICES;
		this.framework = n;
	}

	/**
	 * Add the specification for a set of bundles the runpath if it does not
	 * already is included. This can be used by subclasses to ensure the proper
	 * jars are on the classpath.
	 * 
	 * @param defaultSpec
	 *            The default spec for default jars
	 */
	public void addDefault(String defaultSpec) throws Exception {
		Collection deflts = project.getBundles(Strategy.HIGHEST, defaultSpec, null);
		for (Container c : deflts)
			addClasspath(c);
	}

	/**
	 * Create a self executable.
	 */

	public Jar executable() throws Exception {
		throw new UnsupportedOperationException();
	}
	
	public void clear() {
		errors.clear();
		warnings.clear();
	}
	
	public List getErrors() {
		return Collections.unmodifiableList(errors);
	}
	
	public List getWarnings() {
		return Collections.unmodifiableList(warnings);
	}
	
	protected void error(String message, Object... args) {
		String formatted = String.format(message, args);
		errors.add(formatted);
	}

	protected void warning(String message, Object... args) {
		String formatted = String.format(message, args);
		warnings.add(formatted);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy