/******************************************************************************* * Copyright (c) 2007, 2008 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 * Code 9 - ongoing development * Cloudsmith - ongoing development *******************************************************************************/ package org.eclipse.buckminster.jnlp.p2.installer; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.buckminster.jnlp.p2.JNLPPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; 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.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.director.IDirector; import org.eclipse.equinox.internal.provisional.p2.director.ProfileChangeRequest; 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.IMetadataRepositoryManager; import org.eclipse.equinox.internal.provisional.p2.query.Collector; import org.eclipse.equinox.internal.provisional.p2.query.Query; import org.eclipse.osgi.service.environment.EnvironmentInfo; import org.eclipse.osgi.util.NLS; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; /** * This operation performs installation or update of an Eclipse-based product. */ @SuppressWarnings("restriction") public class InstallUpdateProductOperation implements IInstallOperation { private IArtifactRepositoryManager m_artifactRepoMan; private BundleContext m_bundleContext; private IDirector m_director; private final InstallDescription m_installDescription; private boolean m_isInstall = true; private IMetadataRepositoryManager m_metadataRepoMan; private IProfileRegistry m_profileRegistry; private IStatus m_result; private ArrayList<ServiceReference> m_serviceReferences = new ArrayList<ServiceReference>(); public InstallUpdateProductOperation(BundleContext context, InstallDescription description) { m_bundleContext = context; m_installDescription = description; } /** * Returns the result of the install operation, or <code>null</code> if no install operation has been run. */ public IStatus getResult() { return m_result; } /* * (non-Javadoc) * * @seeorg.eclipse.equinox.internal.provisional.p2.installer.IInstallOperation#install(org.eclipse.core.runtime. * IProgressMonitor) */ public IStatus install(IProgressMonitor pm) { SubMonitor monitor = SubMonitor.convert(pm, Messages.Op_Preparing, 100); try { try { preInstall(); m_isInstall = getProfile() == null; doInstall(monitor); m_result = new Status(IStatus.OK, JNLPPlugin.ID, m_isInstall ? Messages.Op_InstallComplete : Messages.Op_UpdateComplete, null); monitor.setTaskName(Messages.Op_Cleanup); } finally { postInstall(); } } catch(CoreException e) { m_result = e.getStatus(); } finally { monitor.done(); } return m_result; } /** * Returns whether this operation represents the product being installed for the first time, in a new profile. */ public boolean isFirstInstall() { return m_isInstall; } /** * Determine what top level installable units should be installed by the director */ private IInstallableUnit[] computeUnitsToInstall() throws CoreException { ArrayList<IInstallableUnit> result = new ArrayList<IInstallableUnit>(); VersionedName roots[] = m_installDescription.getRoots(); for(int i = 0; i < roots.length; i++) { VersionedName root = roots[i]; IInstallableUnit iu = findUnit(root); if(iu != null) result.add(iu); } return result.toArray(new IInstallableUnit[result.size()]); } /** * This profile is being updated; return the units to uninstall from the profile. */ private IInstallableUnit[] computeUnitsToUninstall(IProfile p) { return (IInstallableUnit[])p.query(InstallableUnitQuery.ANY, new Collector(), null).toArray( IInstallableUnit.class); } /** * Create and return the profile into which units will be installed. */ private IProfile createProfile() throws ProvisionException { IProfile profile = getProfile(); if(profile == null) { Map<Object, Object> properties = new HashMap<Object, Object>(); properties.put(IProfile.PROP_INSTALL_FOLDER, m_installDescription.getInstallLocation().toString()); EnvironmentInfo info = (EnvironmentInfo)ServiceHelper.getService(JNLPPlugin.getDefault().getContext(), EnvironmentInfo.class.getName()); String env = "osgi.os=" + info.getOS() + ",osgi.ws=" + info.getWS() + ",osgi.arch=" + info.getOSArch(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ properties.put(IProfile.PROP_ENVIRONMENTS, env); properties.putAll(m_installDescription.getProfileProperties()); IPath location = m_installDescription.getBundleLocation(); if(location != null) properties.put(IProfile.PROP_CACHE, location.toOSString()); profile = m_profileRegistry.addProfile(getProfileId(), properties); } return profile; } /** * Performs the actual product install or update. */ private void doInstall(SubMonitor monitor) throws CoreException { prepareMetadataRepositories(); prepareArtifactRepositories(); IProfile p = createProfile(); IInstallableUnit[] toInstall = computeUnitsToInstall(); monitor.worked(5); IStatus s; ProfileChangeRequest request = new ProfileChangeRequest(p); if(m_isInstall) { monitor.setTaskName(NLS.bind(Messages.Op_Installing, m_installDescription.getProductName())); request.addInstallableUnits(toInstall); s = m_director.provision(request, null, monitor.newChild(90)); } else { monitor.setTaskName(NLS.bind(Messages.Op_Updating, m_installDescription.getProductName())); IInstallableUnit[] toUninstall = computeUnitsToUninstall(p); request.removeInstallableUnits(toUninstall); request.addInstallableUnits(toInstall); s = m_director.provision(request, null, monitor.newChild(90)); } if(!s.isOK()) throw new CoreException(s); } /** * Returns an exception of severity error with the given error message. */ private CoreException fail(String message) { return fail(message, null); } /** * Returns an exception of severity error with the given error message. */ private CoreException fail(String message, Throwable throwable) { return new CoreException(new Status(IStatus.ERROR, JNLPPlugin.ID, message, throwable)); } /** * Finds and returns the installable unit with the given id, and optionally the given version. */ private IInstallableUnit findUnit(VersionedName spec) throws CoreException { String id = spec.getId(); if(id == null) throw fail(Messages.Op_NoId); Version version = spec.getVersion(); VersionRange range = VersionRange.emptyRange; if(version != null && !version.equals(Version.emptyVersion)) range = new VersionRange(version, true, version, true); Query query = new InstallableUnitQuery(id, range); Collector collector = new Collector(); Iterator<?> matches = m_metadataRepoMan.query(query, collector, null).iterator(); // pick the newest match IInstallableUnit newest = null; while(matches.hasNext()) { IInstallableUnit candidate = (IInstallableUnit)matches.next(); if(newest == null || (newest.getVersion().compareTo(candidate.getVersion()) < 0)) newest = candidate; } if(newest == null) throw fail(Messages.Op_IUNotFound + id); return newest; } /** * Returns the profile being installed into. */ private IProfile getProfile() { return m_profileRegistry.getProfile(getProfileId()); } /** * Returns the id of the profile to use for install/update based on this operation's install description. */ private String getProfileId() { IPath location = m_installDescription.getInstallLocation(); String profileName = (String)m_installDescription.getProfileProperties().get(P2PropertyKeys.PROP_PROFILE_NAME); profileName = profileName == null ? DEFAULT_PROFILE_NAME : profileName; if(location != null) return location.toString() + "/" + profileName; return m_installDescription.getProductName(); } private Object getService(String name) throws CoreException { ServiceReference ref = m_bundleContext.getServiceReference(name); if(ref == null) throw fail(Messages.Op_NoService + name); Object service = m_bundleContext.getService(ref); if(service == null) throw fail(Messages.Op_NoServiceImpl + name); m_serviceReferences.add(ref); return service; } private void postInstall() { for(Iterator<ServiceReference> it = m_serviceReferences.iterator(); it.hasNext();) { ServiceReference sr = it.next(); m_bundleContext.ungetService(sr); } m_serviceReferences.clear(); } private void preInstall() throws CoreException { // obtain required services m_serviceReferences.clear(); m_director = (IDirector)getService(IDirector.class.getName()); m_metadataRepoMan = (IMetadataRepositoryManager)getService(IMetadataRepositoryManager.class.getName()); m_artifactRepoMan = (IArtifactRepositoryManager)getService(IArtifactRepositoryManager.class.getName()); m_profileRegistry = (IProfileRegistry)getService(IProfileRegistry.class.getName()); } private void prepareArtifactRepositories() throws ProvisionException { // disable all cached repos // TODO remove - testing // URI[] knownRepos = m_artifactRepoMan.getKnownRepositories(0); // for(URI repo : knownRepos) // m_artifactRepoMan.setEnabled(repo, false); // end of remove URI[] repos = m_installDescription.getArtifactRepositories(); if(repos == null) return; for(URI repo : repos) { m_artifactRepoMan.loadRepository(repo, null); // enable repo (might be disabled) m_artifactRepoMan.setEnabled(repo, true); } } private void prepareMetadataRepositories() throws ProvisionException { // disable all cached repos // TODO remove - testing // URI[] knownRepos = m_metadataRepoMan.getKnownRepositories(0); // for(URI repo : knownRepos) // m_metadataRepoMan.setEnabled(repo, false); // end of remove URI[] repos = m_installDescription.getMetadataRepositories(); if(repos == null) return; for(URI repo : repos) { m_metadataRepoMan.loadRepository(repo, null); // enable repo (might be disabled) m_metadataRepoMan.setEnabled(repo, true); } } }