/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.motorola.studio.android.installer.utilities; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.IProvisioningAgentProvider; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.engine.IProfileRegistry; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.ILicense; import org.eclipse.equinox.p2.metadata.IRequirement; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.operations.InstallOperation; import org.eclipse.equinox.p2.operations.ProfileModificationJob; import org.eclipse.equinox.p2.operations.ProvisioningJob; import org.eclipse.equinox.p2.operations.ProvisioningSession; import org.eclipse.equinox.p2.operations.UpdateOperation; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.p2.repository.IRepository; import org.eclipse.equinox.p2.repository.IRepositoryReference; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; import org.eclipse.equinox.p2.ui.ProvisioningUI; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import com.motorola.studio.android.common.log.StudioLogger; import com.motorola.studio.android.installer.InstallerException; import com.motorola.studio.android.installer.InstallerPlugin; import com.motorola.studio.android.installer.i18n.InstallerNLS; /** * Utilities class with P2 auxiliary methods */ class P2Utilities { /** * Verify if a given IInstallableUnit is installed on the system (iterates over all known profiles) * @param iu IInstallableUnit to be checked * @return true if iu is installed, false otherwise. * @throws InstallerException */ protected static boolean isInstalled(IInstallableUnit iu, IProgressMonitor progressMonitor) throws InstallerException { return isInstalled(iu.getId(), null, progressMonitor); } /** * Verify if a InstallableUnit with the given id and version is installed on the system (iterates over all known profiles) * @param iuId id of the InstallableUnit to be checked * @param version version of the wanted installableUnit * @return true if iu is installed, false otherwise. * @throws InstallerException */ protected static boolean isInstalled(String iuId, Version version, IProgressMonitor progressMonitor) throws InstallerException { IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(iuId, version); return isInstalled(query, progressMonitor); } /** * Execute a query on every profile found, looking for InstallableUnits * @param query IQuery<IInstallableUnit> to be executed. * @return true if query results are available, false otherwise. * @throws InstallerException */ protected static boolean isInstalled(IQuery<IInstallableUnit> query, IProgressMonitor progressMonitor) throws InstallerException { IProvisioningAgent agent = getProvisioningAgent(); IProfileRegistry profileRegistry = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME); IProfile[] profiles = profileRegistry.getProfiles(); SubMonitor subMonitor = SubMonitor.convert(progressMonitor, profiles.length * 100); for (IProfile profile : profiles) { IQueryResult<IInstallableUnit> available = profile.query(query, subMonitor.newChild(100)); if (!available.isEmpty()) { return true; } } return false; } /** * Get the IProvisioningAgent for the current context. * @return * @throws InstallerException */ private static IProvisioningAgent getProvisioningAgent() throws InstallerException { BundleContext context = InstallerPlugin.getContext(); IProvisioningAgent agent = getProvisioningAgent(context); return agent; } /** * Loads every IInstallableUnit that matches the criteria specified by filter on a given IMetadataRepository * @param metadatarepository Repository containing the IUs * @param query criteria to be used to filter the InstallableUnits on the given MetadataRepository, if null them all IUs * available are returned * @param progressMonitor * @return collection containing all IInstallableUnits from the given repository. * @throws InstallerException */ protected static Collection<IInstallableUnit> getInstallableUnits( IMetadataRepository metadataRepository, IQuery<IInstallableUnit> query, IProgressMonitor progressMonitor) throws InstallerException { SubMonitor subMonitor = SubMonitor.convert(progressMonitor); subMonitor.beginTask(InstallerNLS.P2Utilities_LoadingUnits, 100); Collection<IInstallableUnit> installableUnits; installableUnits = null; if (metadataRepository != null) { if (query == null) { query = QueryUtil.createIUAnyQuery(); } IQueryResult<IInstallableUnit> queryResult = metadataRepository.query(query, subMonitor.newChild(100)); installableUnits = queryResult.toSet(); } return installableUnits; } /** * Retrieves the IMetadataRepository object based on the repository URI * @param metadatarepoUri URI pointing to the MetadataRepository * @param progressMonitor * @return the IMetadataRepository object, if there's no repository on the given URI null will be returned. */ protected static IMetadataRepository getMetadataRepository(URI metadatarepoUri, IProgressMonitor progressMonitor) throws InstallerException, OperationCanceledException { SubMonitor subMonitor = SubMonitor.convert(progressMonitor); subMonitor.beginTask(InstallerNLS.P2Utilities_Preparing, 100); IMetadataRepository metadataRepository = null; IProvisioningAgent agent = getProvisioningAgent(); subMonitor.worked(10); IMetadataRepositoryManager metadataRepositoryManagermanager = (IMetadataRepositoryManager) agent .getService(IMetadataRepositoryManager.SERVICE_NAME); subMonitor.worked(15); try { metadataRepository = metadataRepositoryManagermanager.loadRepository(metadatarepoUri, subMonitor.newChild(75)); } catch (ProvisionException e) { InstallerException installerException; if (e.getStatus().getCode() == ProvisionException.REPOSITORY_FAILED_AUTHENTICATION) { installerException = new InstallerException(InstallerNLS.P2Utilities_AuthenticationFailed); } else { installerException = new InstallerException(e); } throw installerException; } return metadataRepository; } /** * Retrieves the IArtifactRepository object based on the repository URI * @param artifactRepoUri URI pointing to the MetadataRepository * @param progressMonitor * @return the IArtifactRepository object, if there's no repository on the given URI null will be returned. */ protected static IArtifactRepository getArtifactRepository(URI artifactRepoUri, IProgressMonitor progressMonitor) throws InstallerException { SubMonitor subMonitor = SubMonitor.convert(progressMonitor, 175); subMonitor.beginTask(InstallerNLS.P2Utilities_Preparing, 25); IArtifactRepository artifactRepository = null; IProvisioningAgent agent = getProvisioningAgent(); subMonitor.worked(10); IArtifactRepositoryManager artifactRepositoryManagermanager = (IArtifactRepositoryManager) agent .getService(IArtifactRepositoryManager.SERVICE_NAME); subMonitor.worked(15); try { artifactRepository = artifactRepositoryManagermanager.loadRepository(artifactRepoUri, subMonitor.newChild(150)); } catch (ProvisionException e) { throw new InstallerException(e); } catch (OperationCanceledException e) { throw new InstallerException(e); } return artifactRepository; } /** * Retrieves the InstallOperation that is necessary to install the given IUS on the current Profile. * @param installableUnits to be installed. * @param metadataRepositories metadataRepositories to be used * @param artifactRepositories artifactRepositories to be used * @param progressMonitor * @return the InstallOperation * @throws InstallerException if any error occurs */ protected static InstallOperation getInstallOperation( Collection<IInstallableUnit> installableUnits, Collection<IMetadataRepository> metadataRepositories, IProgressMonitor progressMonitor) throws InstallerException { SubMonitor subMonitor = SubMonitor.convert(progressMonitor); subMonitor.beginTask(InstallerNLS.P2Utilities_PreparingEnvironment, 200); final ProvisioningUI provisioningUI = ProvisioningUI.getDefaultUI(); ProvisioningSession session = provisioningUI.getSession(); subMonitor.worked(50); final InstallOperation op = new InstallOperation(session, installableUnits); if (metadataRepositories != null) { List<URI> metadataRepositoriesURIs = new ArrayList<URI>(); List<URI> artifactRepositoriesURIs = new ArrayList<URI>(); for (IMetadataRepository repository : metadataRepositories) { metadataRepositoriesURIs.add(repository.getLocation()); artifactRepositoriesURIs.add(repository.getLocation()); Collection<IRepositoryReference> references = repository.getReferences(); for (IRepositoryReference reference : references) { if ((reference.getOptions() == IRepository.ENABLED) && (reference.getType() == IRepository.TYPE_METADATA)) { metadataRepositoriesURIs.add(reference.getLocation()); } else if ((reference.getOptions() == IRepository.ENABLED) && (reference.getType() == IRepository.TYPE_ARTIFACT)) { artifactRepositoriesURIs.add(reference.getLocation()); } } } op.getProvisioningContext().setMetadataRepositories( metadataRepositoriesURIs.toArray(new URI[0])); op.getProvisioningContext().setArtifactRepositories( artifactRepositoriesURIs.toArray(new URI[0])); } subMonitor.worked(50); op.resolveModal(subMonitor.newChild(80)); final boolean[] canContinue = new boolean[] { true }; Display.getDefault().syncExec(new Runnable() { public void run() { canContinue[0] = provisioningUI.getPolicy().continueWorkingWithOperation(op, PlatformUI.getWorkbench().getModalDialogShellProvider().getShell()); } }); subMonitor.done(); return canContinue[0] ? op : null; } /** * Installs the given InstallableUnits, from the given repositories, on the current profile. * @param installableUnits to be installed * @param metadataRepositories metadataRepositories to be used * @param artifactRepositories artifactRepositories to be used * @param progressMonitor * @return * @throws InstallerException */ protected static IStatus installIu(Collection<IInstallableUnit> installableUnits, InstallOperation installOperation, IProgressMonitor progressMonitor) throws InstallerException { IStatus result = installOperation.getResolutionResult(); if (installOperation.hasResolved() && installOperation.getResolutionResult().isOK()) { ProvisioningJob provisioningJob = installOperation.getProvisioningJob(progressMonitor); if (provisioningJob instanceof ProfileModificationJob) { ((ProfileModificationJob) provisioningJob) .setRestartPolicy(ProvisioningJob.RESTART_NONE); } ProvisioningUI.getDefaultUI().manageJob(provisioningJob, ProvisioningJob.RESTART_NONE); provisioningJob.schedule(); try { provisioningJob.join(); result = provisioningJob.getResult(); if (result.getSeverity() == IStatus.ERROR) { String installableItensNames = ""; for (IInstallableUnit iu : installableUnits) { if (installableItensNames.equals("")) { installableItensNames = P2Utilities.getIUExternalizedValue(iu, IInstallableUnit.PROP_NAME); } else { installableItensNames = installableItensNames + ", " + P2Utilities.getIUExternalizedValue(iu, IInstallableUnit.PROP_NAME); } } result = new Status(IStatus.ERROR, InstallerPlugin.PLUGIN_ID, "Some components (" + installableItensNames + ") could not be downloaded."); } } catch (InterruptedException e) { StudioLogger.error("Error while trying to launch p2 job"); result = new Status(IStatus.ERROR, InstallerPlugin.PLUGIN_ID, 0, InstallerNLS.P2Utilities_ErrorWhileLaunchingP2Job, null); } } return result; } /** * Installs the given InstallableUnits, from the given repositories, on the current profile. * @param installableUnits to be installed * @param metadataRepositories metadataRepositories to be used * @param artifactRepositories artifactRepositories to be used * @param progressMonitor * @return * @throws InstallerException */ protected static IStatus installIu(Collection<IInstallableUnit> installableUnits, Collection<IMetadataRepository> metadataRepositories, IProgressMonitor progressMonitor) throws InstallerException { final InstallOperation op = getInstallOperation(installableUnits, metadataRepositories, progressMonitor); IStatus result = null; if (op != null) { result = op.getResolutionResult(); if (op.hasResolved() && op.getResolutionResult().isOK()) { ProvisioningUI defaultUI = ProvisioningUI.getDefaultUI(); ProvisioningJob provisioningJob = op.getProvisioningJob(progressMonitor); if (provisioningJob instanceof ProfileModificationJob) { ((ProfileModificationJob) provisioningJob) .setRestartPolicy(ProvisioningJob.RESTART_NONE); } defaultUI.manageJob(provisioningJob, ProvisioningJob.RESTART_NONE); provisioningJob.schedule(); try { provisioningJob.join(); result = provisioningJob.getResult(); if (result.getSeverity() == IStatus.ERROR) { String installableItensNames = ""; for (IInstallableUnit iu : installableUnits) { if (installableItensNames.equals("")) { installableItensNames = P2Utilities.getIUExternalizedValue(iu, IInstallableUnit.PROP_NAME); } else { installableItensNames = installableItensNames + ", " + P2Utilities.getIUExternalizedValue(iu, IInstallableUnit.PROP_NAME); } } result = new Status(IStatus.ERROR, InstallerPlugin.PLUGIN_ID, "Some components (" + installableItensNames + ") could not be downloaded."); } } catch (InterruptedException e) { StudioLogger.error("Error while trying to launch p2 job"); result = new Status(IStatus.ERROR, InstallerPlugin.PLUGIN_ID, 0, InstallerNLS.P2Utilities_ErrorWhileLaunchingP2Job, null); } } } else { result = Status.CANCEL_STATUS; } return result; } /** * Retrieves a provisioning agent for the given context. * @param context * @return the IprovisioningAgent * @throws InstallerException */ protected static IProvisioningAgent getProvisioningAgent(BundleContext context) throws InstallerException { ServiceReference<?> agentProviderRef = context.getServiceReference(IProvisioningAgentProvider.SERVICE_NAME); IProvisioningAgentProvider agentProvider = null; if (agentProviderRef != null) { agentProvider = (IProvisioningAgentProvider) context.getService(agentProviderRef); } IProvisioningAgent agent = null; try { agent = agentProvider.createAgent(null); } catch (ProvisionException e) { throw new InstallerException(e); } return agent; } /** * Get the possible localized iu name. Return the iu property name if none translatable name was found * @param iu * @return the name of the IU */ protected static String getIUExternalizedValue(IInstallableUnit iu, String property) { String iuNameProperty = iu.getProperty(property, null); String iuName = iuNameProperty; if (iuNameProperty == null) { String iuNameTemp = null; String currentLang = Platform.getNL(); if (currentLang.contains("_")) { currentLang = currentLang.split("_")[0]; iuNameTemp = iu.getProperty(currentLang + "." + iuNameProperty); } if (iuNameTemp == null) { iuNameTemp = iu.getProperty("df_LT." + iuNameProperty); } if (iuNameTemp != null) { iuName = iuNameTemp; } else { iuName = iu.getProperty(property); } } return iuName; } /** * Retrieves a collection containing all the licences * ILicense given an Installable Unit * @param iu * @return */ protected static Collection<ILicense> getLicenses(IInstallableUnit iu) { Collection<ILicense> licenses = iu.getLicenses(null); if (licenses.isEmpty()) { String currentLang = Platform.getNL(); if (currentLang.contains("_")) { currentLang = currentLang.split("_")[0]; licenses = iu.getLicenses(currentLang); } if (licenses.isEmpty()) { licenses = iu.getLicenses("df_LT"); } if (licenses.isEmpty()) { licenses = iu.getLicenses(); } } return licenses; } /** * Check if the installable unit is a group IU * @param unit * @return true if it contains the group property, false otherwise */ protected static boolean isGroup(IInstallableUnit unit) { return unit.getProperty(QueryUtil.PROP_TYPE_GROUP) != null ? unit.getProperty( QueryUtil.PROP_TYPE_GROUP).equals("true") : false; //$NON-NLS-1$ } /** * Given a Installable Unit, retrieves * a list of the requirements descriptions. * * @param iu * @return */ static List<String> getRequirements(IInstallableUnit iu) { List<String> results = new ArrayList<String>(); Collection<IRequirement> requirements = iu.getRequirements(); for (Iterator<IRequirement> iterator = requirements.iterator(); iterator.hasNext();) { IRequirement iRequirement = iterator.next(); results.add(iRequirement.getDescription()); } return results; } /** * Mounts a only string with the all the licenses texts. * Uses the '\n' char for new lines between licenses * * @param iu * @return */ static String getLicenseText(IInstallableUnit iu) { StringBuffer buffer = new StringBuffer(); if (iu != null) { Collection<ILicense> licenses = P2Utilities.getLicenses(iu); for (ILicense license : licenses) { buffer.append(license.getBody()); buffer.append("\n\n\n"); //$NON-NLS-1$ } } return buffer.toString(); } /** * Retrieves the UpdateOperation that is necessary to update available IUS on the current Profile. * * @param repositories where the update should be searched * @param progressMonitor * @return * @throws InstallerException */ protected static UpdateOperation getUpdateOperation(Collection<URI> repositories, IProgressMonitor progressMonitor) throws InstallerException { final ProvisioningUI provisioningUI = ProvisioningUI.getDefaultUI(); ProvisioningSession session = provisioningUI.getSession(); final UpdateOperation op = new UpdateOperation(session); final boolean[] canContinue = new boolean[] { false }; ArrayList<IRepositoryReference> references = new ArrayList<IRepositoryReference>(); ArrayList<URI> metadataRepositories = new ArrayList<URI>(); ArrayList<URI> artifactRepositories = new ArrayList<URI>(); IMetadataRepository repository = null; for (Iterator<URI> iterator = repositories.iterator(); iterator.hasNext();) { URI uri = iterator.next(); try { repository = getMetadataRepository(uri, progressMonitor); metadataRepositories.add(uri); } catch (OperationCanceledException e) { progressMonitor.setCanceled(true); } } if (repository != null) { references.addAll(repository.getReferences()); } for (IRepositoryReference reference : references) { if (reference.getOptions() == IRepository.ENABLED) { if (reference.getType() == IRepository.TYPE_METADATA) { metadataRepositories.add(reference.getLocation()); } else { artifactRepositories.add(reference.getLocation()); } } } if (!progressMonitor.isCanceled()) { SubMonitor subMonitor = SubMonitor.convert(progressMonitor); subMonitor.beginTask(InstallerNLS.P2Utilities_PreparingEnvironment, 200); op.getProvisioningContext().setMetadataRepositories( metadataRepositories.toArray(new URI[0])); op.getProvisioningContext().setArtifactRepositories( artifactRepositories.toArray(new URI[0])); subMonitor.worked(100); op.resolveModal(subMonitor.newChild(100)); Display.getDefault().syncExec(new Runnable() { public void run() { canContinue[0] = provisioningUI.getPolicy().continueWorkingWithOperation( op, PlatformUI.getWorkbench().getModalDialogShellProvider() .getShell()); } }); subMonitor.done(); } else { canContinue[0] = false; } return canContinue[0] ? op : null; } /** * Method which will receive an UpdateOperation and will start the update action. * * @param up * @param progressMonitor * @return * @throws InstallerException */ protected static IStatus updateIu(UpdateOperation up, IProgressMonitor progressMonitor) throws InstallerException { IStatus result = new Status(IStatus.ERROR, InstallerPlugin.PLUGIN_ID, 0, InstallerNLS.P2Utilities_ErrorDuringUpdate, null); if ((up != null) && up.hasResolved() && up.getResolutionResult().isOK()) { ProvisioningJob provisioningJob = up.getProvisioningJob(progressMonitor); if (provisioningJob instanceof ProfileModificationJob) { ((ProfileModificationJob) provisioningJob) .setRestartPolicy(ProvisioningJob.RESTART_NONE); } try { ProvisioningUI.getDefaultUI().manageJob(provisioningJob, ProvisioningJob.RESTART_NONE); provisioningJob.schedule(); } catch (Exception e) { StudioLogger.error(P2Utilities.class, "updateIu error when schedulling Job. ", e); } try { provisioningJob.join(); result = provisioningJob.getResult(); } catch (InterruptedException e) { StudioLogger.error(P2Utilities.class, "Error while trying to launch p2 job.", e); result = new Status(IStatus.ERROR, InstallerPlugin.PLUGIN_ID, 0, InstallerNLS.P2Utilities_ErrorWhileLaunchingP2Job, null); } } if (!result.isOK()) { StudioLogger.error(P2Utilities.class, "updateIu exiting with status different from ok. " + result.toString() + " - " + result.getMessage()); } return result; } }