/*******************************************************************************
* Copyright (c) 2007, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Cloudsmith - https://bugs.eclipse.org/bugs/show_bug.cgi?id=226401
* EclipseSource - ongoing development
*******************************************************************************/
package org.eclipse.buckminster.jnlp.p2.director.app;
import static org.eclipse.buckminster.jnlp.p2.bootstrap.BootstrapConstants.*;
import java.awt.Image;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import org.eclipse.buckminster.jnlp.p2.bootstrap.BootstrapConstants;
import org.eclipse.buckminster.jnlp.p2.bootstrap.ErrorDialog;
import org.eclipse.buckminster.jnlp.p2.bootstrap.JNLPException;
import org.eclipse.buckminster.jnlp.p2.bootstrap.SplashWindow;
import org.eclipse.buckminster.jnlp.p2.bootstrap.TailLineBuffer;
import org.eclipse.buckminster.jnlp.p2.bootstrap.Utils;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.equinox.internal.p2.console.ProvisioningHelper;
import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepositoryManager;
import org.eclipse.equinox.internal.provisional.p2.core.*;
import org.eclipse.equinox.internal.provisional.p2.core.Version;
import org.eclipse.equinox.internal.provisional.p2.director.*;
import org.eclipse.equinox.internal.provisional.p2.engine.*;
import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.internal.provisional.p2.metadata.query.InstallableUnitQuery;
import org.eclipse.equinox.internal.provisional.p2.metadata.query.LatestIUVersionQuery;
import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepositoryManager;
import org.eclipse.equinox.internal.provisional.p2.query.*;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.service.packageadmin.PackageAdmin;
@SuppressWarnings("restriction")
public class Application implements IApplication
{
private static final Integer EXIT_ERROR = new Integer(13);
static private final String ANT_PROPERTY_PREFIX = "${"; //$NON-NLS-1$
static private final String FLAVOR_DEFAULT = "tooling"; //$NON-NLS-1$
static private final String EXEMPLARY_SETUP = "org.eclipse.equinox.p2.exemplarysetup"; //$NON-NLS-1$
static private final String FRAMEWORKADMIN_EQUINOX = "org.eclipse.equinox.frameworkadmin.equinox"; //$NON-NLS-1$
static private final String SIMPLE_CONFIGURATOR_MANIPULATOR = "org.eclipse.equinox.simpleconfigurator.manipulator"; //$NON-NLS-1$
public static final int COMMAND_INSTALL = 0;
public static final int COMMAND_UNINSTALL = 1;
public static final int COMMAND_LIST = 2;
public static final String[] COMMAND_NAMES = { "-installIU", "-uninstallIU", "-list" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private Path m_destination;
private URI[] m_artifactRepositoryLocations;
private URI[] m_metadataRepositoryLocations;
private URI[] m_metadataReposForRemoval;
private URI[] m_artifactReposForRemoval;
private IArtifactRepositoryManager m_artifactManager;
private IMetadataRepositoryManager m_metadataManager;
private String m_root;
private Version m_version = null;
private String m_flavor;
private String m_profileId;
private String m_profileProperties; // a comma-separated list of property pairs "tag=value"
private String m_bundlePool = null;
private String m_nl;
private String m_os;
private String m_arch;
private String m_ws;
private boolean m_roamingProfile = false;
private IPlanner m_planner;
private IEngine m_engine;
private boolean m_noProfileId = false;
private Properties m_configProps;
private String m_configURL = null;
private String m_extraArgs = null;
private int m_command = -1;
private ServiceReference m_packageAdminRef;
private PackageAdmin m_packageAdmin;
private Image m_splashImageBoot;
private Image m_splashImage;
private Image m_windowIconImage;
private boolean m_productStarted;
private void ambigousCommand(int cmd1, int cmd2) throws CoreException
{
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Ambigous_Command,
new Object[] { COMMAND_NAMES[cmd1], COMMAND_NAMES[cmd2] })));
}
private ProfileChangeRequest buildProvisioningRequest(IProfile profile, Collector roots, boolean install, IProgressMonitor monitor)
{
ProfileChangeRequest request = new ProfileChangeRequest(profile);
markRoots(request, roots);
if(install)
{
InstallableUnitQuery query = new InstallableUnitQuery(m_root, VersionRange.emptyRange);
Collector installedRoots = profile.query(query, new Collector(), monitor);
request.removeInstallableUnits((IInstallableUnit[])installedRoots.toArray(IInstallableUnit.class));
request.addInstallableUnits((IInstallableUnit[])roots.toArray(IInstallableUnit.class));
}
else
{
request.removeInstallableUnits((IInstallableUnit[])roots.toArray(IInstallableUnit.class));
}
return request;
}
synchronized Bundle getBundle(String symbolicName)
{
if(m_packageAdmin == null)
return null;
Bundle[] bundles = m_packageAdmin.getBundles(symbolicName, null);
if(bundles == null)
return null;
// Return the first bundle that is not installed or uninstalled
for(int i = 0; i < bundles.length; i++)
{
if((bundles[i].getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0)
{
return bundles[i];
}
}
return null;
}
private String getEnvironmentProperty()
{
Properties values = new Properties();
if(m_os != null)
values.put("osgi.os", m_os); //$NON-NLS-1$
if(m_nl != null)
values.put("osgi.nl", m_nl); //$NON-NLS-1$
if(m_ws != null)
values.put("osgi.ws", m_ws); //$NON-NLS-1$
if(m_arch != null)
values.put("osgi.arch", m_arch); //$NON-NLS-1$
if(values.isEmpty())
return null;
return toString(values);
}
private IProfile initializeProfile() throws CoreException
{
if(m_profileId == null)
{
m_profileId = IProfileRegistry.SELF;
m_noProfileId = true;
}
IProfile profile = ProvisioningHelper.getProfile(m_profileId);
if(profile == null)
{
if(m_destination == null)
missingArgument("destination"); //$NON-NLS-1$
if(m_flavor == null)
m_flavor = System.getProperty("eclipse.p2.configurationFlavor", FLAVOR_DEFAULT); //$NON-NLS-1$
Properties props = new Properties();
props.setProperty(IProfile.PROP_INSTALL_FOLDER, m_destination.toOSString());
props.setProperty(IProfile.PROP_FLAVOR, m_flavor);
if(m_bundlePool != null)
if(m_bundlePool.equals(Messages.destination_commandline))
props.setProperty(IProfile.PROP_CACHE, m_destination.toOSString());
else
props.setProperty(IProfile.PROP_CACHE, m_bundlePool);
if(m_roamingProfile)
props.setProperty(IProfile.PROP_ROAMING, Boolean.TRUE.toString());
String env = getEnvironmentProperty();
if(env != null)
props.setProperty(IProfile.PROP_ENVIRONMENTS, env);
if(m_profileProperties != null)
{
putProperties(m_profileProperties, props);
}
profile = ProvisioningHelper.addProfile(m_profileId, props);
String currentFlavor = profile.getProperty(IProfile.PROP_FLAVOR);
if(currentFlavor != null && !currentFlavor.endsWith(m_flavor))
throw new RuntimeException(NLS.bind(
"Install flavor {0} not consistent with profile flavor {1}", m_flavor, currentFlavor)); //$NON-NLS-1$
}
return profile;
}
private void initializeRepositories(boolean throwException) throws CoreException
{
if(m_artifactRepositoryLocations == null)
{
if(throwException)
missingArgument("artifactRepository"); //$NON-NLS-1$
}
else
{
m_artifactManager = (IArtifactRepositoryManager)ServiceHelper.getService(Activator.getContext(),
IArtifactRepositoryManager.class.getName());
if(m_artifactManager == null)
{
if(throwException)
throw new ProvisionException(Messages.Application_NoManager);
}
else
{
int removalIdx = 0;
boolean anyValid = false; // do we have any valid repos or did they all fail to load?
m_artifactReposForRemoval = new URI[m_artifactRepositoryLocations.length];
for(int i = 0; i < m_artifactRepositoryLocations.length; i++)
{
try
{
if(!m_artifactManager.contains(m_artifactRepositoryLocations[i]))
{
m_artifactManager.loadRepository(m_artifactRepositoryLocations[i], null);
m_artifactReposForRemoval[removalIdx++] = m_artifactRepositoryLocations[i];
}
anyValid = true;
}
catch(ProvisionException e)
{
// one of the repositories did not load
LogHelper.log(new Status(IStatus.ERROR, Activator.ID, m_artifactRepositoryLocations[i].toString()
+ " failed to load", e)); //$NON-NLS-1$
}
}
if(throwException && !anyValid)
// all repositories failed to load
throw new ProvisionException(Messages.Application_NoRepositories);
}
}
if(m_metadataRepositoryLocations == null)
{
if(throwException)
missingArgument("metadataRepository"); //$NON-NLS-1$
}
else
{
m_metadataManager = (IMetadataRepositoryManager)ServiceHelper.getService(Activator.getContext(),
IMetadataRepositoryManager.class.getName());
if(m_metadataManager == null)
{
if(throwException)
throw new ProvisionException(Messages.Application_NoManager);
}
else
{
int removalIdx = 0;
boolean anyValid = false; // do we have any valid repos or did they all fail to load?
m_metadataReposForRemoval = new URI[m_metadataRepositoryLocations.length];
for(int i = 0; i < m_metadataRepositoryLocations.length; i++)
{
try
{
if(!m_metadataManager.contains(m_metadataRepositoryLocations[i]))
{
m_metadataManager.loadRepository(m_metadataRepositoryLocations[i], null);
m_metadataReposForRemoval[removalIdx++] = m_metadataRepositoryLocations[i];
}
anyValid = true;
}
catch(ProvisionException e)
{
// one of the repositories did not load
LogHelper.log(new Status(IStatus.ERROR, Activator.ID, m_metadataRepositoryLocations[i].toString()
+ " failed to load", e)); //$NON-NLS-1$
}
}
if(throwException && !anyValid)
// all repositories failed to load
throw new ProvisionException(Messages.Application_NoRepositories);
}
}
}
private void initializeServices()
{
IDirector director = (IDirector)ServiceHelper.getService(Activator.getContext(), IDirector.class.getName());
if(director == null)
throw new RuntimeException(Messages.Missing_director);
m_planner = (IPlanner)ServiceHelper.getService(Activator.getContext(), IPlanner.class.getName());
if(m_planner == null)
throw new RuntimeException(Messages.Missing_planner);
m_engine = (IEngine)ServiceHelper.getService(Activator.getContext(), IEngine.SERVICE_NAME);
if(m_engine == null)
throw new RuntimeException(Messages.Missing_Engine);
}
private void markRoots(ProfileChangeRequest request, Collector roots)
{
for(Iterator iterator = roots.iterator(); iterator.hasNext();)
{
request.setInstallableUnitProfileProperty((IInstallableUnit)iterator.next(),
IInstallableUnit.PROP_PROFILE_ROOT_IU, Boolean.TRUE.toString());
}
}
private void missingArgument(String argumentName) throws CoreException
{
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_Required_Argument,
argumentName)));
}
private IStatus planAndExecute(IProfile profile, ProvisioningContext context, ProfileChangeRequest request,
IProgressMonitor monitor)
{
ProvisioningPlan result;
IStatus operationStatus;
result = m_planner.getProvisioningPlan(request, context, monitor);
if(!result.getStatus().isOK())
operationStatus = result.getStatus();
else
{
operationStatus = PlanExecutionHelper.executePlan(result, m_engine, context, monitor);
}
return operationStatus;
}
private void printRequest(ProfileChangeRequest request)
{
IInstallableUnit[] toAdd = request.getAddedInstallableUnits();
IInstallableUnit[] toRemove = request.getRemovedInstallableUnits();
for(int i = 0; i < toAdd.length; i++)
{
System.out.println(NLS.bind(Messages.Installing, toAdd[i].getId(), toAdd[i].getVersion()));
}
for(int i = 0; i < toRemove.length; i++)
{
System.out.println(NLS.bind(Messages.Uninstalling, toRemove[i].getId(), toRemove[i].getVersion()));
}
}
public void processArguments(String[] args) throws Exception
{
if(args == null)
return;
for(int i = 0; i < args.length; i++)
{
String opt = args[i];
if(opt.equals("-roaming")){ //$NON-NLS-1$
m_roamingProfile = true;
}
if(opt.equals(COMMAND_NAMES[COMMAND_LIST]))
{
if(m_command != -1)
ambigousCommand(COMMAND_LIST, m_command);
m_command = COMMAND_LIST;
}
// check for args without parameters (i.e., a flag arg)
// check for args with parameters. If we are at the last
// argument or
// if the next one
// has a '-' as the first character, then we can't have an arg
// with
// a parm so continue.
if(i == args.length - 1 || args[i + 1].startsWith("-")) //$NON-NLS-1$
continue;
String arg = args[++i];
if(opt.equalsIgnoreCase("-profile")) //$NON-NLS-1$
m_profileId = arg;
if(opt.equalsIgnoreCase("-profileProperties") || opt.equalsIgnoreCase("-props")) //$NON-NLS-1$ //$NON-NLS-2$
m_profileProperties = arg;
// we create a path object here to handle ../ entries in the middle of paths
if(opt.equalsIgnoreCase("-destination") || opt.equalsIgnoreCase("-dest")){ //$NON-NLS-1$ //$NON-NLS-2$
if(arg.startsWith("file:")) //$NON-NLS-1$
arg = arg.substring(5);
m_destination = new Path(arg);
}
// we create a path object here to handle ../ entries in the middle of paths
if(opt.equalsIgnoreCase("-bundlepool") || opt.equalsIgnoreCase("-bp")){ //$NON-NLS-1$ //$NON-NLS-2$
if(arg.startsWith("file:")) //$NON-NLS-1$
arg = arg.substring(5);
m_bundlePool = new Path(arg).toOSString();
}
if(opt.equalsIgnoreCase("-metadataRepository") || opt.equalsIgnoreCase("-metadataRepositories") || opt.equalsIgnoreCase("-mr")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
m_metadataRepositoryLocations = getURIs(arg);
if(opt.equalsIgnoreCase("-artifactRepository") || opt.equalsIgnoreCase("-artifactRepositories") || opt.equalsIgnoreCase("-ar")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
m_artifactRepositoryLocations = getURIs(arg);
if(opt.equalsIgnoreCase("-flavor")) //$NON-NLS-1$
m_flavor = arg;
if(opt.equalsIgnoreCase(COMMAND_NAMES[COMMAND_INSTALL]))
{
if(m_command != -1)
ambigousCommand(COMMAND_INSTALL, m_command);
m_root = arg;
m_command = COMMAND_INSTALL;
}
if(opt.equalsIgnoreCase("-version")){ //$NON-NLS-1$
if(arg != null && !arg.startsWith(ANT_PROPERTY_PREFIX))
m_version = new Version(arg);
}
if(opt.equalsIgnoreCase(COMMAND_NAMES[COMMAND_UNINSTALL]))
{
if(m_command != -1)
ambigousCommand(COMMAND_UNINSTALL, m_command);
m_root = arg;
m_command = COMMAND_UNINSTALL;
}
if(opt.equalsIgnoreCase("-p2.os")){ //$NON-NLS-1$
m_os = arg;
}
if(opt.equalsIgnoreCase("-p2.ws")){ //$NON-NLS-1$
m_ws = arg;
}
if(opt.equalsIgnoreCase("-p2.nl")){ //$NON-NLS-1$
m_nl = arg;
}
if(opt.equalsIgnoreCase("-p2.arch")){ //$NON-NLS-1$
m_arch = arg;
}
if(opt.equalsIgnoreCase("-configURL")){ //$NON-NLS-1$
m_configURL = arg;
}
if(opt.equalsIgnoreCase("-extra")){ //$NON-NLS-1$
m_extraArgs = arg;
}
}
}
/**
* @param pairs
* a comma separated list of tag=value pairs
* @param properties
* the collection into which the pairs are put
*/
private void putProperties(String pairs, Properties properties)
{
StringTokenizer tok = new StringTokenizer(pairs, ",", true); //$NON-NLS-1$
while(tok.hasMoreTokens())
{
String next = tok.nextToken().trim();
int i = next.indexOf('=');
if(i > 0 && i < next.length() - 1)
{
String tag = next.substring(0, i).trim();
String value = next.substring(i + 1, next.length()).trim();
if(tag.length() > 0 && value.length() > 0)
{
properties.put(tag, value);
}
}
}
}
public void run(String[] args, IProgressMonitor monitor) throws Exception
{
long time = -System.currentTimeMillis();
initializeServices();
processArguments(args);
IStatus operationStatus = Status.OK_STATUS;
InstallableUnitQuery query;
Collector roots;
try
{
initializeRepositories(m_command == COMMAND_INSTALL);
switch(m_command)
{
case COMMAND_INSTALL:
case COMMAND_UNINSTALL:
IProfile profile = initializeProfile();
query = new InstallableUnitQuery(m_root, m_version == null
? VersionRange.emptyRange
: new VersionRange(m_version, true, m_version, true));
roots = collectRootIUs(m_metadataRepositoryLocations, new CompositeQuery(new Query[] { query,
new LatestIUVersionQuery() }), new Collector(), monitor);
if(roots.size() <= 0)
roots = profile.query(query, roots, monitor);
if(roots.size() <= 0)
{
System.out.println(NLS.bind(Messages.Missing_IU, m_root));
IStatus status = new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_IU, m_root));
logFailure(status);
throw BuckminsterException.wrap(status);
}
// keep this result status in case there is a problem so we can report it to the user
boolean wasRoaming = Boolean.valueOf(profile.getProperty(IProfile.PROP_ROAMING)).booleanValue();
try
{
IStatus updateRoamStatus = updateRoamingProperties(profile, monitor);
if(!updateRoamStatus.isOK())
{
MultiStatus multi = new MultiStatus(Activator.ID, IStatus.ERROR, NLS.bind(
Messages.Cant_change_roaming, profile.getProfileId()), null);
multi.add(updateRoamStatus);
System.out.println(multi.getMessage());
System.out.println(updateRoamStatus.getMessage());
logFailure(multi);
throw BuckminsterException.wrap(multi);
}
ProvisioningContext context = new ProvisioningContext(m_metadataRepositoryLocations);
context.setArtifactRepositories(m_artifactRepositoryLocations);
ProfileChangeRequest request = buildProvisioningRequest(profile, roots, m_command == COMMAND_INSTALL, monitor);
printRequest(request);
operationStatus = planAndExecute(profile, context, request, monitor);
}
finally
{
// if we were originally were set to be roaming and we changed it, change it back before we return
if(wasRoaming && !Boolean.valueOf(profile.getProperty(IProfile.PROP_ROAMING)).booleanValue())
setRoaming(profile, monitor);
}
break;
case COMMAND_LIST:
query = new InstallableUnitQuery(null, VersionRange.emptyRange);
if(m_metadataRepositoryLocations == null)
missingArgument("metadataRepository"); //$NON-NLS-1$
roots = collectRootIUs(m_metadataRepositoryLocations, query, null, monitor);
Iterator unitIterator = roots.iterator();
while(unitIterator.hasNext())
{
IInstallableUnit iu = (IInstallableUnit)unitIterator.next();
System.out.println(iu.getId());
}
break;
}
}
finally
{
cleanupRepositories();
}
time += System.currentTimeMillis();
if(operationStatus.isOK())
System.out.println(NLS.bind(Messages.Operation_complete, new Long(time)));
else if(operationStatus.matches(IStatus.CANCEL))
throw new OperationCanceledException();
else
{
System.out.println(Messages.Operation_failed);
logFailure(operationStatus);
throw BuckminsterException.wrap(operationStatus);
}
}
private void loadConfigProperties(String configURL) throws JNLPException
{
if(m_configProps != null)
return;
m_configProps = new Properties();
if(configURL != null)
{
URL propertiesURL = null;
InputStream propStream = null;
try
{
propertiesURL = new URL(configURL.trim());
propStream = new BufferedInputStream(propertiesURL.openStream());
m_configProps.load(propStream);
}
catch(MalformedURLException e)
{
throw new JNLPException(Messages.cannot_read_URL_to_configuration_properties,
Messages.report_the_problem, ERROR_CODE_MALFORMED_PROPERTY_EXCEPTION, e);
}
catch(IOException e)
{
throw new JNLPException(Messages.cannot_read_configuration_properties,
Messages.check_your_system_permissions_internet_connection_and_try_again,
ERROR_CODE_PROPERTY_IO_EXCEPTION, e);
}
finally
{
Utils.close(propStream);
}
}
}
private void startSplash(boolean forceSplashVisible) throws JNLPException
{
if(!SplashWindow.isSplashUp())
{
SplashWindow.splash(getSplashImageBoot(), getSplashImage(), getWindowIconImage(), forceSplashVisible ? 0 : BootstrapConstants.SPLASH_WINDOW_DELAY);
if(!forceSplashVisible)
{
Thread splashSynchronizationThread = new Thread(new ThreadGroup("splash.threads"), "bootstrap.synchronization")
{
@Override
public void run()
{
InputStream is = System.in;
int sleepTime = 50;
int cyclesToGo = BootstrapConstants.SPLASH_WINDOW_DELAY / sleepTime;
StringBuilder sb = new StringBuilder();
ByteArrayOutputStream cache = new ByteArrayOutputStream();
try
{
while(cyclesToGo > 0)
{
if(is.available() > 0)
{
cache.reset();
while(is.available() > 0)
cache.write(is.read());
sb.append(cache.toString());
if(sb.toString().contains(SLASH_IS_SHOWN_STRING))
{
forceShowSplash();
break;
}
}
Thread.sleep(sleepTime);
cyclesToGo--;
}
}
catch(InterruptedException e)
{
// do nothing
}
catch(IOException e)
{
// do nothing
}
}
};
splashSynchronizationThread.setDaemon(true);
splashSynchronizationThread.start();
}
}
}
private void forceShowSplash()
{
SplashWindow.forceShowSplash();
}
private Image getSplashImageBoot()
{
if(m_splashImageBoot == null && m_configProps != null)
{
try
{
m_splashImageBoot = Utils.createImage(m_configProps
.getProperty(BootstrapConstants.PROP_SPLASH_IMAGE_BOOT));
}
catch(JNLPException e)
{
// stays null
}
}
return m_splashImageBoot;
}
private Image getSplashImage()
{
if(m_splashImage == null && m_configProps != null)
{
try
{
m_splashImage = Utils.createImage(m_configProps
.getProperty(BootstrapConstants.PROP_SPLASH_IMAGE));
}
catch(JNLPException e)
{
// stays null
}
}
return m_splashImage;
}
private Image getWindowIconImage()
{
if(m_windowIconImage == null && m_configProps != null)
{
try
{
m_windowIconImage = Utils.createImage(m_configProps
.getProperty(BootstrapConstants.PROP_WINDOW_ICON));
}
catch(JNLPException e)
{
// stays null
}
}
return m_windowIconImage;
}
private void stopSplash()
{
SplashWindow.disposeSplash();
}
private void cleanupRepositories()
{
if(m_artifactReposForRemoval != null && m_artifactManager != null)
{
for(int i = 0; i < m_artifactReposForRemoval.length && m_artifactReposForRemoval[i] != null; i++)
{
m_artifactManager.removeRepository(m_artifactReposForRemoval[i]);
}
}
if(m_metadataReposForRemoval != null && m_metadataManager != null)
{
for(int i = 0; i < m_metadataReposForRemoval.length && m_metadataReposForRemoval[i] != null; i++)
{
m_metadataManager.removeRepository(m_metadataReposForRemoval[i]);
}
}
}
class LocationQueryable implements IQueryable
{
private URI location;
public LocationQueryable(URI location)
{
this.location = location;
}
public Collector query(Query query, Collector collector, IProgressMonitor monitor)
{
return ProvisioningHelper.getInstallableUnits(location, query, collector, monitor);
}
}
private Collector collectRootIUs(URI[] locations, Query query, Collector collector, IProgressMonitor monitor)
{
if(locations == null || locations.length == 0)
return ProvisioningHelper.getInstallableUnits(null, query, collector, monitor);
Collector result = collector != null
? collector
: new Collector();
IQueryable[] locationQueryables = new IQueryable[locations.length];
for(int i = 0; i < locations.length; i++)
{
locationQueryables[i] = new LocationQueryable(locations[i]);
}
return new CompoundQueryable(locationQueryables).query(query, result, monitor);
}
private synchronized void setPackageAdmin(PackageAdmin service)
{
m_packageAdmin = service;
}
private boolean startEarly(String bundleName) throws BundleException
{
Bundle bundle = getBundle(bundleName);
if(bundle == null)
return false;
bundle.start(Bundle.START_TRANSIENT);
return true;
}
public Object start(IApplicationContext context) throws Exception
{
IProgressMonitor monitor = null;
Exception exception = null;
boolean productInstalled = false;
try
{
String[] args = (String[])context.getArguments().get("application.args");
String configURL = readArgs(args, "-configURL");
loadConfigProperties(configURL);
monitor = new JNLPProgressMonitor();
boolean forceSplashVisible = "true".equals(readArgs(args, "-forceSplash"));
startSplash(forceSplashVisible);
// tell jnlp.p2.bootstrap that the director app is started
System.out.println(BootstrapConstants.APP_LAUNCHED_SYNC_STRING);
m_packageAdminRef = Activator.getContext().getServiceReference(PackageAdmin.class.getName());
setPackageAdmin((PackageAdmin)Activator.getContext().getService(m_packageAdminRef));
if(!startEarly(EXEMPLARY_SETUP))
{
IStatus status = new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_bundle, EXEMPLARY_SETUP));
logFailure(status);
throw BuckminsterException.wrap(status);
}
if(!startEarly(SIMPLE_CONFIGURATOR_MANIPULATOR))
{
IStatus status = new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_bundle,
SIMPLE_CONFIGURATOR_MANIPULATOR));
logFailure(status);
throw BuckminsterException.wrap(status);
}
if(!startEarly(FRAMEWORKADMIN_EQUINOX))
{
IStatus status = new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_bundle,
FRAMEWORKADMIN_EQUINOX));
logFailure(status);
throw BuckminsterException.wrap(status);
}
run(args, monitor);
productInstalled = true;
startProduct(monitor);
}
catch(OperationCanceledException e)
{
// do nothing
}
catch(Exception e)
{
exception = e;
}
finally
{
stopSplash();
if(exception != null)
{
String title;
if(productInstalled)
title = "Materialization wizard cannot be launched";
else
title = "Materialization wizard cannot be installed";
String errorCode;
String problem;
String solution;
Throwable throwableToReport;
if(exception instanceof JNLPException)
{
JNLPException jnlpException = (JNLPException)exception;
errorCode = jnlpException.getErrorCode();
problem = jnlpException.getProblem();
solution = jnlpException.getSolution();
throwableToReport = jnlpException.isReportable() ? exception : null;
}
else
{
errorCode = BootstrapConstants.ERROR_CODE_MATERIALIZER_INSTALL_EXCEPTION;
problem = "An unexpected error occurred.\n\nThis could be because of intermittent network problems.";
solution = "Try again, and if the problem persists, please report the problem.";
throwableToReport = exception;
}
new ErrorDialog(
getWindowIconImage(),
title,
problem,
solution,
(String)m_configProps.get(PROP_SUPPORT_EMAIL),
"Cannot launch materializer",
throwableToReport)
.open();
if(exception != null)
{
try
{
Utils.reportToServer((String)m_configProps.get(BootstrapConstants.PROP_BASE_PATH_URL), errorCode, exception);
}
catch(IOException e)
{
// no report
}
}
return EXIT_ERROR;
}
}
return IApplication.EXIT_OK;
}
private String readArgs(String[] args, String key)
{
if(key == null)
return null;
for(int i = 0; i < args.length; i++)
if(key.equals(args[i]))
return args[++i];
return null;
}
private void startProduct(IProgressMonitor monitor) throws JNLPException
{
ArrayList<String> allArgs = new ArrayList<String>();
allArgs.add(m_destination.toString() + "/eclipse"); //$NON-NLS-1$
//allArgs.add("-consoleLog"); //$NON-NLS-1$
allArgs.add("-data"); //$NON-NLS-1$
allArgs.add(m_destination.removeLastSegments(1).toString());
allArgs.add("-configURL"); //$NON-NLS-1$
allArgs.add(m_configURL);
allArgs.add("-syncString"); //$NON-NLS-1$
allArgs.add(APP_LAUNCHED_SYNC_STRING);
int startupTime = Integer.getInteger(PROP_STARTUP_TIME, DEFAULT_STARTUP_TIME).intValue();
long popupAfter = (new Date()).getTime() + startupTime;
allArgs.add("-popupAfter"); //$NON-NLS-1$
allArgs.add("" + popupAfter); //$NON-NLS-1$
allArgs.add("-vmargs");
allArgs.add("-Xmx512m"); //$NON-NLS-1$
allArgs.addAll(Utils.getProxySettings());
allArgs.addAll(Utils.parseExtraArgs(m_extraArgs));
Runtime runtime = Runtime.getRuntime();
Process process = null;
final TailLineBuffer tailOut = new TailLineBuffer(Integer.getInteger(PROP_MAX_CAPTURED_LINES, DEFAULT_MAX_CAPTURED_LINES)
.intValue());
final TailLineBuffer tailErr = new TailLineBuffer(Integer.getInteger(PROP_MAX_CAPTURED_LINES, DEFAULT_MAX_CAPTURED_LINES)
.intValue());
try
{
process = runtime.exec(allArgs.toArray(new String[allArgs.size()]));
InputStream is = process.getInputStream();
InputStream eis = process.getErrorStream();
final BufferedReader rd = new BufferedReader(new InputStreamReader(is));
final BufferedReader erd = new BufferedReader(new InputStreamReader(eis));
Thread outReaderThread = new Thread()
{
@Override
public void run()
{
String line;
try
{
while((line = rd.readLine()) != null)
{
if(APP_LAUNCHED_SYNC_STRING.equals(line))
m_productStarted = true;
tailOut.writeLine(line);
}
}
catch(IOException e)
{
System.err
.println("Error reading from JNLP application standard output:" + e.getMessage());
}
finally
{
Utils.close(rd);
}
}
};
outReaderThread.setDaemon(true);
outReaderThread.start();
Thread errReaderThread = new Thread()
{
@Override
public void run()
{
String line;
try
{
while((line = erd.readLine()) != null)
tailErr.writeLine(line);
}
catch(IOException e)
{
System.err
.println("Error reading from JNLP application standard error:" + e.getMessage());
}
finally
{
Utils.close(erd);
}
}
};
errReaderThread.setDaemon(true);
errReaderThread.start();
}
catch(IOException e)
{
throw new JNLPException("Cannot launch materialization wizard", "Check your system permissions and try again",
ERROR_CODE_MATERIALIZER_EXECUTION_EXCEPTION, e);
}
try
{
if(!SplashWindow.isSplashUp())
SplashWindow.splash(null, getSplashImage(), getWindowIconImage());
else
forceShowSplash();
SplashWindow.setSplashImage(SplashWindow.SPLASH_IMAGE_ID);
try
{
// Two seconds to start, with progressbar. The time is an
// estimate of course.
startupTime /= 100;
monitor.beginTask("starting materializer", startupTime);
while(--startupTime >= 0 && !m_productStarted)
{
if(monitor.isCanceled())
throw new OperationCanceledException();
Thread.sleep(100);
monitor.worked(1);
}
monitor.done();
int processExitValue = 0;
boolean processTerminated = false;
// Add some grace startup time with progress bar frozen at 100%
// Check often if the process is still alive; if not, break the loop
if(process != null)
{
int startupTimeOut = Integer.getInteger(BootstrapConstants.PROP_STARTUP_TIMEOUT, BootstrapConstants.DEFAULT_STARTUP_TIMEOUT).intValue() / 100;
while(--startupTimeOut >= 0 && !m_productStarted)
try
{
if(monitor.isCanceled())
throw new OperationCanceledException();
processExitValue = process.exitValue();
processTerminated = true;
break;
}
catch(IllegalThreadStateException e)
{
// The process is still alive, let's wait
Thread.sleep(100);
}
}
if(!m_productStarted)
{
if(processTerminated)
{
String capturedErrors = tailErr.getLinesAsString();
String capturedOutput = tailOut.getLinesAsString();
throw new JNLPException("Cannot launch materialization wizard" + "\nExit code: " + processExitValue
+ (capturedErrors != null
? "\n" + "captured errors:" + "\n" + capturedErrors
: "") + (capturedOutput != null //$NON-NLS-1$
? "\n" + "captured output:" + "\n" + capturedOutput
: ""), "Read error description above",
BootstrapConstants.ERROR_CODE_LAUNCHER_NOT_STARTED_EXCEPTION);
}
process.destroy();
throw new JNLPException("Cannot launch materialization wizard within timeout",
"Check your machine (might be too slow or too busy)",
BootstrapConstants.ERROR_CODE_LAUNCHER_NOT_STARTED_EXCEPTION);
}
}
catch(InterruptedException e)
{
}
}
catch(OperationCanceledException e)
{
if(process != null)
{
process.destroy();
}
throw e;
}
finally
{
}
}
private String getErrorURL()
{
String errorURL = null;
if(m_configProps != null)
errorURL = (String)m_configProps.get(BootstrapConstants.PROP_ERROR_URL);
if(errorURL == null)
errorURL = BootstrapConstants.ERROR_HELP_URL;
return errorURL;
}
public void stop()
{
setPackageAdmin(null);
Activator.getContext().ungetService(m_packageAdminRef);
}
private String toString(Properties context)
{
StringBuffer result = new StringBuffer();
for(Enumeration iter = context.keys(); iter.hasMoreElements();)
{
String key = (String)iter.nextElement();
result.append(key);
result.append('=');
result.append(context.get(key));
if(iter.hasMoreElements())
result.append(',');
}
return result.toString();
}
private IStatus updateRoamingProperties(IProfile profile, IProgressMonitor monitor)
{
// if the user didn't specify a destination path on the command-line
// then we assume they are installing into the currently running
// instance and we don't have anything to update
if(m_destination == null)
return Status.OK_STATUS;
// if the user didn't set a profile id on the command-line this is ok if they
// also didn't set the destination path. (handled in the case above) otherwise throw an error.
if(m_noProfileId) // && destination != null
return new Status(IStatus.ERROR, Activator.ID, Messages.Missing_profileid);
// make sure that we are set to be roaming before we update the values
if(!Boolean.valueOf(profile.getProperty(IProfile.PROP_ROAMING)).booleanValue())
return Status.OK_STATUS;
ProfileChangeRequest request = new ProfileChangeRequest(profile);
File destinationFile = m_destination.toFile();
if(!destinationFile.equals(new File(profile.getProperty(IProfile.PROP_INSTALL_FOLDER))))
request.setProfileProperty(IProfile.PROP_INSTALL_FOLDER, m_destination.toOSString());
if(!destinationFile.equals(new File(profile.getProperty(IProfile.PROP_CACHE))))
request.setProfileProperty(IProfile.PROP_CACHE, m_destination.toOSString());
if(request.getProfileProperties().size() == 0)
return Status.OK_STATUS;
// otherwise we have to make a change so set the profile to be non-roaming so the
// values don't get recalculated to the wrong thing if we are flushed from memory - we
// will set it back later (see bug 269468)
request.setProfileProperty(IProfile.PROP_ROAMING, "false"); //$NON-NLS-1$
ProvisioningContext context = new ProvisioningContext(new URI[0]);
context.setArtifactRepositories(new URI[0]);
ProvisioningPlan result = m_planner.getProvisioningPlan(request, context, monitor);
return PlanExecutionHelper.executePlan(result, m_engine, context, monitor);
}
/*
* Set the roaming property on the given profile.
*/
private IStatus setRoaming(IProfile profile, IProgressMonitor monitor)
{
ProfileChangeRequest request = new ProfileChangeRequest(profile);
request.setProfileProperty(IProfile.PROP_ROAMING, "true"); //$NON-NLS-1$
ProvisioningContext context = new ProvisioningContext(new URI[0]);
context.setArtifactRepositories(new URI[0]);
ProvisioningPlan result = m_planner.getProvisioningPlan(request, context, monitor);
return PlanExecutionHelper.executePlan(result, m_engine, context, monitor);
}
private static URI[] getURIs(String spec)
{
if(spec == null)
return null;
String[] urlSpecs = getArrayFromString(spec, ","); //$NON-NLS-1$
ArrayList result = new ArrayList(urlSpecs.length);
for(int i = 0; i < urlSpecs.length; i++)
{
try
{
result.add(URIUtil.fromString(urlSpecs[i]));
}
catch(URISyntaxException e)
{
LogHelper.log(new Status(IStatus.WARNING, Activator.ID, NLS.bind(Messages.Ignored_repo, urlSpecs[i])));
}
}
if(result.size() == 0)
return null;
return (URI[])result.toArray(new URI[result.size()]);
}
/**
* Convert a list of tokens into an array. The list separator has to be specified.
*/
public static String[] getArrayFromString(String list, String separator)
{
if(list == null || list.trim().equals("")) //$NON-NLS-1$
return new String[0];
List result = new ArrayList();
for(StringTokenizer tokens = new StringTokenizer(list, separator); tokens.hasMoreTokens();)
{
String token = tokens.nextToken().trim();
if(!token.equals("")) //$NON-NLS-1$
result.add(token);
}
return (String[])result.toArray(new String[result.size()]);
}
private void logFailure(IStatus status)
{
FrameworkLog log = (FrameworkLog)ServiceHelper.getService(Activator.getContext(), FrameworkLog.class.getName());
if(log != null)
System.err.println("Application failed, log file location: " + log.getFile()); //$NON-NLS-1$
LogHelper.log(status);
}
}