/** * 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); } } }