/**
* Copyright (C) 2005 - 2012 Eric Van Dewoestine
*
* Portions of this class that are copied from the eclipse source are the
* copyright (c) of IBM Corporation and others, and released under the Eclipse
* Public License v1.0: http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclim.installer.eclipse;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IBundleGroup;
import org.eclipse.core.runtime.IBundleGroupProvider;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;
import org.eclipse.equinox.internal.p2.director.app.Messages;
//import org.eclipse.equinox.internal.p2.ui.ProvUI;
import org.eclipse.equinox.internal.provisional.p2.director.PlanExecutionHelper;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.engine.IEngine;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProvisioningPlan;
import org.eclipse.equinox.p2.engine.ProvisioningContext;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.equinox.p2.planner.IPlanner;
/*import org.eclipse.equinox.p2.repository.IRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.equinox.p2.ui.ProvisioningUI;*/
import org.eclipse.osgi.util.NLS;
import org.eclipse.update.internal.configurator.FeatureEntry;
import org.osgi.framework.ServiceReference;
/**
* Entry point for installer application.
*
* @author Eric Van Dewoestine
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class Application
extends org.eclipse.equinox.internal.p2.director.app.DirectorApplication
{
private static final Integer EXIT_ERROR = new Integer(13);
private Object invokePrivate(String methodName, Class[] params, Object[] args)
throws Exception
{
Method method =
org.eclipse.equinox.internal.p2.director.app.DirectorApplication.class
.getDeclaredMethod(methodName, params);
method.setAccessible(true);
return method.invoke(this, args);
}
private Object getPrivateField(String fieldName)
throws Exception
{
Field field =
org.eclipse.equinox.internal.p2.director.app.DirectorApplication.class
.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(this);
}
// EV: straight copy from super w/ private field/method workarounds and
// instead of returning EXIT_ERROR on error, throw an exception instead.
public Object run(String[] args)
{
// get eclipse information:
// - profile name
// - configuration location (user local dir for root installed eclipse)
// - least of installed features
if ("-info".equals(args[0])){
System.out.println(" Profile: " +
System.getProperty("eclipse.p2.profile"));
System.out.println(" Configuration: " +
System.getProperty("osgi.configuration.area"));
IBundleGroupProvider[] providers = Platform.getBundleGroupProviders();
for(IBundleGroupProvider provider : providers){
IBundleGroup[] groups = provider.getBundleGroups();
for(IBundleGroup group : groups){
FeatureEntry feature = (FeatureEntry)group;
System.out.println(" Feature: " +
feature.getIdentifier() + ' ' +
feature.getVersion() + ' ' +
feature.getSite().getResolvedURL());
}
}
return IApplication.EXIT_OK;
}
// remove temp p2 repositories
// FIXME: after removing the repositories the changes don't seem to be
// committed. Either some event listener is registered or the application
// exists before the changes can be committed. Need to find out how to wait
// or force a synchronous saving of the changes. Also, the
// getKnownRepositories seems to not return the uri of the current update
// site, perhaps making this those block moot.
/*if ("-removeRepos".equals(args[0])){
// see
// org.eclipse.equinox.p2.ui.RepositoryManipulationPage
// org.eclipse.equinox.internal.p2.ui.model.ElementUtils
ProvisioningUI ui = ProvisioningUI.getDefaultUI();
ui.signalRepositoryOperationStart();
IMetadataRepositoryManager metaManager =
ProvUI.getMetadataRepositoryManager(ui.getSession());
IArtifactRepositoryManager artManager =
ProvUI.getArtifactRepositoryManager(ui.getSession());
URI[] repos = metaManager.getKnownRepositories(
IRepositoryManager.REPOSITORIES_ALL);
for (URI repo : repos){
if (repo.toString().indexOf("formic_") != -1){
System.out.println("Remove repository: " + repo);
metaManager.removeRepository(repo);
artManager.removeRepository(repo);
}
}
ui.signalRepositoryOperationComplete(null, true);
return IApplication.EXIT_OK;
}*/
long time = System.currentTimeMillis();
try {
processArguments(args);
// EV: pull some private vars in to local scope. must be after
// processArguments
boolean printHelpInfo = ((Boolean)this.getPrivateField("printHelpInfo")).booleanValue();
boolean printIUList = ((Boolean)this.getPrivateField("printIUList")).booleanValue();
boolean printRootIUList = ((Boolean)this.getPrivateField("printRootIUList")).booleanValue();
boolean printTags = ((Boolean)this.getPrivateField("printTags")).booleanValue();
boolean purgeRegistry = ((Boolean)this.getPrivateField("purgeRegistry")).booleanValue();
if (printHelpInfo){
// EV: invoke private method
//performHelpInfo();
invokePrivate("performHelpInfo", new Class[0], new Object[0]);
} else {
// EV: invoke private methods
//initializeServices();
//initializeRepositories();
invokePrivate("initializeServices", new Class[0], new Object[0]);
invokePrivate("initializeRepositories", new Class[0], new Object[0]);
// EV: pull more private vars in.
String NOTHING_TO_REVERT_TO = (String)this.getPrivateField("NOTHING_TO_REVERT_TO");
String revertToPreviousState = (String)this.getPrivateField("revertToPreviousState");
List<IVersionedId> rootsToInstall = (List<IVersionedId>)this.getPrivateField("rootsToInstall");
List<IVersionedId> rootsToUninstall = (List<IVersionedId>)this.getPrivateField("rootsToUninstall");
if (revertToPreviousState != NOTHING_TO_REVERT_TO) {
// EV: invoke private methods
//revertToPreviousState();
invokePrivate("revertToPreviousState", new Class[0], new Object[0]);
} else if (!(rootsToInstall.isEmpty() && rootsToUninstall.isEmpty()))
performProvisioningActions();
if (printIUList)
// EV: invoke private method
//performList();
invokePrivate("performList", new Class[0], new Object[0]);
if (printRootIUList)
// EV: invoke private method
//performListInstalledRoots();
invokePrivate("performListInstalledRoots", new Class[0], new Object[0]);
if (printTags)
// EV: invoke private method
//performPrintTags();
invokePrivate("performPrintTags", new Class[0], new Object[0]);
if (purgeRegistry)
// EV: invoke private method
//purgeRegistry();
invokePrivate("purgeRegistry", new Class[0], new Object[0]);
System.out.println(NLS.bind(
Messages.Operation_complete,
new Long(System.currentTimeMillis() - time)));
}
return IApplication.EXIT_OK;
} catch (CoreException e) {
try{
// EV: invoke private methods
//deeplyPrint(e.getStatus(), System.err, 0);
//logFailure(e.getStatus());
invokePrivate("deeplyPrint",
new Class[]{IStatus.class, PrintStream.class, Integer.TYPE},
new Object[]{e.getStatus(), System.err, 0});
invokePrivate("logFailure",
new Class[]{IStatus.class},
new Object[]{e.getStatus()});
//set empty exit data to suppress error dialog from launcher
// EV: invoke private methods
//setSystemProperty("eclipse.exitdata", ""); //$NON-NLS-1$ //$NON-NLS-2$
invokePrivate("setSystemProperty",
new Class[]{String.class, String.class},
new Object[]{"eclipse.exitdata", ""});
// EV: throw exception for the installer
//return EXIT_ERROR;
String workspace =
ResourcesPlugin.getWorkspace().getRoot().getRawLocation().toOSString();
String log = workspace + "/.metadata/.log";
throw new RuntimeException(
"Operation failed. See '" + log + "' for additional info.", e);
}catch(Exception ex){
ex.printStackTrace();
return EXIT_ERROR;
}
// EV: handle reflection exceptions
} catch(Exception e){
e.printStackTrace();
return EXIT_ERROR;
} finally {
try{
// EV: pull private var in.
ServiceReference packageAdminRef = (ServiceReference)
this.getPrivateField("packageAdminRef");
if (packageAdminRef != null) {
// EV: invoke private methods.
//cleanupRepositories();
//cleanupServices();
invokePrivate("cleanupRepositories", new Class[0], new Object[0]);
invokePrivate("cleanupServices", new Class[0], new Object[0]);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
// EV: straight copy from super w/ private field/method workarounds.
private void performProvisioningActions()
// EV: throw a regular Exception to account for reflection exceptions
//throws CoreException
throws Exception
{
// EV: pull private vars in.
List<IVersionedId> rootsToInstall = (List<IVersionedId>)this.getPrivateField("rootsToInstall");
List<IVersionedId> rootsToUninstall = (List<IVersionedId>)this.getPrivateField("rootsToUninstall");
// EV: invoke private methods
//IProfile profile = initializeProfile();
//Collection<IInstallableUnit> installs = collectRoots(profile, rootsToInstall, true);
//Collection<IInstallableUnit> uninstalls = collectRoots(profile, rootsToUninstall, false);
IProfile profile = (IProfile)
invokePrivate("initializeProfile", new Class[0], new Object[0]);
Collection<IInstallableUnit> installs = (Collection<IInstallableUnit>)
invokePrivate("collectRoots",
new Class[]{IProfile.class, List.class, Boolean.TYPE},
new Object[]{profile, rootsToInstall, true});
Collection<IInstallableUnit> uninstalls = (Collection<IInstallableUnit>)
invokePrivate("collectRoots",
new Class[]{IProfile.class, List.class, Boolean.TYPE},
new Object[]{profile, rootsToUninstall, false});
// 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 {
// EV: invoke private methods
//updateRoamingProperties(profile);
invokePrivate("updateRoamingProperties",
new Class[]{IProfile.class}, new Object[]{profile});
// EV: pull in private fields
IProvisioningAgent targetAgent = (IProvisioningAgent)this.getPrivateField("targetAgent");
List<URI> metadataRepositoryLocations = (List<URI>)this.getPrivateField("metadataRepositoryLocations");
List<URI> artifactRepositoryLocations = (List<URI>)this.getPrivateField("artifactRepositoryLocations");
boolean followReferences = ((Boolean)this.getPrivateField("followReferences")).booleanValue();
String FOLLOW_ARTIFACT_REPOSITORY_REFERENCES = (String)this.getPrivateField("FOLLOW_ARTIFACT_REPOSITORY_REFERENCES");
ProvisioningContext context = new ProvisioningContext(targetAgent);
context.setMetadataRepositories(metadataRepositoryLocations.toArray(new URI[metadataRepositoryLocations.size()]));
context.setArtifactRepositories(artifactRepositoryLocations.toArray(new URI[artifactRepositoryLocations.size()]));
context.setProperty(ProvisioningContext.FOLLOW_REPOSITORY_REFERENCES, String.valueOf(followReferences));
context.setProperty(FOLLOW_ARTIFACT_REPOSITORY_REFERENCES, String.valueOf(followReferences));
// EV: invoke private methods
//ProfileChangeRequest request = buildProvisioningRequest(profile, installs, uninstalls);
//printRequest(request);
ProfileChangeRequest request = (ProfileChangeRequest)
invokePrivate("buildProvisioningRequest",
new Class[]{IProfile.class, Collection.class, Collection.class},
new Object[]{profile, installs, uninstalls});
invokePrivate(
"printRequest",
new Class[]{ProfileChangeRequest.class},
new Object[]{request});
planAndExecute(profile, context, request);
} 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())
// EV: invoke private method
//setRoaming(profile);
invokePrivate("setRoaming", new Class[]{IProfile.class}, new Object[]{profile});
}
}
private void planAndExecute(
IProfile profile, ProvisioningContext context, ProfileChangeRequest request)
// EV: throw a regular Exception to account for reflection exceptions
//throws CoreException
throws Exception
{
// EV: pull some private vars in to local scope.
IPlanner planner = (IPlanner)this.getPrivateField("planner");
IProvisioningPlan result = planner.getProvisioningPlan(
request, context, new NullProgressMonitor());
IStatus operationStatus = result.getStatus();
if (!operationStatus.isOK())
throw new CoreException(operationStatus);
executePlan(context, result);
}
private void executePlan(ProvisioningContext context, IProvisioningPlan result)
// EV: throw a regular Exception to account for reflection exceptions
//throws CoreException
throws Exception
{
// EV: pull some private vars in to local scope.
IEngine engine = (IEngine)this.getPrivateField("engine");
boolean verifyOnly = ((Boolean)this.getPrivateField("verifyOnly")).booleanValue();
boolean noArtifactRepositorySpecified = ((Boolean)this.getPrivateField("noArtifactRepositorySpecified")).booleanValue();
IStatus operationStatus;
if (!verifyOnly) {
// EV: plug in the eclim installer progress monitor
//operationStatus = PlanExecutionHelper.executePlan(result, engine, context, new NullProgressMonitor());
operationStatus = PlanExecutionHelper.executePlan(result, engine, context, new ProgressMonitor());
if (!operationStatus.isOK()) {
// EV: invoke private method
//if (noArtifactRepositorySpecified && hasNoRepositoryFound(operationStatus))
boolean hasNoRepositoryFound = ((Boolean)invokePrivate(
"hasNoRepositoryFound",
new Class[]{IStatus.class},
new Object[]{operationStatus})).booleanValue();
if (noArtifactRepositorySpecified && hasNoRepositoryFound)
throw new ProvisionException(Messages.Application_NoRepositories);
throw new CoreException(operationStatus);
}
}
}
private static class ProgressMonitor
implements IProgressMonitor
{
private double totalWorked;
private boolean canceled;
/**
* {@inheritDoc}
* @see IProgressMonitor#beginTask(String,int)
*/
public void beginTask(String name, int totalWork)
{
System.out.println("beginTask: totalWork=" + totalWork + " name=" + name);
}
/**
* {@inheritDoc}
* @see IProgressMonitor#done()
*/
public void done()
{
System.out.println("done");
}
/**
* {@inheritDoc}
* @see IProgressMonitor#internalWorked(double)
*/
public void internalWorked(double work)
{
totalWorked += work;
System.out.println("internalWorked: " + totalWorked);
}
/**
* {@inheritDoc}
* @see IProgressMonitor#isCanceled()
*/
public boolean isCanceled()
{
return canceled;
}
/**
* {@inheritDoc}
* @see IProgressMonitor#setCanceled(boolean)
*/
public void setCanceled(boolean canceled)
{
this.canceled = canceled;
}
/**
* {@inheritDoc}
* @see IProgressMonitor#setTaskName(String)
*/
public void setTaskName(String name)
{
System.out.println("setTaskName: " + name);
}
/**
* {@inheritDoc}
* @see IProgressMonitor#subTask(String)
*/
public void subTask(String name)
{
if (name != null && !name.trim().equals(StringUtils.EMPTY)){
System.out.println("subTask: " + name);
}
}
/**
* {@inheritDoc}
* @see IProgressMonitor#worked(int)
*/
public void worked(int work)
{
totalWorked += work;
System.out.println("worked: " + totalWorked);
}
}
}