/** * This file Copyright (c) 2005-2010 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain Eclipse Public Licensed code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.update.internal.manager; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; import org.eclipse.equinox.internal.p2.ui.sdk.scheduler.AutomaticUpdatePlugin; import org.eclipse.equinox.internal.p2.ui.sdk.scheduler.PreferenceConstants; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepository; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepositoryManager; import org.eclipse.equinox.internal.provisional.p2.core.ProvisionException; import org.eclipse.equinox.internal.provisional.p2.core.Version; import org.eclipse.equinox.internal.provisional.p2.core.VersionRange; import org.eclipse.equinox.internal.provisional.p2.engine.IProfile; import org.eclipse.equinox.internal.provisional.p2.engine.IProfileRegistry; 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.repository.IMetadataRepository; import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepositoryManager; import org.eclipse.equinox.internal.provisional.p2.query.Collector; import org.eclipse.equinox.internal.provisional.p2.repository.IRepositoryManager; import org.eclipse.equinox.internal.provisional.p2.ui.IProvHelpContextIds; import org.eclipse.equinox.internal.provisional.p2.ui.QueryableMetadataRepositoryManager; import org.eclipse.equinox.internal.provisional.p2.ui.actions.UninstallAction; import org.eclipse.equinox.internal.provisional.p2.ui.dialogs.InstallWizard; import org.eclipse.equinox.internal.provisional.p2.ui.dialogs.ProvisioningWizardDialog; import org.eclipse.equinox.internal.provisional.p2.ui.model.ProfileElement; import org.eclipse.equinox.internal.provisional.p2.ui.operations.ProvisioningUtil; import org.eclipse.equinox.internal.provisional.p2.ui.policy.Policy; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import com.aptana.ide.core.IdeLog; import com.aptana.ide.internal.update.manager.AbstractPluginManager; import com.aptana.ide.update.P2Eclipse35Activator; import com.aptana.ide.update.manager.IPlugin; import com.aptana.ide.update.manager.Plugin; import com.aptana.ide.update.manager.PluginManagerException; @SuppressWarnings("restriction") public class P2Eclipse35PluginManager extends AbstractPluginManager { public P2Eclipse35PluginManager() { } /** * @see com.aptana.ide.update.manager.IPluginManager#addUpdateSite(java.net.URL) */ public boolean addUpdateSite(URL siteURL) { try { URI siteURI = siteURL.toURI(); URI[] existingMetaRepos = getAllMetadataRepositories(); if (contains(existingMetaRepos, siteURI)) { return false; } ProvisioningUtil.addMetadataRepository(siteURI, false); ProvisioningUtil.addArtifactRepository(siteURI, false); return true; } catch (Exception e) { // ignores the exception } return false; } /** * @see com.aptana.ide.update.manager.IPluginManager#removeUpdateSite(java.net.URL) */ public void removeUpdateSite(URL siteURL) { try { URI siteURI = siteURL.toURI(); ProvisioningUtil.removeMetadataRepository(siteURI); ProvisioningUtil.removeArtifactRepository(siteURI); } catch (Exception e) { // ignores the exception } } /** * @see com.aptana.ide.update.manager.IPluginManager#checkForUpdates(boolean) */ public void checkForUpdates(boolean immediate) { if (!immediate) { AutomaticUpdatePlugin.getDefault().getScheduler().earlyStartup(); return; } // Force the P2 automatic update check pref to be turned on, and force a // reschedule of the update check IPreferenceStore prefs = AutomaticUpdatePlugin.getDefault().getPreferenceStore(); // Grab existing values boolean wasEnabled = prefs.getBoolean(PreferenceConstants.PREF_AUTO_UPDATE_ENABLED); String oldSchedule = prefs.getString(PreferenceConstants.PREF_AUTO_UPDATE_SCHEDULE); // Force new ones temporarily prefs.setValue(PreferenceConstants.PREF_AUTO_UPDATE_ENABLED, true); prefs.setValue(PreferenceConstants.PREF_AUTO_UPDATE_SCHEDULE, PreferenceConstants.PREF_UPDATE_ON_STARTUP); AutomaticUpdatePlugin.getDefault().savePreferences(); // now check for updates AutomaticUpdatePlugin.getDefault().getScheduler().earlyStartup(); // Now revert prefs prefs.setValue(PreferenceConstants.PREF_AUTO_UPDATE_ENABLED, wasEnabled); prefs.setValue(PreferenceConstants.PREF_AUTO_UPDATE_SCHEDULE, oldSchedule); AutomaticUpdatePlugin.getDefault().savePreferences(); } /** * @see com.aptana.ide.update.manager.IPluginManager#install(Plugin[], IProgressMonitor) */ public IStatus install(final IPlugin[] plugins, IProgressMonitor monitor) throws PluginManagerException { if (monitor == null) { monitor = new NullProgressMonitor(); } if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } String profileId = IProfileRegistry.SELF; IInstallableUnit[] toInstall = getInstallationUnits(plugins, profileId); if (toInstall.length <= 0) { throw new PluginManagerException(P2Eclipse35Messages.P2PluginManager_ERR_MSG_No_installable_units_found); } if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } QueryableMetadataRepositoryManager queryableManager = new QueryableMetadataRepositoryManager(Policy .getDefault().getQueryContext(), false) { @Override protected URI[] getRepoLocations(IRepositoryManager manager) { URI[] result = new URI[plugins.length]; int i = 0; for (IPlugin ref : plugins) { try { result[i++] = ref.getURL().toURI(); } catch (URISyntaxException e) { // ignore for now } } return result; } }; InstallWizard wizard = new InstallWizard(generateNonManipulatingRepoPolicy(), profileId, toInstall, null, queryableManager); WizardDialog dialog = new ProvisioningWizardDialog(Display.getDefault().getActiveShell(), wizard); dialog.create(); PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(), IProvHelpContextIds.INSTALL_WIZARD); dialog.open(); return Status.OK_STATUS; } /** * Generates a copy of the default policy but removes the ability to manipulate repos, so that that portion of * Install Wizard UI doesn't show and mess up our installation process! * * @return */ private Policy generateNonManipulatingRepoPolicy() { Policy newPolicy = new Policy(); newPolicy.setLicenseManager(Policy.getDefault().getLicenseManager()); newPolicy.setPlanValidator(Policy.getDefault().getPlanValidator()); newPolicy.setProfileChooser(Policy.getDefault().getProfileChooser()); newPolicy.setQueryContext(Policy.getDefault().getQueryContext()); newPolicy.setQueryProvider(Policy.getDefault().getQueryProvider()); newPolicy.setRepositoryManipulator(null); return newPolicy; } /** * @see com.aptana.ide.update.manager.IPluginManager#uninstall(IPlugin, IProgressMonitor) */ public IStatus uninstall(IPlugin plugin, IProgressMonitor monitor) throws PluginManagerException { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } String profileId = IProfileRegistry.SELF; Collector roots = new Collector(); try { InstallableUnitQuery query = new InstallableUnitQuery(getFeatureGroupName(plugin), Version .parseVersion(plugin.getVersion())); ProfileElement element = new ProfileElement(null, profileId); roots = element.getQueryable().query(query, roots, monitor); } catch (CoreException e) { IdeLog.logError(P2Eclipse35Activator.getDefault(), e.getMessage(), e); } if (roots == null || roots.size() <= 0) { throw new PluginManagerException(P2Eclipse35Messages.P2PluginManager_ERR_MSG_No_installable_units_found); } final IInstallableUnit[] ius = (IInstallableUnit[]) roots.toArray(IInstallableUnit.class); if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } UninstallAction action = new UninstallAction(Policy.getDefault(), new ISelectionProvider() { public void addSelectionChangedListener( ISelectionChangedListener listener) { } public ISelection getSelection() { return new StructuredSelection(ius); } public void removeSelectionChangedListener( ISelectionChangedListener listener) { } public void setSelection(ISelection selection) { } }, profileId); action.run(); return Status.OK_STATUS; } private static boolean contains(URI[] existingMetaRepos, URI updateSiteURI) { if (existingMetaRepos == null) { return false; } for (int i = 0; i < existingMetaRepos.length; ++i) { if (existingMetaRepos[i].equals(updateSiteURI)) { return true; } } return false; } private static IInstallableUnit[] getInstallationUnits(final IPlugin[] plugins, final String profileId) throws PluginManagerException { final List<IInstallableUnit> units = new ArrayList<IInstallableUnit>(); IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { SubMonitor sub = SubMonitor.convert(monitor, plugins.length * 4); sub.setTaskName(P2Eclipse35Messages.P2PluginManager_Locating_selected_features_job_title); try { for (IPlugin plugin : plugins) { URI siteURL = plugin.getURL().toURI(); IMetadataRepositoryManager manager = (IMetadataRepositoryManager) ServiceHelper.getService( P2Eclipse35Activator.getContext(), IMetadataRepositoryManager.class.getName()); IMetadataRepository repo = manager.loadRepository(siteURL, new NullProgressMonitor()); if (repo == null) { throw new ProvisionException( P2Eclipse35Messages.P2PluginManager_ERR_MSG_Metadata_repo_not_found + siteURL); } if (!manager.isEnabled(siteURL)) { manager.setEnabled(siteURL, true); } sub.worked(1); IArtifactRepositoryManager artifactManager = (IArtifactRepositoryManager) ServiceHelper .getService(P2Eclipse35Activator.getContext(), IArtifactRepositoryManager.class .getName()); IArtifactRepository artifactRepo = artifactManager.loadRepository(siteURL, new NullProgressMonitor()); if (artifactRepo == null) { throw new ProvisionException( P2Eclipse35Messages.P2PluginManager_ERR_MSG_Artifact_repo_not_found + siteURL); } if (!artifactManager.isEnabled(siteURL)) { artifactManager.setEnabled(siteURL, true); } sub.worked(1); InstallableUnitQuery query = new InstallableUnitQuery(getFeatureGroupName(plugin), VersionRange.emptyRange); Collector roots = repo.query(query, new LatestIUVersionCollector(), monitor); if (roots.size() <= 0) { if (monitor.isCanceled()) { return; } IProfile profile = ProvisioningUtil.getProfile(profileId); roots = profile.query(query, roots, monitor); } units.addAll(roots.toCollection()); sub.worked(2); } } catch (Exception e) { throw new InvocationTargetException(e); } finally { sub.done(); } } }; try { new ProgressMonitorDialog(Display.getDefault().getActiveShell()).run(true, true, runnable); } catch (InterruptedException e) { // don't report thread interruption } catch (InvocationTargetException e) { throw new PluginManagerException(P2Eclipse35Messages.ProfileModificationAction_UnexpectedError, e .getCause()); } return units.toArray(new IInstallableUnit[units.size()]); } private static String getFeatureGroupName(IPlugin plugin) throws CoreException { return plugin.getId() + FEATURE_IU_SUFFIX; } private static class LatestIUVersionCollector extends Collector { private Map<String, Object> uniqueIds = new HashMap<String, Object>(); /** * Accepts a result that matches the query criteria. * * @param match * an object matching the query * @return <code>true</code> if the query should continue, or <code>false</code> to indicate the query should * stop. */ public boolean accept(Object match) { if (!(match instanceof IInstallableUnit)) { return true; } IInstallableUnit iu = (IInstallableUnit) match; // Look for the latest element Object matchElement = uniqueIds.get(iu.getId()); if (matchElement == null || iu.getVersion().compareTo(getIU(matchElement).getVersion()) > 0) { if (matchElement != null) { getCollection().remove(matchElement); } matchElement = makeDefaultElement(iu); uniqueIds.put(iu.getId(), matchElement); return super.accept(matchElement); } return true; } private Object makeDefaultElement(IInstallableUnit iu) { return iu; } protected IInstallableUnit getIU(Object matchElement) { if (matchElement instanceof IInstallableUnit) { return (IInstallableUnit) matchElement; } return null; } } public boolean isFeatureInstalled(String id) { return getInstalledFeature(id) != null; } public IPlugin getInstalledFeature(String id) { if (id == null) return null; if (!id.endsWith(FEATURE_IU_SUFFIX)) { id += FEATURE_IU_SUFFIX; } BundleContext context = P2Eclipse35Activator.getDefault().getBundle().getBundleContext(); ServiceReference ref = context.getServiceReference(IProfileRegistry.class.getName()); if (ref == null) return null; IProfileRegistry profileRegistry = (IProfileRegistry) context.getService(ref); if (profileRegistry == null) return null; IProfile profile = profileRegistry.getProfile(IProfileRegistry.SELF); if (profile == null) { IProfile[] profiles = profileRegistry.getProfiles(); if (profiles != null && profiles.length > 0) { profile = profiles[0]; } } if (profile == null) return null; Collector roots = profile.available(new InstallableUnitQuery(id), new Collector(), new NullProgressMonitor()); if (roots == null || roots.size() == 0) return null; try { return toPlugin((IInstallableUnit) roots.iterator().next()); } catch (MalformedURLException e) { IdeLog.logError(P2Eclipse35Activator.getDefault(), e.getMessage(), e); } return null; } public List<IPlugin> getInstalledPlugins() { BundleContext context = P2Eclipse35Activator.getDefault().getBundle().getBundleContext(); ServiceReference ref = context.getServiceReference(IProfileRegistry.class.getName()); if (ref == null) return Collections.emptyList(); IProfileRegistry profileRegistry = (IProfileRegistry) context.getService(ref); if (profileRegistry == null) return Collections.emptyList(); IProfile profile = profileRegistry.getProfile(IProfileRegistry.SELF); if (profile == null) { IProfile[] profiles = profileRegistry.getProfiles(); if (profiles != null && profiles.length > 0) { profile = profiles[0]; } } if (profile == null) return Collections.emptyList(); Collector roots = profile.available(new InstallableUnitQuery("FakeId") //$NON-NLS-1$ { public boolean isMatch(Object object) { if (!(object instanceof IInstallableUnit)) return false; IInstallableUnit candidate = (IInstallableUnit) object; String name = candidate.getId(); if (name == null || !name.endsWith(FEATURE_IU_SUFFIX)) // only features return false; return true; } }, new Collector(), new NullProgressMonitor()); IInstallableUnit[] ius = (IInstallableUnit[]) roots.toArray(IInstallableUnit.class); // Convert them to Plugin objects List<IPlugin> plugins = new ArrayList<IPlugin>(); for (IInstallableUnit iu : ius) { try { plugins.add(toPlugin(iu)); } catch (MalformedURLException e) { IdeLog.logError(P2Eclipse35Activator.getDefault(), e.getMessage(), e); } } return plugins; } public String getUpdatePreferencePageId() { return "org.eclipse.equinox.internal.p2.ui.sdk.scheduler.AutomaticUpdatesPreferencePage"; //$NON-NLS-1$ } private Plugin toPlugin(IInstallableUnit iu) throws MalformedURLException { String name = iu.getProperty("df_LT.featureName"); //$NON-NLS-1$ if (name == null) name = iu.getProperty(IInstallableUnit.PROP_NAME); if (name == null) name = iu.getId(); return new Plugin(stripFeatureGroup(iu.getId()), name, iu.getVersion().toString(), null, iu .getProperty("df_LT.description"), new URL("file:/fake/" + iu.getId()), "", "", 0, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ null, "", null); //$NON-NLS-1$ } private String stripFeatureGroup(String id) { if (id == null) return null; if (id.endsWith(FEATURE_IU_SUFFIX)) return id.substring(0, id.length() - FEATURE_IU_SUFFIX.length()); return id; } public URI[] getAllMetadataRepositories() throws PluginManagerException { try { return ProvisioningUtil.getMetadataRepositories(IRepositoryManager.REPOSITORIES_ALL); } catch (Exception e) { throw new PluginManagerException(e); } } }