1 /******************************************************************************* 2 * Copyright (c) 2008, 2010 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * EclipseSource - ongoing development 14 *******************************************************************************/ 15 package org.eclipse.equinox.internal.p2.ui; 16 17 import java.net.URI; 18 import java.util.*; 19 import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; 20 import org.eclipse.equinox.internal.p2.ui.model.*; 21 import org.eclipse.equinox.internal.p2.ui.query.*; 22 import org.eclipse.equinox.p2.engine.IProfile; 23 import org.eclipse.equinox.p2.metadata.IInstallableUnit; 24 import org.eclipse.equinox.p2.metadata.IRequirement; 25 import org.eclipse.equinox.p2.metadata.expression.*; 26 import org.eclipse.equinox.p2.query.*; 27 import org.eclipse.equinox.p2.repository.artifact.ArtifactKeyQuery; 28 import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; 29 import org.eclipse.equinox.p2.ui.Policy; 30 import org.eclipse.equinox.p2.ui.ProvisioningUI; 31 32 /** 33 * Provides a default set of queries to drive the provisioning UI. 34 * 35 * @since 3.5 36 */ 37 38 public class QueryProvider { 39 40 private ProvisioningUI ui; 41 42 public static final int METADATA_REPOS = 1; 43 public static final int ARTIFACT_REPOS = 2; 44 public static final int PROFILES = 3; 45 public static final int AVAILABLE_IUS = 4; 46 public static final int AVAILABLE_UPDATES = 5; 47 public static final int INSTALLED_IUS = 6; 48 public static final int AVAILABLE_ARTIFACTS = 7; 49 QueryProvider(ProvisioningUI ui)50 public QueryProvider(ProvisioningUI ui) { 51 this.ui = ui; 52 } 53 54 /* 55 * Return a map of key/value pairs which are set to the environment settings 56 * for the given profile. May return <code>null</code> or an empty <code>Map</code> 57 * if the settings cannot be obtained. 58 */ getEnvFromProfile(IProfile profile)59 private static Map<String, String> getEnvFromProfile(IProfile profile) { 60 if (profile == null) 61 return null; 62 String environments = profile.getProperty(IProfile.PROP_ENVIRONMENTS); 63 if (environments == null) 64 return null; 65 Map<String, String> result = new HashMap<>(); 66 for (StringTokenizer tokenizer = new StringTokenizer(environments, ","); tokenizer.hasMoreElements();) { //$NON-NLS-1$ 67 String entry = tokenizer.nextToken(); 68 int i = entry.indexOf('='); 69 String key = entry.substring(0, i).trim(); 70 String value = entry.substring(i + 1).trim(); 71 result.put(key, value); 72 } 73 return result; 74 } 75 76 // If we are supposed to filter out the results based on the environment settings in 77 // the target profile then create a compound query otherwise just return the given query createEnvironmentFilterQuery(IUViewQueryContext context, IProfile profile, IQuery<IInstallableUnit> query)78 private IQuery<IInstallableUnit> createEnvironmentFilterQuery(IUViewQueryContext context, IProfile profile, IQuery<IInstallableUnit> query) { 79 if (!context.getFilterOnEnv()) 80 return query; 81 Map<String, String> environment = getEnvFromProfile(profile); 82 if (environment == null) 83 return query; 84 IInstallableUnit envIU = InstallableUnit.contextIU(environment); 85 IQuery<IInstallableUnit> filterQuery = QueryUtil.createMatchQuery("filter == null || $0 ~= filter", envIU); //$NON-NLS-1$ 86 return QueryUtil.createCompoundQuery(query, filterQuery, true); 87 } 88 getQueryDescriptor(final QueriedElement element)89 public ElementQueryDescriptor getQueryDescriptor(final QueriedElement element) { 90 // Initialize queryable, queryContext, and queryType from the element. 91 // In some cases we override this. 92 Policy policy = ui.getPolicy(); 93 IQueryable<?> queryable = element.getQueryable(); 94 int queryType = element.getQueryType(); 95 IUViewQueryContext context = element.getQueryContext(); 96 if (context == null) { 97 context = ProvUI.getQueryContext(policy); 98 context.setInstalledProfileId(ui.getProfileId()); 99 } 100 switch (queryType) { 101 case ARTIFACT_REPOS : 102 queryable = new QueryableArtifactRepositoryManager(ui, false).locationsQueriable(); 103 return new ElementQueryDescriptor(queryable, new RepositoryLocationQuery(), new Collector<URI>(), new ArtifactRepositoryElementWrapper(null, element)); 104 105 case AVAILABLE_IUS : 106 // Things get more complicated if the user wants to filter out installed items. 107 // This involves setting up a secondary query for installed content that the various 108 // collectors will use to reject content. We can't use a compound query because the 109 // queryables are different (profile for installed content, repo for available content) 110 AvailableIUWrapper availableIUWrapper; 111 boolean showLatest = context.getShowLatestVersionsOnly(); 112 boolean hideInstalled = context.getHideAlreadyInstalled(); 113 IProfile targetProfile = null; 114 String profileId = context.getInstalledProfileId(); 115 if (profileId != null) { 116 targetProfile = ProvUI.getProfileRegistry(ui.getSession()).getProfile(profileId); 117 } 118 119 IQuery<IInstallableUnit> topLevelQuery = policy.getVisibleAvailableIUQuery(); 120 IQuery<IInstallableUnit> categoryQuery = QueryUtil.createIUCategoryQuery(); 121 122 topLevelQuery = createEnvironmentFilterQuery(context, targetProfile, topLevelQuery); 123 categoryQuery = createEnvironmentFilterQuery(context, targetProfile, categoryQuery); 124 125 // Showing child IU's of a group of repositories, or of a single repository 126 if (element instanceof MetadataRepositories || element instanceof MetadataRepositoryElement) { 127 if (context.getViewType() == IUViewQueryContext.AVAILABLE_VIEW_FLAT || !context.getUseCategories()) { 128 AvailableIUWrapper wrapper = new AvailableIUWrapper(queryable, element, false, context.getShowAvailableChildren()); 129 if (showLatest) 130 topLevelQuery = QueryUtil.createLatestQuery(topLevelQuery); 131 if (targetProfile != null) 132 wrapper.markInstalledIUs(targetProfile, hideInstalled); 133 return new ElementQueryDescriptor(queryable, topLevelQuery, new Collector<>(), wrapper); 134 } 135 // Installed content not a concern for collecting categories 136 return new ElementQueryDescriptor(queryable, categoryQuery, new Collector<>(), new CategoryElementWrapper(queryable, element)); 137 } 138 139 // If it's a category or some other IUElement to drill down in, we get the requirements and show all requirements 140 // that are also visible in the available list. 141 if (element instanceof CategoryElement || (element instanceof IIUElement && ((IIUElement) element).shouldShowChildren())) { 142 // children of a category should drill down according to the context. If we aren't in a category, we are already drilling down and 143 // continue to do so. 144 boolean drillDownTheChildren = element instanceof CategoryElement ? context.getShowAvailableChildren() : true; 145 IQuery<IInstallableUnit> memberOfCategoryQuery; 146 if (element instanceof CategoryElement) { 147 // We need an expression that uses the requirements of the element's requirements, which could be merged 148 // from multiple category IUs shown as one in the UI. 149 IExpression matchesRequirementsExpression = ExpressionUtil.parse("$0.exists(r | this ~= r)"); //$NON-NLS-1$ 150 memberOfCategoryQuery = QueryUtil.createMatchQuery(matchesRequirementsExpression, ((CategoryElement) element).getRequirements()); 151 } else { 152 memberOfCategoryQuery = QueryUtil.createIUCategoryMemberQuery(((IIUElement) element).getIU()); 153 } 154 memberOfCategoryQuery = createEnvironmentFilterQuery(context, targetProfile, memberOfCategoryQuery); 155 availableIUWrapper = new AvailableIUWrapper(queryable, element, true, drillDownTheChildren); 156 if (targetProfile != null) 157 availableIUWrapper.markInstalledIUs(targetProfile, hideInstalled); 158 // if it's a category, there is a special query. 159 if (element instanceof CategoryElement) { 160 if (showLatest) 161 memberOfCategoryQuery = QueryUtil.createLatestQuery(memberOfCategoryQuery); 162 return new ElementQueryDescriptor(queryable, memberOfCategoryQuery, new Collector<>(), availableIUWrapper); 163 } 164 // It is not a category, we want to traverse the requirements that are groups. 165 IQuery<IInstallableUnit> query = QueryUtil.createCompoundQuery(topLevelQuery, new RequiredIUsQuery(((IIUElement) element).getIU()), true); 166 if (showLatest) 167 query = QueryUtil.createLatestQuery(query); 168 // If it's not a category, these are generic requirements and should be filtered by the visibility property (topLevelQuery) 169 return new ElementQueryDescriptor(queryable, query, new Collector<>(), availableIUWrapper); 170 } 171 return null; 172 173 case AVAILABLE_UPDATES : 174 // This query can be used by the automatic updater in headless cases (checking for updates). 175 // We traffic in IU's rather than wrapped elements 176 IProfile profile; 177 IInstallableUnit[] toUpdate = null; 178 if (element instanceof Updates) { 179 profile = ProvUI.getProfileRegistry(ui.getSession()).getProfile(((Updates) element).getProfileId()); 180 toUpdate = ((Updates) element).getIUs(); 181 } else { 182 profile = ProvUI.getAdapter(element, IProfile.class); 183 } 184 if (profile == null) 185 return null; 186 if (toUpdate == null) { 187 IQueryResult<IInstallableUnit> queryResult = profile.query(policy.getVisibleInstalledIUQuery(), null); 188 toUpdate = queryResult.toArray(IInstallableUnit.class); 189 } 190 QueryableUpdates updateQueryable = new QueryableUpdates(ui, toUpdate); 191 return new ElementQueryDescriptor(updateQueryable, context.getShowLatestVersionsOnly() ? QueryUtil.createLatestIUQuery() : QueryUtil.createIUAnyQuery(), new Collector<>()); 192 193 case INSTALLED_IUS : 194 // Querying of IU's. We are drilling down into the requirements. 195 if (element instanceof IIUElement && context.getShowInstallChildren()) { 196 Collection<IRequirement> reqs = ((IIUElement) element).getRequirements(); 197 if (reqs.size() == 0) 198 return null; // no children 199 IExpression[] requirementExpressions = new IExpression[reqs.size()]; 200 int i = 0; 201 for (IRequirement req : reqs) { 202 requirementExpressions[i++] = req.getMatches(); 203 } 204 205 IExpressionFactory factory = ExpressionUtil.getFactory(); 206 IQuery<IInstallableUnit> meetsAnyRequirementQuery = QueryUtil.createMatchQuery(factory.or(requirementExpressions)); 207 IQuery<IInstallableUnit> visibleAsAvailableQuery = policy.getVisibleAvailableIUQuery(); 208 IQuery<IInstallableUnit> createCompoundQuery = QueryUtil.createCompoundQuery(visibleAsAvailableQuery, meetsAnyRequirementQuery, true); 209 return new ElementQueryDescriptor(queryable, createCompoundQuery, new Collector<IInstallableUnit>(), new InstalledIUElementWrapper(queryable, element)); 210 } 211 profile = ProvUI.getAdapter(element, IProfile.class); 212 if (profile == null) 213 return null; 214 return new ElementQueryDescriptor(profile, policy.getVisibleInstalledIUQuery(), new Collector<IInstallableUnit>(), new InstalledIUElementWrapper(profile, element)); 215 216 case METADATA_REPOS : 217 if (element instanceof MetadataRepositories) { 218 if (queryable == null) { 219 queryable = new QueryableMetadataRepositoryManager(ui, ((MetadataRepositories) element).getIncludeDisabledRepositories()).locationsQueriable(); 220 element.setQueryable(queryable); 221 } 222 return new ElementQueryDescriptor(element.getQueryable(), new RepositoryLocationQuery(), new Collector<URI>(), new MetadataRepositoryElementWrapper(null, element)); 223 } 224 return null; 225 226 case PROFILES : 227 queryable = new QueryableProfileRegistry(ui); 228 return new ElementQueryDescriptor(queryable, QueryUtil.createMatchQuery(IProfile.class, ExpressionUtil.TRUE_EXPRESSION), new Collector<>(), new ProfileElementWrapper(null, element)); 229 230 case AVAILABLE_ARTIFACTS : 231 if (!(queryable instanceof IArtifactRepository)) 232 return null; 233 return new ElementQueryDescriptor(queryable, ArtifactKeyQuery.ALL_KEYS, new Collector<>(), new ArtifactKeyWrapper((IArtifactRepository) queryable, element)); 234 235 default : 236 return null; 237 } 238 } 239 } 240