1 /******************************************************************************* 2 * Copyright (c) 2013, 2018 Red Hat, Inc. 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 * Red Hat, Inc. - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.equinox.internal.p2.operations; 15 16 import java.util.*; 17 import java.util.Map.Entry; 18 import org.eclipse.core.runtime.*; 19 import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest; 20 import org.eclipse.equinox.p2.engine.*; 21 import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery; 22 import org.eclipse.equinox.p2.metadata.*; 23 import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil; 24 import org.eclipse.equinox.p2.metadata.expression.IMatchExpression; 25 import org.eclipse.equinox.p2.planner.IPlanner; 26 import org.eclipse.equinox.p2.planner.IProfileChangeRequest; 27 import org.eclipse.equinox.p2.query.*; 28 29 public class RequestFlexer { 30 final String INCLUSION_RULES = "org.eclipse.equinox.p2.internal.inclusion.rules"; //$NON-NLS-1$ 31 final String INCLUSION_OPTIONAL = "OPTIONAL"; //$NON-NLS-1$ 32 final String INCLUSION_STRICT = "STRICT"; //$NON-NLS-1$ 33 final String EXPLANATION_ENABLEMENT = "org.eclipse.equinox.p2.director.explain"; //$NON-NLS-1$ 34 35 IPlanner planner; 36 37 private boolean allowInstalledUpdate = false; 38 private boolean allowInstalledRemoval = false; 39 private boolean allowDifferentVersion = false; 40 private boolean allowPartialInstall = false; 41 42 private boolean ensureProductPresence = true; 43 private boolean honorSharedSettings = true; 44 45 private ProvisioningContext provisioningContext; 46 47 Set<IRequirement> requirementsForElementsBeingInstalled = new HashSet<>(); 48 Set<IRequirement> requirementsForElementsAlreadyInstalled = new HashSet<>(); 49 Map<IRequirement, Map<String, String>> propertiesPerRequirement = new HashMap<>(); 50 Map<IRequirement, List<String>> removedPropertiesPerRequirement = new HashMap<>(); 51 52 IProfile profile; 53 54 private boolean foundDifferentVersionsForElementsToInstall = false; 55 private boolean foundDifferentVersionsForElementsInstalled = false; 56 private Set<IInstallableUnit> futureOptionalIUs; 57 RequestFlexer(IPlanner planner)58 public RequestFlexer(IPlanner planner) { 59 this.planner = planner; 60 } 61 setAllowInstalledElementChange(boolean allow)62 public void setAllowInstalledElementChange(boolean allow) { 63 allowInstalledUpdate = allow; 64 } 65 setAllowInstalledElementRemoval(boolean allow)66 public void setAllowInstalledElementRemoval(boolean allow) { 67 allowInstalledRemoval = allow; 68 } 69 setAllowDifferentVersion(boolean allow)70 public void setAllowDifferentVersion(boolean allow) { 71 allowDifferentVersion = allow; 72 } 73 setAllowPartialInstall(boolean allow)74 public void setAllowPartialInstall(boolean allow) { 75 allowPartialInstall = allow; 76 } 77 setProvisioningContext(ProvisioningContext context)78 public void setProvisioningContext(ProvisioningContext context) { 79 provisioningContext = context; 80 } 81 setEnsureProduct(boolean productPresent)82 public void setEnsureProduct(boolean productPresent) { 83 ensureProductPresence = productPresent; 84 } 85 getChangeRequest(IProfileChangeRequest request, IProfile prof, IProgressMonitor monitor)86 public IProfileChangeRequest getChangeRequest(IProfileChangeRequest request, IProfile prof, IProgressMonitor monitor) { 87 this.profile = prof; 88 SubMonitor sub = SubMonitor.convert(monitor, 2); 89 IProfileChangeRequest loosenedRequest = computeLooseRequest(request, sub.newChild(1)); 90 if (canShortCircuit(request)) { 91 return null; 92 } 93 IProvisioningPlan intermediaryPlan = resolve(loosenedRequest, sub.newChild(1)); 94 if (!intermediaryPlan.getStatus().isOK()) 95 return null; 96 if (intermediaryPlan.getAdditions().query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).isEmpty() && intermediaryPlan.getRemovals().query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).isEmpty()) 97 //No changes, we can't return anything 98 return null; 99 if (!productContainmentOK(intermediaryPlan)) { 100 return null; 101 } 102 IProfileChangeRequest effectiveRequest = computeEffectiveChangeRequest(intermediaryPlan, loosenedRequest, request); 103 if (isRequestUseless(effectiveRequest)) 104 return null; 105 return effectiveRequest; 106 } 107 isRequestUseless(IProfileChangeRequest effectiveRequest)108 private boolean isRequestUseless(IProfileChangeRequest effectiveRequest) { 109 if (effectiveRequest.getAdditions().isEmpty() && effectiveRequest.getRemovals().isEmpty()) 110 return true; 111 if (effectiveRequest.getRemovals().containsAll(effectiveRequest.getAdditions())) 112 return true; 113 return false; 114 } 115 canShortCircuit(IProfileChangeRequest originalRequest)116 private boolean canShortCircuit(IProfileChangeRequest originalRequest) { 117 //Case where the user is asking to install only some of the requested IUs but there is only one IU to install. 118 if (allowPartialInstall && !allowInstalledUpdate && !allowDifferentVersion && !allowInstalledRemoval) 119 if (originalRequest.getAdditions().size() == 1) 120 return true; 121 122 //When we can find a different version of the IU but the only version available is the one the user is asking to install 123 if (allowDifferentVersion && !allowPartialInstall && !allowInstalledRemoval && !allowInstalledUpdate) 124 if (!foundDifferentVersionsForElementsToInstall) 125 return true; 126 127 if (allowInstalledUpdate && !allowDifferentVersion && !allowPartialInstall && !allowInstalledRemoval) 128 if (!foundDifferentVersionsForElementsInstalled) 129 return true; 130 131 if (!allowPartialInstall && !allowInstalledUpdate && !allowDifferentVersion && !allowInstalledRemoval) 132 return true; 133 134 return false; 135 } 136 137 //From the loosened request and the plan resulting from its resolution, create a new profile change request representing the delta between where the profile currently is 138 // and the plan returned. 139 //To perform this efficiently, this relies on a traversal of the requirements that are part of the loosened request. computeEffectiveChangeRequest(IProvisioningPlan intermediaryPlan, IProfileChangeRequest loosenedRequest, IProfileChangeRequest originalRequest)140 private IProfileChangeRequest computeEffectiveChangeRequest(IProvisioningPlan intermediaryPlan, IProfileChangeRequest loosenedRequest, IProfileChangeRequest originalRequest) { 141 IProfileChangeRequest finalChangeRequest = planner.createChangeRequest(profile); 142 // We have the following two variables because a IPCRequest can not be muted 143 Set<IInstallableUnit> iusToAdd = new HashSet<>(); 144 Set<IInstallableUnit> iusToRemove = new HashSet<>(); 145 146 for (IRequirement beingInstalled : requirementsForElementsBeingInstalled) { 147 IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery(beingInstalled.getMatches()); 148 IQueryResult<IInstallableUnit> matches = intermediaryPlan.getFutureState().query(QueryUtil.createLatestQuery(query), null); 149 IInstallableUnit replacementIU = null; 150 if (!matches.isEmpty()) { 151 replacementIU = matches.iterator().next(); 152 iusToAdd.add(replacementIU); 153 adaptIUPropertiesToNewIU(beingInstalled, replacementIU, finalChangeRequest); 154 } 155 } 156 157 for (IRequirement alreadyInstalled : requirementsForElementsAlreadyInstalled) { 158 IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery(alreadyInstalled.getMatches()); 159 IQueryResult<IInstallableUnit> matches = intermediaryPlan.getFutureState().query(QueryUtil.createLatestQuery(query), null); 160 IInstallableUnit potentialRootChange = null; 161 if (!matches.isEmpty()) 162 potentialRootChange = matches.iterator().next(); 163 164 IQueryResult<IInstallableUnit> iuAlreadyInstalled = profile.available(query, new NullProgressMonitor()); 165 166 if (!iuAlreadyInstalled.isEmpty()) {//This deals with the case where the root has not changed 167 if (potentialRootChange != null && iuAlreadyInstalled.toUnmodifiableSet().contains(potentialRootChange)) 168 continue; 169 } 170 iusToRemove.addAll(iuAlreadyInstalled.toUnmodifiableSet()); 171 if (potentialRootChange != null) { 172 if (!iusToAdd.contains(potentialRootChange)) {//So we don't add the same IU twice for addition 173 iusToAdd.add(potentialRootChange); 174 adaptIUPropertiesToNewIU(alreadyInstalled, potentialRootChange, finalChangeRequest); 175 } 176 } 177 } 178 179 iusToRemove.addAll(originalRequest.getRemovals()); 180 181 //Remove entries that are both in the additions and removals (since this is a no-op) 182 HashSet<IInstallableUnit> commons = new HashSet<>(iusToAdd); 183 if (commons.retainAll(iusToRemove)) { 184 iusToAdd.removeAll(commons); 185 iusToRemove.removeAll(commons); 186 } 187 188 //Finish construction of the IPCR 189 finalChangeRequest.addAll(iusToAdd); 190 finalChangeRequest.removeAll(iusToRemove); 191 if (originalRequest.getExtraRequirements() != null) 192 finalChangeRequest.addExtraRequirements(originalRequest.getExtraRequirements()); 193 return finalChangeRequest; 194 } 195 adaptIUPropertiesToNewIU(IRequirement beingInstalled, IInstallableUnit newIU, IProfileChangeRequest finalChangeRequest)196 private void adaptIUPropertiesToNewIU(IRequirement beingInstalled, IInstallableUnit newIU, IProfileChangeRequest finalChangeRequest) { 197 Map<String, String> associatedProperties = propertiesPerRequirement.get(beingInstalled); 198 if (associatedProperties != null) { 199 Set<Entry<String, String>> entries = associatedProperties.entrySet(); 200 for (Entry<String, String> entry : entries) { 201 finalChangeRequest.setInstallableUnitProfileProperty(newIU, entry.getKey(), entry.getValue()); 202 } 203 } 204 List<String> removedProperties = removedPropertiesPerRequirement.get(beingInstalled); 205 if (removedProperties != null) { 206 for (String toRemove : removedProperties) { 207 finalChangeRequest.removeInstallableUnitProfileProperty(newIU, toRemove); 208 } 209 } 210 } 211 212 //Create a request where the original requirements are "loosened" according to flags specified in this instance 213 //The resulting profile change request uses the requirements specified using p2QL and those appear in the extraRequirements. computeLooseRequest(IProfileChangeRequest originalRequest, IProgressMonitor monitor)214 private IProfileChangeRequest computeLooseRequest(IProfileChangeRequest originalRequest, IProgressMonitor monitor) { 215 IProfileChangeRequest loosenedRequest = planner.createChangeRequest(profile); 216 SubMonitor sub = SubMonitor.convert(monitor, 2); 217 loosenUpOriginalRequest(loosenedRequest, originalRequest, sub.newChild(1)); 218 loosenUpInstalledSoftware(loosenedRequest, originalRequest, sub.newChild(1)); 219 return loosenedRequest; 220 } 221 removalRequested(IInstallableUnit removalRequested, IProfileChangeRequest request)222 private boolean removalRequested(IInstallableUnit removalRequested, IProfileChangeRequest request) { 223 return request.getRemovals().contains(removalRequested); 224 } 225 resolve(IProfileChangeRequest temporaryRequest, IProgressMonitor monitor)226 private IProvisioningPlan resolve(IProfileChangeRequest temporaryRequest, IProgressMonitor monitor) { 227 SubMonitor subMonitor = SubMonitor.convert(monitor, 1); 228 String explainPropertyBackup = null; 229 try { 230 temporaryRequest.setProfileProperty("_internal_user_defined_", "true"); //$NON-NLS-1$//$NON-NLS-2$ 231 if (provisioningContext != null) { 232 explainPropertyBackup = provisioningContext.getProperty(EXPLANATION_ENABLEMENT); 233 provisioningContext.setProperty(EXPLANATION_ENABLEMENT, Boolean.FALSE.toString()); 234 } 235 return planner.getProvisioningPlan(temporaryRequest, provisioningContext, subMonitor.split(1)); 236 } finally { 237 if (provisioningContext != null) { 238 if (explainPropertyBackup == null) 239 provisioningContext.getProperties().remove(EXPLANATION_ENABLEMENT); 240 else 241 provisioningContext.setProperty(EXPLANATION_ENABLEMENT, explainPropertyBackup); 242 } 243 } 244 } 245 246 //Loosen the request originally emitted. 247 //For example if the user said "install A 1.0", then a new Requirement is added saying (install A 1.0 or install A 2.0), this depending on the configuration flags loosenUpOriginalRequest(IProfileChangeRequest newRequest, IProfileChangeRequest originalRequest, IProgressMonitor monitor)248 private void loosenUpOriginalRequest(IProfileChangeRequest newRequest, IProfileChangeRequest originalRequest, IProgressMonitor monitor) { 249 //First deal with the IUs that are being added 250 Collection<IInstallableUnit> requestedAdditions = originalRequest.getAdditions(); 251 SubMonitor subMonitor = SubMonitor.convert(monitor, requestedAdditions.size()); 252 for (IInstallableUnit addedIU : requestedAdditions) { 253 SubMonitor iterationMonitor = subMonitor.split(1); 254 Collection<IInstallableUnit> potentialUpdates = allowDifferentVersion ? findAllVersionsAvailable(addedIU, iterationMonitor) : new ArrayList<>(); 255 foundDifferentVersionsForElementsToInstall = (foundDifferentVersionsForElementsToInstall || (potentialUpdates.size() == 0 ? false : true)); 256 potentialUpdates.add(addedIU); //Make sure that we include the IU that we were initially trying to install 257 258 Collection<IRequirement> newRequirement = new ArrayList<>(1); 259 IRequirement req = createORRequirement(potentialUpdates, allowPartialInstall || isRequestedInstallationOptional(addedIU, originalRequest)); 260 newRequirement.add(req); 261 newRequest.addExtraRequirements(newRequirement); 262 requirementsForElementsBeingInstalled.addAll(newRequirement); 263 rememberIUProfileProperties(addedIU, req, originalRequest, false); 264 } 265 266 //Deal with the IUs requested for removal 267 newRequest.removeAll(originalRequest.getRemovals()); 268 269 //Deal with extra requirements that could have been specified 270 if (originalRequest.getExtraRequirements() != null) 271 newRequest.addExtraRequirements(originalRequest.getExtraRequirements()); 272 } 273 274 //This keeps track for each requirement created (those created to loosen the constraint), of the original IU and the properties associated with it in the profile 275 //This is used for more easily construct the final profile change request rememberIUProfileProperties(IInstallableUnit iu, IRequirement req, IProfileChangeRequest originalRequest, boolean includeProfile)276 private void rememberIUProfileProperties(IInstallableUnit iu, IRequirement req, IProfileChangeRequest originalRequest, boolean includeProfile) { 277 Map<String, String> allProperties = new HashMap<>(); 278 if (includeProfile) { 279 Map<String, String> tmp = new HashMap<>(profile.getInstallableUnitProperties(iu)); 280 List<String> propertiesToRemove = ((ProfileChangeRequest) originalRequest).getInstallableUnitProfilePropertiesToRemove().get(iu); 281 if (propertiesToRemove != null) { 282 for (String toRemove : propertiesToRemove) { 283 tmp.remove(toRemove); 284 } 285 } 286 allProperties.putAll(tmp); 287 } 288 289 Map<String, String> propertiesInRequest = ((ProfileChangeRequest) originalRequest).getInstallableUnitProfilePropertiesToAdd().get(iu); 290 if (propertiesInRequest != null) 291 allProperties.putAll(propertiesInRequest); 292 293 propertiesPerRequirement.put(req, allProperties); 294 295 List<String> removalInRequest = ((ProfileChangeRequest) originalRequest).getInstallableUnitProfilePropertiesToRemove().get(iu); 296 if (removalInRequest != null) 297 removedPropertiesPerRequirement.put(req, removalInRequest); 298 } 299 isRequestedInstallationOptional(IInstallableUnit iu, IProfileChangeRequest originalRequest)300 private boolean isRequestedInstallationOptional(IInstallableUnit iu, IProfileChangeRequest originalRequest) { 301 Map<String, String> match = ((ProfileChangeRequest) originalRequest).getInstallableUnitProfilePropertiesToAdd().get(iu); 302 if (match == null) 303 return false; 304 return INCLUSION_OPTIONAL.equals(match.get(INCLUSION_RULES)); 305 } 306 findAllVersionsAvailable(IInstallableUnit iu, IProgressMonitor monitor)307 private Collection<IInstallableUnit> findAllVersionsAvailable(IInstallableUnit iu, IProgressMonitor monitor) { 308 Collection<IInstallableUnit> allVersions = new HashSet<>(); 309 SubMonitor sub = SubMonitor.convert(monitor, 2); 310 allVersions.addAll(findIUsWithSameId(iu, sub.newChild(1))); 311 allVersions.addAll(findUpdates(iu, sub.newChild(1))); 312 return allVersions; 313 } 314 findIUsWithSameId(IInstallableUnit iu, IProgressMonitor monitor)315 private Collection<IInstallableUnit> findIUsWithSameId(IInstallableUnit iu, IProgressMonitor monitor) { 316 SubMonitor sub = SubMonitor.convert(monitor, 2); 317 IQueryable<IInstallableUnit> metadata = provisioningContext.getMetadata(sub.newChild(1)); 318 return metadata.query(QueryUtil.createIUQuery(iu.getId()), sub.newChild(1)).toUnmodifiableSet(); 319 } 320 findUpdates(IInstallableUnit iu, IProgressMonitor monitor)321 private Collection<IInstallableUnit> findUpdates(IInstallableUnit iu, IProgressMonitor monitor) { 322 SubMonitor subMonitor = SubMonitor.convert(monitor, 1); 323 Collection<IInstallableUnit> availableUpdates = new HashSet<>(); 324 IQueryResult<IInstallableUnit> updatesAvailable = planner.updatesFor(iu, provisioningContext, subMonitor.split(1)); 325 for (IInstallableUnit unit : updatesAvailable) { 326 availableUpdates.add(unit); 327 } 328 return availableUpdates; 329 } 330 331 //Create an OR expression that is matching all the entries from the given collection createORRequirement(Collection<IInstallableUnit> findUpdates, boolean optional)332 private IRequirement createORRequirement(Collection<IInstallableUnit> findUpdates, boolean optional) { 333 StringBuilder expression = new StringBuilder(); 334 Object[] expressionParameters = new Object[findUpdates.size() * 2]; 335 int count = 0; 336 for (IInstallableUnit iu : findUpdates) { 337 expression.append("(id == $").append(count * 2).append(" && version == $").append(count * 2 + 1).append(')'); //$NON-NLS-1$//$NON-NLS-2$ 338 if (findUpdates.size() > 1 && count < findUpdates.size() - 1) 339 expression.append(" || "); //$NON-NLS-1$ 340 expressionParameters[count * 2] = iu.getId(); 341 expressionParameters[count * 2 + 1] = iu.getVersion(); 342 count++; 343 } 344 IMatchExpression<IInstallableUnit> iuMatcher = ExpressionUtil.getFactory().matchExpression(ExpressionUtil.parse(expression.toString()), expressionParameters); 345 return MetadataFactory.createRequirement(iuMatcher, null, optional ? 0 : 1, 1, true); 346 } 347 348 //Loosen up the IUs that are already part of the profile 349 //Given how we are creating our request, this needs to take into account the removal from the original request as well as the change in inclusion loosenUpInstalledSoftware(IProfileChangeRequest request, IProfileChangeRequest originalRequest, IProgressMonitor monitor)350 private IProfileChangeRequest loosenUpInstalledSoftware(IProfileChangeRequest request, IProfileChangeRequest originalRequest, IProgressMonitor monitor) { 351 if (!allowInstalledRemoval && !allowInstalledUpdate) 352 return request; 353 Set<IInstallableUnit> allRoots = getRoots(); 354 355 for (IInstallableUnit existingIU : allRoots) { 356 Collection<IInstallableUnit> potentialUpdates = allowInstalledUpdate ? findUpdates(existingIU, monitor) : new HashSet<>(); 357 foundDifferentVersionsForElementsInstalled = (foundDifferentVersionsForElementsInstalled || (potentialUpdates.size() == 0 ? false : true)); 358 potentialUpdates.add(existingIU); 359 Collection<IRequirement> newRequirement = new ArrayList<>(1); 360 //when the element is requested for removal or is installed optionally we make sure to mark it optional, otherwise the removal woudl fail 361 IRequirement req = createORRequirement(potentialUpdates, allowInstalledRemoval || removalRequested(existingIU, originalRequest) || isOptionallyInstalled(existingIU, originalRequest)); 362 newRequirement.add(req); 363 request.addExtraRequirements(newRequirement); 364 requirementsForElementsAlreadyInstalled.addAll(newRequirement); 365 request.remove(existingIU); 366 rememberIUProfileProperties(existingIU, req, originalRequest, true); 367 } 368 369 return request; 370 } 371 getRoots()372 private Set<IInstallableUnit> getRoots() { 373 Set<IInstallableUnit> allRoots = profile.query(new IUProfilePropertyQuery(INCLUSION_RULES, IUProfilePropertyQuery.ANY), null).toSet(); 374 if (!honorSharedSettings) 375 return allRoots; 376 IQueryResult<IInstallableUnit> baseRoots = profile.query(new IUProfilePropertyQuery("org.eclipse.equinox.p2.base", Boolean.TRUE.toString()), null); 377 allRoots.removeAll(baseRoots.toUnmodifiableSet()); 378 return allRoots; 379 } 380 381 //This return whether or not the given IU is installed optionally or not. 382 //This also take into account the future state isOptionallyInstalled(IInstallableUnit existingIU, IProfileChangeRequest request)383 private boolean isOptionallyInstalled(IInstallableUnit existingIU, IProfileChangeRequest request) { 384 return computeFutureStateOfInclusion((ProfileChangeRequest) request).contains(existingIU); 385 } 386 387 //Given the change request, this returns the collection of optional IUs computeFutureStateOfInclusion(ProfileChangeRequest profileChangeRequest)388 private Set<IInstallableUnit> computeFutureStateOfInclusion(ProfileChangeRequest profileChangeRequest) { 389 if (futureOptionalIUs != null) 390 return futureOptionalIUs; 391 392 futureOptionalIUs = profileChangeRequest.getProfile().query(new IUProfilePropertyQuery(INCLUSION_RULES, INCLUSION_OPTIONAL), null).toSet(); 393 394 Set<Entry<IInstallableUnit, List<String>>> propertiesBeingRemoved = profileChangeRequest.getInstallableUnitProfilePropertiesToRemove().entrySet(); 395 for (Entry<IInstallableUnit, List<String>> propertyRemoved : propertiesBeingRemoved) { 396 if (propertyRemoved.getValue().contains(INCLUSION_RULES)) { 397 futureOptionalIUs.remove(propertyRemoved.getKey()); 398 } 399 } 400 401 Set<Entry<IInstallableUnit, Map<String, String>>> propertiesBeingAdded = profileChangeRequest.getInstallableUnitProfilePropertiesToAdd().entrySet(); 402 for (Entry<IInstallableUnit, Map<String, String>> propertyBeingAdded : propertiesBeingAdded) { 403 String inclusionRule = propertyBeingAdded.getValue().get(INCLUSION_RULES); 404 if (inclusionRule == null) { 405 continue; 406 } 407 if (INCLUSION_STRICT.equals(inclusionRule)) { 408 futureOptionalIUs.remove(propertyBeingAdded.getKey()); 409 } 410 if (INCLUSION_OPTIONAL.equals(inclusionRule)) { 411 futureOptionalIUs.add(propertyBeingAdded.getKey()); 412 } 413 } 414 return futureOptionalIUs; 415 } 416 productContainmentOK(IProvisioningPlan intermediaryPlan)417 private boolean productContainmentOK(IProvisioningPlan intermediaryPlan) { 418 if (!ensureProductPresence) 419 return true; 420 if (!hasProduct()) 421 return true; 422 //At this point we know we had a product installed and we want to make sure there is one in the resulting solution 423 if (!intermediaryPlan.getFutureState().query(QueryUtil.createIUProductQuery(), new NullProgressMonitor()).isEmpty()) 424 return true; 425 //Support for legacy identification of product using the lineUp. 426 if (!intermediaryPlan.getFutureState().query(QueryUtil.createIUPropertyQuery("lineUp", "true"), new NullProgressMonitor()).isEmpty()) //$NON-NLS-1$//$NON-NLS-2$ 427 return true; 428 return false; 429 } 430 hasProduct()431 private boolean hasProduct() { 432 if (!profile.available(QueryUtil.createIUProductQuery(), new NullProgressMonitor()).isEmpty()) { 433 return true; 434 } 435 //Support for legacy identification of product using the lineUp. 436 if (!profile.available(QueryUtil.createIUPropertyQuery("lineUp", "true"), new NullProgressMonitor()).isEmpty()) //$NON-NLS-1$//$NON-NLS-2$ 437 return true; 438 return false; 439 } 440 441 } 442