blob: 9f96758a588bc6bffe070a2214814018b619d181 [file] [log] [blame]
/*******************************************************************************
* 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<String, String>();
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<Object>(), wrapper);
}
// Installed content not a concern for collecting categories
return new ElementQueryDescriptor(queryable, categoryQuery, new Collector<Object>(), 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<Object>(), 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<Object>(), 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<Object>());
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<Object>(), new ProfileElementWrapper(null, element));
case AVAILABLE_ARTIFACTS :
if (!(queryable instanceof IArtifactRepository))
return null;
return new ElementQueryDescriptor(queryable, ArtifactKeyQuery.ALL_KEYS, new Collector<Object>(), new ArtifactKeyWrapper((IArtifactRepository) queryable, element));
default :
return null;
}
}
}