/******************************************************************************* * Copyright (c) 2008, 2010 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 * EclipseSource - ongoing development *******************************************************************************/ package org.eclipse.equinox.internal.p2.ui; import java.net.URI; import java.util.*; import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; import org.eclipse.equinox.internal.p2.ui.model.*; import org.eclipse.equinox.internal.p2.ui.query.*; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IRequirement; import org.eclipse.equinox.p2.metadata.expression.*; import org.eclipse.equinox.p2.query.*; import org.eclipse.equinox.p2.repository.artifact.ArtifactKeyQuery; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; import org.eclipse.equinox.p2.ui.Policy; import org.eclipse.equinox.p2.ui.ProvisioningUI; /** * Provides a default set of queries to drive the provisioning UI. * * @since 3.5 */ public class QueryProvider { private ProvisioningUI ui; public static final int METADATA_REPOS = 1; public static final int ARTIFACT_REPOS = 2; public static final int PROFILES = 3; public static final int AVAILABLE_IUS = 4; public static final int AVAILABLE_UPDATES = 5; public static final int INSTALLED_IUS = 6; public static final int AVAILABLE_ARTIFACTS = 7; public QueryProvider(ProvisioningUI ui) { this.ui = ui; } /* * Return a map of key/value pairs which are set to the environment settings * for the given profile. May return <code>null</code> or an empty <code>Map</code> * if the settings cannot be obtained. */ private static Map<String, String> getEnvFromProfile(IProfile profile) { if (profile == null) return null; String environments = profile.getProperty(IProfile.PROP_ENVIRONMENTS); if (environments == null) return null; Map<String, String> result = new HashMap<>(); for (StringTokenizer tokenizer = new StringTokenizer(environments, ","); tokenizer.hasMoreElements();) { //$NON-NLS-1$ String entry = tokenizer.nextToken(); int i = entry.indexOf('='); String key = entry.substring(0, i).trim(); String value = entry.substring(i + 1).trim(); result.put(key, value); } return result; } // If we are supposed to filter out the results based on the environment settings in // the target profile then create a compound query otherwise just return the given query private IQuery<IInstallableUnit> createEnvironmentFilterQuery(IUViewQueryContext context, IProfile profile, IQuery<IInstallableUnit> query) { if (!context.getFilterOnEnv()) return query; Map<String, String> environment = getEnvFromProfile(profile); if (environment == null) return query; IInstallableUnit envIU = InstallableUnit.contextIU(environment); IQuery<IInstallableUnit> filterQuery = QueryUtil.createMatchQuery("filter == null || $0 ~= filter", envIU); //$NON-NLS-1$ return QueryUtil.createCompoundQuery(query, filterQuery, true); } public ElementQueryDescriptor getQueryDescriptor(final QueriedElement element) { // Initialize queryable, queryContext, and queryType from the element. // In some cases we override this. Policy policy = ui.getPolicy(); IQueryable<?> queryable = element.getQueryable(); int queryType = element.getQueryType(); IUViewQueryContext context = element.getQueryContext(); if (context == null) { context = ProvUI.getQueryContext(policy); context.setInstalledProfileId(ui.getProfileId()); } switch (queryType) { case ARTIFACT_REPOS : queryable = new QueryableArtifactRepositoryManager(ui, false).locationsQueriable(); return new ElementQueryDescriptor(queryable, new RepositoryLocationQuery(), new Collector<URI>(), new ArtifactRepositoryElementWrapper(null, element)); case AVAILABLE_IUS : // Things get more complicated if the user wants to filter out installed items. // This involves setting up a secondary query for installed content that the various // collectors will use to reject content. We can't use a compound query because the // queryables are different (profile for installed content, repo for available content) AvailableIUWrapper availableIUWrapper; boolean showLatest = context.getShowLatestVersionsOnly(); boolean hideInstalled = context.getHideAlreadyInstalled(); IProfile targetProfile = null; String profileId = context.getInstalledProfileId(); if (profileId != null) { targetProfile = ProvUI.getProfileRegistry(ui.getSession()).getProfile(profileId); } IQuery<IInstallableUnit> topLevelQuery = policy.getVisibleAvailableIUQuery(); IQuery<IInstallableUnit> categoryQuery = QueryUtil.createIUCategoryQuery(); topLevelQuery = createEnvironmentFilterQuery(context, targetProfile, topLevelQuery); categoryQuery = createEnvironmentFilterQuery(context, targetProfile, categoryQuery); // Showing child IU's of a group of repositories, or of a single repository if (element instanceof MetadataRepositories || element instanceof MetadataRepositoryElement) { if (context.getViewType() == IUViewQueryContext.AVAILABLE_VIEW_FLAT || !context.getUseCategories()) { AvailableIUWrapper wrapper = new AvailableIUWrapper(queryable, element, false, context.getShowAvailableChildren()); if (showLatest) topLevelQuery = QueryUtil.createLatestQuery(topLevelQuery); if (targetProfile != null) wrapper.markInstalledIUs(targetProfile, hideInstalled); return new ElementQueryDescriptor(queryable, topLevelQuery, new Collector<>(), wrapper); } // Installed content not a concern for collecting categories return new ElementQueryDescriptor(queryable, categoryQuery, new Collector<>(), new CategoryElementWrapper(queryable, element)); } // If it's a category or some other IUElement to drill down in, we get the requirements and show all requirements // that are also visible in the available list. if (element instanceof CategoryElement || (element instanceof IIUElement && ((IIUElement) element).shouldShowChildren())) { // children of a category should drill down according to the context. If we aren't in a category, we are already drilling down and // continue to do so. boolean drillDownTheChildren = element instanceof CategoryElement ? context.getShowAvailableChildren() : true; IQuery<IInstallableUnit> memberOfCategoryQuery; if (element instanceof CategoryElement) { // We need an expression that uses the requirements of the element's requirements, which could be merged // from multiple category IUs shown as one in the UI. IExpression matchesRequirementsExpression = ExpressionUtil.parse("$0.exists(r | this ~= r)"); //$NON-NLS-1$ memberOfCategoryQuery = QueryUtil.createMatchQuery(matchesRequirementsExpression, ((CategoryElement) element).getRequirements()); } else { memberOfCategoryQuery = QueryUtil.createIUCategoryMemberQuery(((IIUElement) element).getIU()); } memberOfCategoryQuery = createEnvironmentFilterQuery(context, targetProfile, memberOfCategoryQuery); availableIUWrapper = new AvailableIUWrapper(queryable, element, true, drillDownTheChildren); if (targetProfile != null) availableIUWrapper.markInstalledIUs(targetProfile, hideInstalled); // if it's a category, there is a special query. if (element instanceof CategoryElement) { if (showLatest) memberOfCategoryQuery = QueryUtil.createLatestQuery(memberOfCategoryQuery); return new ElementQueryDescriptor(queryable, memberOfCategoryQuery, new Collector<>(), availableIUWrapper); } // It is not a category, we want to traverse the requirements that are groups. IQuery<IInstallableUnit> query = QueryUtil.createCompoundQuery(topLevelQuery, new RequiredIUsQuery(((IIUElement) element).getIU()), true); if (showLatest) query = QueryUtil.createLatestQuery(query); // If it's not a category, these are generic requirements and should be filtered by the visibility property (topLevelQuery) return new ElementQueryDescriptor(queryable, query, new Collector<>(), availableIUWrapper); } return null; case AVAILABLE_UPDATES : // This query can be used by the automatic updater in headless cases (checking for updates). // We traffic in IU's rather than wrapped elements IProfile profile; IInstallableUnit[] toUpdate = null; if (element instanceof Updates) { profile = ProvUI.getProfileRegistry(ui.getSession()).getProfile(((Updates) element).getProfileId()); toUpdate = ((Updates) element).getIUs(); } else { profile = ProvUI.getAdapter(element, IProfile.class); } if (profile == null) return null; if (toUpdate == null) { IQueryResult<IInstallableUnit> queryResult = profile.query(policy.getVisibleInstalledIUQuery(), null); toUpdate = queryResult.toArray(IInstallableUnit.class); } QueryableUpdates updateQueryable = new QueryableUpdates(ui, toUpdate); return new ElementQueryDescriptor(updateQueryable, context.getShowLatestVersionsOnly() ? QueryUtil.createLatestIUQuery() : QueryUtil.createIUAnyQuery(), new Collector<>()); case INSTALLED_IUS : // Querying of IU's. We are drilling down into the requirements. if (element instanceof IIUElement && context.getShowInstallChildren()) { Collection<IRequirement> reqs = ((IIUElement) element).getRequirements(); if (reqs.size() == 0) return null; // no children IExpression[] requirementExpressions = new IExpression[reqs.size()]; int i = 0; for (IRequirement req : reqs) { requirementExpressions[i++] = req.getMatches(); } IExpressionFactory factory = ExpressionUtil.getFactory(); IQuery<IInstallableUnit> meetsAnyRequirementQuery = QueryUtil.createMatchQuery(factory.or(requirementExpressions)); IQuery<IInstallableUnit> visibleAsAvailableQuery = policy.getVisibleAvailableIUQuery(); IQuery<IInstallableUnit> createCompoundQuery = QueryUtil.createCompoundQuery(visibleAsAvailableQuery, meetsAnyRequirementQuery, true); return new ElementQueryDescriptor(queryable, createCompoundQuery, new Collector<IInstallableUnit>(), new InstalledIUElementWrapper(queryable, element)); } profile = ProvUI.getAdapter(element, IProfile.class); if (profile == null) return null; return new ElementQueryDescriptor(profile, policy.getVisibleInstalledIUQuery(), new Collector<IInstallableUnit>(), new InstalledIUElementWrapper(profile, element)); case METADATA_REPOS : if (element instanceof MetadataRepositories) { if (queryable == null) { queryable = new QueryableMetadataRepositoryManager(ui, ((MetadataRepositories) element).getIncludeDisabledRepositories()).locationsQueriable(); element.setQueryable(queryable); } return new ElementQueryDescriptor(element.getQueryable(), new RepositoryLocationQuery(), new Collector<URI>(), new MetadataRepositoryElementWrapper(null, element)); } return null; case PROFILES : queryable = new QueryableProfileRegistry(ui); return new ElementQueryDescriptor(queryable, QueryUtil.createMatchQuery(IProfile.class, ExpressionUtil.TRUE_EXPRESSION), new Collector<>(), new ProfileElementWrapper(null, element)); case AVAILABLE_ARTIFACTS : if (!(queryable instanceof IArtifactRepository)) return null; return new ElementQueryDescriptor(queryable, ArtifactKeyQuery.ALL_KEYS, new Collector<>(), new ArtifactKeyWrapper((IArtifactRepository) queryable, element)); default : return null; } } }