PageRenderTime 31ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/eclipse_SDK-3.7.1/plugins/org.eclipse.equinox.p2.director.source_2.1.0.v20110504-1715/org/eclipse/equinox/internal/p2/director/Projector.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1209 lines | 1025 code | 97 blank | 87 comment | 278 complexity | 98a32a500a1aa45dfa251e358195bc92 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2007, 2011 IBM Corporation and others. All rights reserved. This
  3. * program and the accompanying materials are made available under the terms of
  4. * the Eclipse Public License v1.0 which accompanies this distribution, and is
  5. * available at http://www.eclipse.org/legal/epl-v10.html
  6. *
  7. * Contributors:
  8. * IBM Corporation - initial API and implementation
  9. * Daniel Le Berre - Fix in the encoding and the optimization function
  10. * Alban Browaeys - Optimized string concatenation in bug 251357
  11. * Jed Anderson - switch from opb files to API calls to DependencyHelper in bug 200380
  12. * Sonatype, Inc. - ongoing development
  13. ******************************************************************************/
  14. package org.eclipse.equinox.internal.p2.director;
  15. import java.math.BigInteger;
  16. import java.util.*;
  17. import java.util.Map.Entry;
  18. import org.eclipse.core.runtime.*;
  19. import org.eclipse.core.runtime.jobs.Job;
  20. import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils;
  21. import org.eclipse.equinox.internal.p2.core.helpers.Tracing;
  22. import org.eclipse.equinox.internal.p2.director.Explanation.NotInstallableRoot;
  23. import org.eclipse.equinox.internal.p2.metadata.IRequiredCapability;
  24. import org.eclipse.equinox.internal.p2.metadata.InstallableUnit;
  25. import org.eclipse.equinox.p2.metadata.*;
  26. import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
  27. import org.eclipse.equinox.p2.query.*;
  28. import org.eclipse.osgi.util.NLS;
  29. import org.sat4j.pb.*;
  30. import org.sat4j.pb.tools.DependencyHelper;
  31. import org.sat4j.pb.tools.WeightedObject;
  32. import org.sat4j.specs.*;
  33. /**
  34. * This class is the interface between SAT4J and the planner. It produces a
  35. * boolean satisfiability problem, invokes the solver, and converts the solver result
  36. * back into information understandable by the planner.
  37. */
  38. public class Projector {
  39. static boolean DEBUG = Tracing.DEBUG_PLANNER_PROJECTOR;
  40. private static boolean DEBUG_ENCODING = false;
  41. private IQueryable<IInstallableUnit> picker;
  42. private QueryableArray patches;
  43. private Map<IInstallableUnit, AbstractVariable> noopVariables; //key IU, value AbstractVariable
  44. private List<AbstractVariable> abstractVariables;
  45. private Map<String, Map<Version, IInstallableUnit>> slice; //The IUs that have been considered to be part of the problem
  46. private IInstallableUnit selectionContext;
  47. DependencyHelper<Object, Explanation> dependencyHelper;
  48. private Collection<IInstallableUnit> solution;
  49. private Collection<Object> assumptions;
  50. private MultiStatus result;
  51. private Collection<IInstallableUnit> alreadyInstalledIUs;
  52. private IQueryable<IInstallableUnit> lastState;
  53. private boolean considerMetaRequirements;
  54. private IInstallableUnit entryPoint;
  55. private Map<IInstallableUnitFragment, Set<IInstallableUnit>> fragments = new HashMap<IInstallableUnitFragment, Set<IInstallableUnit>>();
  56. private int numberOfInstalledIUs;
  57. //Non greedy things
  58. private Set<IInstallableUnit> nonGreedyIUs; //All the IUs that would satisfy non greedy dependencies
  59. private Map<IInstallableUnit, AbstractVariable> nonGreedyVariables = new HashMap<IInstallableUnit, AbstractVariable>();
  60. private Map<AbstractVariable, List<Object>> nonGreedyProvider = new HashMap<AbstractVariable, List<Object>>(); //Keeps track of all the "object" that provide an IU that is non greedly requested
  61. static class AbstractVariable {
  62. // private String name;
  63. public AbstractVariable(String name) {
  64. // this.name = name;
  65. }
  66. public AbstractVariable() {
  67. // TODO Auto-generated constructor stub
  68. }
  69. public String toString() {
  70. return "AbstractVariable: " + hashCode(); //$NON-NLS-1$
  71. // return name == null ? "AbstractVariable: " + hashCode() : name; //$NON-NLS-1$
  72. }
  73. }
  74. /**
  75. * Job for computing SAT failure explanation in the background.
  76. */
  77. class ExplanationJob extends Job {
  78. private Set<Explanation> explanation;
  79. public ExplanationJob() {
  80. super(Messages.Planner_NoSolution);
  81. //explanations cannot be canceled directly, so don't show it to the user
  82. setSystem(true);
  83. }
  84. public boolean belongsTo(Object family) {
  85. return family == ExplanationJob.this;
  86. }
  87. protected void canceling() {
  88. super.canceling();
  89. dependencyHelper.stopExplanation();
  90. }
  91. public Set<Explanation> getExplanationResult() {
  92. return explanation;
  93. }
  94. protected IStatus run(IProgressMonitor monitor) {
  95. long start = 0;
  96. if (DEBUG) {
  97. start = System.currentTimeMillis();
  98. Tracing.debug("Determining cause of failure: " + start); //$NON-NLS-1$
  99. }
  100. try {
  101. explanation = dependencyHelper.why();
  102. if (DEBUG) {
  103. long stop = System.currentTimeMillis();
  104. Tracing.debug("Explanation found: " + (stop - start)); //$NON-NLS-1$
  105. Tracing.debug("Explanation:"); //$NON-NLS-1$
  106. for (Explanation ex : explanation) {
  107. Tracing.debug(ex.toString());
  108. }
  109. }
  110. } catch (TimeoutException e) {
  111. if (DEBUG)
  112. Tracing.debug("Timeout while computing explanations"); //$NON-NLS-1$
  113. } finally {
  114. //must never have a null result, because caller is waiting on result to be non-null
  115. if (explanation == null)
  116. explanation = CollectionUtils.emptySet();
  117. }
  118. synchronized (this) {
  119. ExplanationJob.this.notify();
  120. }
  121. return Status.OK_STATUS;
  122. }
  123. }
  124. public Projector(IQueryable<IInstallableUnit> q, Map<String, String> context, Set<IInstallableUnit> nonGreedyIUs, boolean considerMetaRequirements) {
  125. picker = q;
  126. noopVariables = new HashMap<IInstallableUnit, AbstractVariable>();
  127. slice = new HashMap<String, Map<Version, IInstallableUnit>>();
  128. selectionContext = InstallableUnit.contextIU(context);
  129. abstractVariables = new ArrayList<AbstractVariable>();
  130. result = new MultiStatus(DirectorActivator.PI_DIRECTOR, IStatus.OK, Messages.Planner_Problems_resolving_plan, null);
  131. assumptions = new ArrayList<Object>();
  132. this.nonGreedyIUs = nonGreedyIUs;
  133. this.considerMetaRequirements = considerMetaRequirements;
  134. }
  135. protected boolean isInstalled(IInstallableUnit iu) {
  136. return !lastState.query(QueryUtil.createIUQuery(iu), null).isEmpty();
  137. }
  138. @SuppressWarnings("unchecked")
  139. public void encode(IInstallableUnit entryPointIU, IInstallableUnit[] alreadyExistingRoots, IQueryable<IInstallableUnit> installedIUs, Collection<IInstallableUnit> newRoots, IProgressMonitor monitor) {
  140. alreadyInstalledIUs = Arrays.asList(alreadyExistingRoots);
  141. numberOfInstalledIUs = sizeOf(installedIUs);
  142. lastState = installedIUs;
  143. this.entryPoint = entryPointIU;
  144. try {
  145. long start = 0;
  146. if (DEBUG) {
  147. start = System.currentTimeMillis();
  148. Tracing.debug("Start projection: " + start); //$NON-NLS-1$
  149. }
  150. IPBSolver solver;
  151. if (DEBUG_ENCODING) {
  152. solver = new UserFriendlyPBStringSolver<Object>();
  153. } else {
  154. solver = SolverFactory.newEclipseP2();
  155. }
  156. int timeout = 1000;
  157. String timeoutString = null;
  158. try {
  159. // allow the user to specify a longer timeout.
  160. // only set the value if it is a positive integer larger than the default.
  161. // see https://bugs.eclipse.org/336967
  162. timeoutString = DirectorActivator.context.getProperty("eclipse.p2.projector.timeout"); //$NON-NLS-1$
  163. if (timeoutString != null)
  164. timeout = Math.max(timeout, Integer.parseInt(timeoutString));
  165. } catch (Exception e) {
  166. // intentionally catch all errors (npe, number format, etc)
  167. // print out to syserr and fall through
  168. System.err.println("Ignoring user-specified 'eclipse.p2.projector.timeout' value of: " + timeoutString); //$NON-NLS-1$
  169. e.printStackTrace();
  170. }
  171. solver.setTimeoutOnConflicts(timeout);
  172. IQueryResult<IInstallableUnit> queryResult = picker.query(QueryUtil.createIUAnyQuery(), null);
  173. if (DEBUG_ENCODING) {
  174. dependencyHelper = new DependencyHelper<Object, Explanation>(solver, false);
  175. ((UserFriendlyPBStringSolver<Object>) solver).setMapping(dependencyHelper.getMappingToDomain());
  176. } else {
  177. dependencyHelper = new DependencyHelper<Object, Explanation>(solver);
  178. }
  179. Iterator<IInstallableUnit> iusToEncode = queryResult.iterator();
  180. List<IInstallableUnit> iusToOrder = new ArrayList<IInstallableUnit>();
  181. while (iusToEncode.hasNext()) {
  182. iusToOrder.add(iusToEncode.next());
  183. }
  184. Collections.sort(iusToOrder);
  185. iusToEncode = iusToOrder.iterator();
  186. while (iusToEncode.hasNext()) {
  187. if (monitor.isCanceled()) {
  188. result.merge(Status.CANCEL_STATUS);
  189. throw new OperationCanceledException();
  190. }
  191. IInstallableUnit iuToEncode = iusToEncode.next();
  192. if (iuToEncode != entryPointIU) {
  193. processIU(iuToEncode, false);
  194. }
  195. }
  196. createMustHave(entryPointIU, alreadyExistingRoots);
  197. createConstraintsForSingleton();
  198. createConstraintsForNonGreedy();
  199. createOptimizationFunction(entryPointIU, newRoots);
  200. if (DEBUG) {
  201. long stop = System.currentTimeMillis();
  202. Tracing.debug("Projection complete: " + (stop - start)); //$NON-NLS-1$
  203. }
  204. if (DEBUG_ENCODING) {
  205. System.out.println(solver.toString());
  206. }
  207. } catch (IllegalStateException e) {
  208. result.add(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, e.getMessage(), e));
  209. } catch (ContradictionException e) {
  210. result.add(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, Messages.Planner_Unsatisfiable_problem));
  211. }
  212. }
  213. private void createConstraintsForNonGreedy() throws ContradictionException {
  214. for (IInstallableUnit iu : nonGreedyIUs) {
  215. AbstractVariable var = getNonGreedyVariable(iu);
  216. List<Object> providers = nonGreedyProvider.get(var);
  217. if (providers == null || providers.size() == 0) {
  218. dependencyHelper.setFalse(var, new Explanation.MissingGreedyIU(iu));
  219. } else {
  220. createImplication(var, providers, Explanation.OPTIONAL_REQUIREMENT);//FIXME
  221. }
  222. }
  223. }
  224. /**
  225. * Efficiently compute the size of a queryable
  226. */
  227. private int sizeOf(IQueryable<IInstallableUnit> installedIUs) {
  228. IQueryResult<IInstallableUnit> qr = installedIUs.query(QueryUtil.createIUAnyQuery(), null);
  229. if (qr instanceof Collector<?>)
  230. return ((Collector<?>) qr).size();
  231. return qr.toUnmodifiableSet().size();
  232. }
  233. //Create an optimization function favoring the highest version of each IU
  234. private void createOptimizationFunction(IInstallableUnit metaIu, Collection<IInstallableUnit> newRoots) {
  235. List<WeightedObject<? extends Object>> weightedObjects = new ArrayList<WeightedObject<? extends Object>>();
  236. Set<IInstallableUnit> transitiveClosure;
  237. if (newRoots.isEmpty()) {
  238. transitiveClosure = CollectionUtils.emptySet();
  239. } else {
  240. IQueryable<IInstallableUnit> queryable = new Slicer(picker, selectionContext, false).slice(newRoots.toArray(new IInstallableUnit[newRoots.size()]), new NullProgressMonitor());
  241. if (queryable == null) {
  242. transitiveClosure = CollectionUtils.emptySet();
  243. } else {
  244. transitiveClosure = queryable.query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).toSet();
  245. }
  246. }
  247. Set<Entry<String, Map<Version, IInstallableUnit>>> s = slice.entrySet();
  248. final BigInteger POWER = BigInteger.valueOf(numberOfInstalledIUs > 0 ? numberOfInstalledIUs + 1 : 2);
  249. BigInteger maxWeight = POWER;
  250. for (Entry<String, Map<Version, IInstallableUnit>> entry : s) {
  251. List<IInstallableUnit> conflictingEntries = new ArrayList<IInstallableUnit>(entry.getValue().values());
  252. if (conflictingEntries.size() == 1) {
  253. IInstallableUnit iu = conflictingEntries.get(0);
  254. if (iu != metaIu) {
  255. weightedObjects.add(WeightedObject.newWO(iu, POWER));
  256. }
  257. continue;
  258. }
  259. Collections.sort(conflictingEntries, Collections.reverseOrder());
  260. BigInteger weight = POWER;
  261. boolean installedIuMet = false;
  262. boolean rootedMet = false;
  263. for (IInstallableUnit iu : conflictingEntries) {
  264. if (!rootedMet && isInstalled(iu) && !transitiveClosure.contains(iu)) {
  265. installedIuMet = true;
  266. weightedObjects.add(WeightedObject.newWO(iu, BigInteger.ONE));
  267. } else if (!installedIuMet && !rootedMet && isRoot(iu, newRoots)) {
  268. rootedMet = true;
  269. weightedObjects.add(WeightedObject.newWO(iu, BigInteger.ONE));
  270. } else {
  271. weightedObjects.add(WeightedObject.newWO(iu, weight));
  272. }
  273. weight = weight.multiply(POWER);
  274. }
  275. if (weight.compareTo(maxWeight) > 0)
  276. maxWeight = weight;
  277. }
  278. // no need to add one here, since maxWeight is strictly greater than the
  279. // maximal weight used so far.
  280. maxWeight = maxWeight.multiply(POWER).multiply(BigInteger.valueOf(s.size()));
  281. // Add the abstract variables
  282. BigInteger abstractWeight = maxWeight.negate();
  283. for (AbstractVariable var : abstractVariables) {
  284. weightedObjects.add(WeightedObject.newWO(var, abstractWeight));
  285. }
  286. maxWeight = maxWeight.multiply(POWER).add(BigInteger.ONE);
  287. BigInteger optionalWeight = maxWeight.negate();
  288. long countOptional = 1;
  289. List<IInstallableUnit> requestedPatches = new ArrayList<IInstallableUnit>();
  290. Collection<IRequirement> reqs = metaIu.getRequirements();
  291. for (IRequirement req : reqs) {
  292. if (req.getMin() > 0 || !req.isGreedy())
  293. continue;
  294. IQueryResult<IInstallableUnit> matches = picker.query(QueryUtil.createMatchQuery(req.getMatches()), null);
  295. for (Iterator<IInstallableUnit> iterator = matches.iterator(); iterator.hasNext();) {
  296. IInstallableUnit match = iterator.next();
  297. if (match instanceof IInstallableUnitPatch) {
  298. requestedPatches.add(match);
  299. countOptional = countOptional + 1;
  300. } else {
  301. weightedObjects.add(WeightedObject.newWO(match, optionalWeight));
  302. }
  303. }
  304. }
  305. BigInteger patchWeight = maxWeight.multiply(POWER).multiply(BigInteger.valueOf(countOptional)).negate();
  306. for (Iterator<IInstallableUnit> iterator = requestedPatches.iterator(); iterator.hasNext();) {
  307. weightedObjects.add(WeightedObject.newWO(iterator.next(), patchWeight));
  308. }
  309. if (!weightedObjects.isEmpty()) {
  310. createObjectiveFunction(weightedObjects);
  311. }
  312. }
  313. private boolean isRoot(IInstallableUnit iu, Collection<IInstallableUnit> newRoots) {
  314. return newRoots.contains(iu);
  315. }
  316. private void createObjectiveFunction(List<WeightedObject<? extends Object>> weightedObjects) {
  317. if (DEBUG) {
  318. StringBuffer b = new StringBuffer();
  319. for (WeightedObject<? extends Object> object : weightedObjects) {
  320. if (b.length() > 0)
  321. b.append(", "); //$NON-NLS-1$
  322. b.append(object.getWeight());
  323. b.append(' ');
  324. b.append(object.thing);
  325. }
  326. Tracing.debug("objective function: " + b); //$NON-NLS-1$
  327. }
  328. @SuppressWarnings("unchecked")
  329. WeightedObject<Object>[] array = (WeightedObject<Object>[]) weightedObjects.toArray(new WeightedObject<?>[weightedObjects.size()]);
  330. dependencyHelper.setObjectiveFunction(array);
  331. }
  332. private void createMustHave(IInstallableUnit iu, IInstallableUnit[] alreadyExistingRoots) throws ContradictionException {
  333. processIU(iu, true);
  334. if (DEBUG) {
  335. Tracing.debug(iu + "=1"); //$NON-NLS-1$
  336. }
  337. // dependencyHelper.setTrue(variable, new Explanation.IUToInstall(iu));
  338. assumptions.add(iu);
  339. }
  340. private void createNegation(IInstallableUnit iu, IRequirement req) throws ContradictionException {
  341. if (DEBUG) {
  342. Tracing.debug(iu + "=0"); //$NON-NLS-1$
  343. }
  344. dependencyHelper.setFalse(iu, new Explanation.MissingIU(iu, req, iu == this.entryPoint));
  345. }
  346. // Check whether the requirement is applicable
  347. private boolean isApplicable(IRequirement req) {
  348. IMatchExpression<IInstallableUnit> filter = req.getFilter();
  349. return filter == null || filter.isMatch(selectionContext);
  350. }
  351. private boolean isApplicable(IInstallableUnit iu) {
  352. IMatchExpression<IInstallableUnit> filter = iu.getFilter();
  353. return filter == null || filter.isMatch(selectionContext);
  354. }
  355. private void expandNegatedRequirement(IRequirement req, IInstallableUnit iu, List<AbstractVariable> optionalAbstractRequirements, boolean isRootIu) throws ContradictionException {
  356. if (!isApplicable(req))
  357. return;
  358. List<IInstallableUnit> matches = getApplicableMatches(req);
  359. if (matches.isEmpty()) {
  360. return;
  361. }
  362. Explanation explanation;
  363. if (isRootIu) {
  364. IInstallableUnit reqIu = matches.get(0);
  365. if (alreadyInstalledIUs.contains(reqIu)) {
  366. explanation = new Explanation.IUInstalled(reqIu);
  367. } else {
  368. explanation = new Explanation.IUToInstall(reqIu);
  369. }
  370. } else {
  371. explanation = new Explanation.HardRequirement(iu, req);
  372. }
  373. createNegationImplication(iu, matches, explanation);
  374. }
  375. private void determinePotentialHostsForFragment(IInstallableUnit iu) {
  376. // determine matching hosts only for fragments
  377. if (!(iu instanceof IInstallableUnitFragment))
  378. return;
  379. IInstallableUnitFragment fragment = (IInstallableUnitFragment) iu;
  380. // for each host requirement, find matches and remember them
  381. for (IRequirement req : fragment.getHost()) {
  382. List<IInstallableUnit> matches = getApplicableMatches(req);
  383. rememberHostMatches((IInstallableUnitFragment) iu, matches);
  384. }
  385. }
  386. private void expandRequirement(IRequirement req, IInstallableUnit iu, List<AbstractVariable> optionalAbstractRequirements, boolean isRootIu) throws ContradictionException {
  387. if (req.getMax() == 0) {
  388. expandNegatedRequirement(req, iu, optionalAbstractRequirements, isRootIu);
  389. return;
  390. }
  391. if (!isApplicable(req))
  392. return;
  393. List<IInstallableUnit> matches = getApplicableMatches(req);
  394. determinePotentialHostsForFragment(iu);
  395. if (req.getMin() > 0) {
  396. if (matches.isEmpty()) {
  397. if (iu == entryPoint && emptyBecauseFiltered) {
  398. dependencyHelper.setFalse(iu, new NotInstallableRoot(req));
  399. } else {
  400. missingRequirement(iu, req);
  401. }
  402. } else {
  403. if (req.isGreedy()) {
  404. IInstallableUnit reqIu = matches.get(0);
  405. Explanation explanation;
  406. if (isRootIu) {
  407. if (alreadyInstalledIUs.contains(reqIu)) {
  408. explanation = new Explanation.IUInstalled(reqIu);
  409. } else {
  410. explanation = new Explanation.IUToInstall(reqIu);
  411. }
  412. } else {
  413. explanation = new Explanation.HardRequirement(iu, req);
  414. }
  415. createImplication(iu, matches, explanation);
  416. IInstallableUnit current;
  417. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  418. current = it.next();
  419. if (nonGreedyIUs.contains(current)) {
  420. addNonGreedyProvider(getNonGreedyVariable(current), iu);
  421. }
  422. }
  423. } else {
  424. List<Object> newConstraint = new ArrayList<Object>(matches.size());
  425. IInstallableUnit current;
  426. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  427. current = it.next();
  428. newConstraint.add(getNonGreedyVariable(current));
  429. }
  430. createImplication(new Object[] {iu}, newConstraint, new Explanation.HardRequirement(iu, req)); // FIXME
  431. }
  432. }
  433. } else {
  434. if (!matches.isEmpty()) {
  435. IInstallableUnit current;
  436. AbstractVariable abs;
  437. if (req.isGreedy()) {
  438. abs = getAbstractVariable(req);
  439. createImplication(new Object[] {abs, iu}, matches, Explanation.OPTIONAL_REQUIREMENT);
  440. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  441. current = it.next();
  442. if (nonGreedyIUs.contains(current)) {
  443. addNonGreedyProvider(getNonGreedyVariable(current), abs);
  444. }
  445. }
  446. } else {
  447. abs = getAbstractVariable(req, false);
  448. List<Object> newConstraint = new ArrayList<Object>();
  449. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  450. current = it.next();
  451. newConstraint.add(getNonGreedyVariable(current));
  452. }
  453. createImplication(new Object[] {abs, iu}, newConstraint, Explanation.OPTIONAL_REQUIREMENT);
  454. }
  455. optionalAbstractRequirements.add(abs);
  456. }
  457. }
  458. }
  459. private void addNonGreedyProvider(AbstractVariable nonGreedyVariable, Object o) {
  460. List<Object> providers = nonGreedyProvider.get(nonGreedyVariable);
  461. if (providers == null) {
  462. providers = new ArrayList<Object>();
  463. nonGreedyProvider.put(nonGreedyVariable, providers);
  464. }
  465. providers.add(o);
  466. }
  467. private void expandRequirements(Collection<IRequirement> reqs, IInstallableUnit iu, boolean isRootIu) throws ContradictionException {
  468. if (reqs.isEmpty())
  469. return;
  470. List<AbstractVariable> optionalAbstractRequirements = new ArrayList<AbstractVariable>();
  471. for (IRequirement req : reqs) {
  472. expandRequirement(req, iu, optionalAbstractRequirements, isRootIu);
  473. }
  474. createOptionalityExpression(iu, optionalAbstractRequirements);
  475. }
  476. public void processIU(IInstallableUnit iu, boolean isRootIU) throws ContradictionException {
  477. iu = iu.unresolved();
  478. Map<Version, IInstallableUnit> iuSlice = slice.get(iu.getId());
  479. if (iuSlice == null) {
  480. iuSlice = new HashMap<Version, IInstallableUnit>();
  481. slice.put(iu.getId(), iuSlice);
  482. }
  483. iuSlice.put(iu.getVersion(), iu);
  484. if (!isApplicable(iu)) {
  485. createNegation(iu, null);
  486. return;
  487. }
  488. IQueryResult<IInstallableUnit> applicablePatches = getApplicablePatches(iu);
  489. expandLifeCycle(iu, isRootIU);
  490. //No patches apply, normal code path
  491. if (applicablePatches.isEmpty()) {
  492. expandRequirements(getRequiredCapabilities(iu), iu, isRootIU);
  493. } else {
  494. //Patches are applicable to the IU
  495. expandRequirementsWithPatches(iu, applicablePatches, isRootIU);
  496. }
  497. }
  498. private Collection<IRequirement> getRequiredCapabilities(IInstallableUnit iu) {
  499. boolean isFragment = iu instanceof IInstallableUnitFragment;
  500. //Short-circuit for the case of an IInstallableUnit
  501. if ((!isFragment) && iu.getMetaRequirements().size() == 0)
  502. return iu.getRequirements();
  503. ArrayList<IRequirement> aggregatedRequirements = new ArrayList<IRequirement>(iu.getRequirements().size() + iu.getMetaRequirements().size() + (isFragment ? ((IInstallableUnitFragment) iu).getHost().size() : 0));
  504. aggregatedRequirements.addAll(iu.getRequirements());
  505. if (iu instanceof IInstallableUnitFragment) {
  506. aggregatedRequirements.addAll(((IInstallableUnitFragment) iu).getHost());
  507. }
  508. if (considerMetaRequirements)
  509. aggregatedRequirements.addAll(iu.getMetaRequirements());
  510. return aggregatedRequirements;
  511. }
  512. static final class Pending {
  513. List<? super IInstallableUnitPatch> matches;
  514. Explanation explanation;
  515. Object left;
  516. }
  517. private void expandRequirementsWithPatches(IInstallableUnit iu, IQueryResult<IInstallableUnit> applicablePatches, boolean isRootIu) throws ContradictionException {
  518. //Unmodified dependencies
  519. Collection<IRequirement> iuRequirements = getRequiredCapabilities(iu);
  520. Map<IRequirement, List<IInstallableUnitPatch>> unchangedRequirements = new HashMap<IRequirement, List<IInstallableUnitPatch>>(iuRequirements.size());
  521. Map<IRequirement, Pending> nonPatchedRequirements = new HashMap<IRequirement, Pending>(iuRequirements.size());
  522. for (Iterator<IInstallableUnit> iterator = applicablePatches.iterator(); iterator.hasNext();) {
  523. IInstallableUnitPatch patch = (IInstallableUnitPatch) iterator.next();
  524. IRequirement[][] reqs = mergeRequirements(iu, patch);
  525. if (reqs.length == 0)
  526. return;
  527. // Optional requirements are encoded via:
  528. // ABS -> (match1(req) or match2(req) or ... or matchN(req))
  529. // noop(IU)-> ~ABS
  530. // IU -> (noop(IU) or ABS)
  531. // Therefore we only need one optional requirement statement per IU
  532. List<AbstractVariable> optionalAbstractRequirements = new ArrayList<AbstractVariable>();
  533. for (int i = 0; i < reqs.length; i++) {
  534. //The requirement is unchanged
  535. if (reqs[i][0] == reqs[i][1]) {
  536. if (reqs[i][0].getMax() == 0) {
  537. expandNegatedRequirement(reqs[i][0], iu, optionalAbstractRequirements, isRootIu);
  538. return;
  539. }
  540. if (!isApplicable(reqs[i][0]))
  541. continue;
  542. List<IInstallableUnitPatch> patchesAppliedElseWhere = unchangedRequirements.get(reqs[i][0]);
  543. if (patchesAppliedElseWhere == null) {
  544. patchesAppliedElseWhere = new ArrayList<IInstallableUnitPatch>();
  545. unchangedRequirements.put(reqs[i][0], patchesAppliedElseWhere);
  546. }
  547. patchesAppliedElseWhere.add(patch);
  548. continue;
  549. }
  550. //Generate dependency when the patch is applied
  551. //P1 -> (A -> D) equiv. (P1 & A) -> D
  552. if (isApplicable(reqs[i][1])) {
  553. IRequirement req = reqs[i][1];
  554. List<IInstallableUnit> matches = getApplicableMatches(req);
  555. determinePotentialHostsForFragment(iu);
  556. if (req.getMin() > 0) {
  557. if (matches.isEmpty()) {
  558. missingRequirement(patch, req);
  559. } else {
  560. IInstallableUnit current;
  561. if (req.isGreedy()) {
  562. IInstallableUnit reqIu = matches.get(0);
  563. Explanation explanation;
  564. if (isRootIu) {
  565. if (alreadyInstalledIUs.contains(reqIu)) {
  566. explanation = new Explanation.IUInstalled(reqIu);
  567. } else {
  568. explanation = new Explanation.IUToInstall(reqIu);
  569. }
  570. } else {
  571. explanation = new Explanation.PatchedHardRequirement(iu, req, patch);
  572. }
  573. createImplication(new Object[] {patch, iu}, matches, explanation);
  574. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  575. current = it.next();
  576. if (nonGreedyIUs.contains(current)) {
  577. addNonGreedyProvider(getNonGreedyVariable(current), iu);
  578. }
  579. }
  580. } else {
  581. List<Object> newConstraint = new ArrayList<Object>();
  582. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  583. current = it.next();
  584. newConstraint.add(getNonGreedyVariable(current));
  585. }
  586. createImplication(new Object[] {iu}, newConstraint, new Explanation.HardRequirement(iu, req)); // FIXME
  587. }
  588. }
  589. } else {
  590. if (!matches.isEmpty()) {
  591. IInstallableUnit current;
  592. AbstractVariable abs;
  593. if (req.isGreedy()) {
  594. abs = getAbstractVariable(req);
  595. createImplication(new Object[] {patch, abs, iu}, matches, Explanation.OPTIONAL_REQUIREMENT);
  596. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  597. current = it.next();
  598. if (nonGreedyIUs.contains(current)) {
  599. addNonGreedyProvider(getNonGreedyVariable(current), abs);
  600. }
  601. }
  602. } else {
  603. abs = getAbstractVariable(req, false);
  604. List<Object> newConstraint = new ArrayList<Object>(matches.size());
  605. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  606. current = it.next();
  607. newConstraint.add(getNonGreedyVariable(current));
  608. }
  609. createImplication(new Object[] {patch, abs, iu}, newConstraint, Explanation.OPTIONAL_REQUIREMENT);
  610. }
  611. optionalAbstractRequirements.add(abs);
  612. }
  613. }
  614. }
  615. //Generate dependency when the patch is not applied
  616. //-P1 -> (A -> B) ( equiv. A -> (P1 or B) )
  617. if (isApplicable(reqs[i][0])) {
  618. IRequirement req = reqs[i][0];
  619. // Fix: if multiple patches apply to the same IU-req, we need to make sure we list each
  620. // patch as an optional match
  621. Pending pending = nonPatchedRequirements.get(req);
  622. if (pending != null) {
  623. pending.matches.add(patch);
  624. continue;
  625. }
  626. pending = new Pending();
  627. pending.left = iu;
  628. List<IInstallableUnit> matches = getApplicableMatches(req);
  629. determinePotentialHostsForFragment(iu);
  630. if (req.getMin() > 0) {
  631. if (matches.isEmpty()) {
  632. matches.add(patch);
  633. pending.explanation = new Explanation.HardRequirement(iu, req);
  634. pending.matches = matches;
  635. } else {
  636. // manage non greedy IUs
  637. IInstallableUnit current;
  638. List<Object> nonGreedys = new ArrayList<Object>();
  639. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  640. current = it.next();
  641. if (nonGreedyIUs.contains(current)) {
  642. nonGreedys.add(getNonGreedyVariable(current));
  643. }
  644. }
  645. matches.add(patch);
  646. if (req.isGreedy()) {
  647. IInstallableUnit reqIu = matches.get(0);///(IInstallableUnit) picker.query(new CapabilityQuery(req), new Collector(), null).iterator().next();
  648. Explanation explanation;
  649. if (isRootIu) {
  650. if (alreadyInstalledIUs.contains(reqIu)) {
  651. explanation = new Explanation.IUInstalled(reqIu);
  652. } else {
  653. explanation = new Explanation.IUToInstall(reqIu);
  654. }
  655. } else {
  656. explanation = new Explanation.HardRequirement(iu, req);
  657. }
  658. // Fix: make sure we collect all patches that will impact this IU-req, not just one
  659. pending.explanation = explanation;
  660. pending.matches = matches;
  661. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  662. current = it.next();
  663. if (nonGreedyIUs.contains(current)) {
  664. addNonGreedyProvider(getNonGreedyVariable(current), iu);
  665. }
  666. }
  667. } else {
  668. List<Object> newConstraint = new ArrayList<Object>(matches.size());
  669. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  670. current = it.next();
  671. newConstraint.add(getNonGreedyVariable(current));
  672. }
  673. pending.explanation = new Explanation.HardRequirement(iu, req);
  674. pending.matches = newConstraint;
  675. }
  676. nonPatchedRequirements.put(req, pending);
  677. }
  678. } else {
  679. if (!matches.isEmpty()) {
  680. IInstallableUnit current;
  681. AbstractVariable abs;
  682. matches.add(patch);
  683. pending = new Pending();
  684. pending.explanation = Explanation.OPTIONAL_REQUIREMENT;
  685. if (req.isGreedy()) {
  686. abs = getAbstractVariable(req);
  687. // Fix: make sure we collect all patches that will impact this IU-req, not just one
  688. pending.left = new Object[] {abs, iu};
  689. pending.matches = matches;
  690. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  691. current = it.next();
  692. if (nonGreedyIUs.contains(current)) {
  693. addNonGreedyProvider(getNonGreedyVariable(current), abs);
  694. }
  695. }
  696. } else {
  697. abs = getAbstractVariable(req, false);
  698. List<Object> newConstraint = new ArrayList<Object>(matches.size());
  699. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  700. current = it.next();
  701. newConstraint.add(getNonGreedyVariable(current));
  702. }
  703. newConstraint.add(patch);
  704. pending.left = new Object[] {abs, iu};
  705. pending.matches = newConstraint;
  706. }
  707. nonPatchedRequirements.put(req, pending);
  708. optionalAbstractRequirements.add(abs);
  709. }
  710. }
  711. }
  712. }
  713. createOptionalityExpression(iu, optionalAbstractRequirements);
  714. }
  715. // Fix: now create the pending non-patch requirements based on the full set of patches
  716. for (Pending pending : nonPatchedRequirements.values()) {
  717. createImplication(pending.left, pending.matches, pending.explanation);
  718. }
  719. List<AbstractVariable> optionalAbstractRequirements = new ArrayList<AbstractVariable>();
  720. for (Entry<IRequirement, List<IInstallableUnitPatch>> entry : unchangedRequirements.entrySet()) {
  721. List<IInstallableUnitPatch> patchesApplied = entry.getValue();
  722. Iterator<IInstallableUnit> allPatches = applicablePatches.iterator();
  723. List<IInstallableUnitPatch> requiredPatches = new ArrayList<IInstallableUnitPatch>();
  724. while (allPatches.hasNext()) {
  725. IInstallableUnitPatch patch = (IInstallableUnitPatch) allPatches.next();
  726. if (!patchesApplied.contains(patch))
  727. requiredPatches.add(patch);
  728. }
  729. IRequirement req = entry.getKey();
  730. List<IInstallableUnit> matches = getApplicableMatches(req);
  731. determinePotentialHostsForFragment(iu);
  732. if (req.getMin() > 0) {
  733. if (matches.isEmpty()) {
  734. if (requiredPatches.isEmpty()) {
  735. missingRequirement(iu, req);
  736. } else {
  737. createImplication(iu, requiredPatches, new Explanation.HardRequirement(iu, req));
  738. }
  739. } else {
  740. // manage non greedy IUs
  741. IInstallableUnit current;
  742. List<Object> nonGreedys = new ArrayList<Object>(matches.size());
  743. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  744. current = it.next();
  745. if (nonGreedyIUs.contains(current)) {
  746. nonGreedys.add(getNonGreedyVariable(current));
  747. }
  748. }
  749. if (!requiredPatches.isEmpty())
  750. matches.addAll(requiredPatches);
  751. if (req.isGreedy()) {
  752. IInstallableUnit reqIu = matches.get(0);
  753. Explanation explanation;
  754. if (isRootIu) {
  755. if (alreadyInstalledIUs.contains(reqIu)) {
  756. explanation = new Explanation.IUInstalled(reqIu);
  757. } else {
  758. explanation = new Explanation.IUToInstall(reqIu);
  759. }
  760. } else {
  761. explanation = new Explanation.HardRequirement(iu, req);
  762. }
  763. createImplication(iu, matches, explanation);
  764. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  765. current = it.next();
  766. if (nonGreedyIUs.contains(current)) {
  767. addNonGreedyProvider(getNonGreedyVariable(current), iu);
  768. }
  769. }
  770. } else {
  771. List<Object> newConstraint = new ArrayList<Object>(matches.size());
  772. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  773. current = it.next();
  774. newConstraint.add(getNonGreedyVariable(current));
  775. }
  776. createImplication(new Object[] {iu}, newConstraint, new Explanation.HardRequirement(iu, req)); // FIXME
  777. }
  778. }
  779. } else {
  780. if (!matches.isEmpty()) {
  781. IInstallableUnit current;
  782. if (!requiredPatches.isEmpty())
  783. matches.addAll(requiredPatches);
  784. AbstractVariable abs;
  785. if (req.isGreedy()) {
  786. abs = getAbstractVariable(req);
  787. createImplication(new Object[] {abs, iu}, matches, Explanation.OPTIONAL_REQUIREMENT);
  788. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  789. current = it.next();
  790. if (nonGreedyIUs.contains(current)) {
  791. addNonGreedyProvider(getNonGreedyVariable(current), iu);
  792. }
  793. }
  794. } else {
  795. abs = getAbstractVariable(req, false);
  796. List<Object> newConstraint = new ArrayList<Object>(matches.size());
  797. for (Iterator<IInstallableUnit> it = matches.iterator(); it.hasNext();) {
  798. current = it.next();
  799. newConstraint.add(getNonGreedyVariable(current));
  800. }
  801. createImplication(new Object[] {abs, iu}, newConstraint, new Explanation.HardRequirement(iu, req)); // FIXME
  802. }
  803. optionalAbstractRequirements.add(abs);
  804. }
  805. }
  806. }
  807. createOptionalityExpression(iu, optionalAbstractRequirements);
  808. }
  809. private void expandLifeCycle(IInstallableUnit iu, boolean isRootIu) throws ContradictionException {
  810. if (!(iu instanceof IInstallableUnitPatch))
  811. return;
  812. IInstallableUnitPatch patch = (IInstallableUnitPatch) iu;
  813. IRequirement req = patch.getLifeCycle();
  814. if (req == null)
  815. return;
  816. expandRequirement(req, iu, CollectionUtils.<AbstractVariable> emptyList(), isRootIu);
  817. }
  818. private void missingRequirement(IInstallableUnit iu, IRequirement req) throws ContradictionException {
  819. result.add(new Status(IStatus.WARNING, DirectorActivator.PI_DIRECTOR, NLS.bind(Messages.Planner_Unsatisfied_dependency, iu, req)));
  820. createNegation(iu, req);
  821. }
  822. private boolean emptyBecauseFiltered;
  823. /**
  824. * @param req
  825. * @return a list of mandatory requirements if any, an empty list if req.isOptional().
  826. */
  827. private List<IInstallableUnit> getApplicableMatches(IRequirement req) {
  828. List<IInstallableUnit> target = new ArrayList<IInstallableUnit>();
  829. IQueryResult<IInstallableUnit> matches = picker.query(QueryUtil.createMatchQuery(req.getMatches()), null);
  830. for (Iterator<IInstallableUnit> iterator = matches.iterator(); iterator.hasNext();) {
  831. IInstallableUnit match = iterator.next();
  832. if (isApplicable(match)) {
  833. target.add(match);
  834. }
  835. }
  836. emptyBecauseFiltered = !matches.isEmpty() && target.isEmpty();
  837. return target;
  838. }
  839. //Return a new array of requirements representing the application of the patch
  840. private IRequirement[][] mergeRequirements(IInstallableUnit iu, IInstallableUnitPatch patch) {
  841. if (patch == null)
  842. return null;
  843. List<IRequirementChange> changes = patch.getRequirementsChange();
  844. Collection<IRequirement> iuRequirements = iu.getRequirements();
  845. IRequirement[] originalRequirements = iuRequirements.toArray(new IRequirement[iuRequirements.size()]);
  846. List<IRequirement[]> rrr = new ArrayList<IRequirement[]>();
  847. boolean found = false;
  848. for (int i = 0; i < changes.size(); i++) {
  849. IRequirementChange change = changes.get(i);
  850. for (int j = 0; j < originalRequirements.length; j++) {
  851. if (originalRequirements[j] != null && change.matches((IRequiredCapability) originalRequirements[j])) {
  852. found = true;
  853. if (change.newValue() != null)
  854. rrr.add(new IRequirement[] {originalRequirements[j], change.newValue()});
  855. else
  856. // case where a requirement is removed
  857. rrr.add(new IRequirement[] {originalRequirements[j], null});
  858. originalRequirements[j] = null;
  859. }
  860. // break;
  861. }
  862. if (!found && change.applyOn() == null && change.newValue() != null) //Case where a new requirement is added
  863. rrr.add(new IRequirement[] {null, change.newValue()});
  864. }
  865. //Add all the unmodified requirements to the result
  866. for (int i = 0; i < originalRequirements.length; i++) {
  867. if (originalRequirements[i] != null)
  868. rrr.add(new IRequirement[] {originalRequirements[i], originalRequirements[i]});
  869. }
  870. return rrr.toArray(new IRequirement[rrr.size()][]);
  871. }
  872. /**
  873. * Optional requirements are encoded via:
  874. * ABS -> (match1(req) or match2(req) or ... or matchN(req))
  875. * noop(IU)-> ~ABS
  876. * IU -> (noop(IU) or ABS)
  877. * @param iu
  878. * @param optionalRequirements
  879. * @throws ContradictionException
  880. */
  881. private void createOptionalityExpression(IInstallableUnit iu, List<AbstractVariable> optionalRequirements) throws ContradictionException {
  882. if (optionalRequirements.isEmpty())
  883. return;
  884. AbstractVariable noop = getNoOperationVariable(iu);
  885. for (AbstractVariable abs : optionalRequirements) {
  886. createIncompatibleValues(abs, noop);
  887. }
  888. optionalRequirements.add(noop);
  889. createImplication(iu, optionalRequirements, Explanation.OPTIONAL_REQUIREMENT);
  890. }
  891. //This will create as many implication as there is element in the right argument
  892. private void createNegationImplication(Object left, List<?> right, Explanation name) throws ContradictionException {
  893. if (DEBUG) {
  894. Tracing.debug(name + ": " + left + "->" + right); //$NON-NLS-1$ //$NON-NLS-2$
  895. }
  896. for (Object r : right)
  897. dependencyHelper.implication(new Object[] {left}).impliesNot(r).named(name);
  898. }
  899. private void createImplication(Object left, List<?> right, Explanation name) throws ContradictionException {
  900. if (DEBUG) {
  901. Tracing.debug(name + ": " + left + "->" + right); //$NON-NLS-1$ //$NON-NLS-2$
  902. }
  903. dependencyHelper.implication(new Object[] {left}).implies(right.toArray()).named(name);
  904. }
  905. private void createImplication(Object[] left, List<?> right, Explanation name) throws ContradictionException {
  906. if (DEBUG) {
  907. Tracing.debug(name + ": " + Arrays.asList(left) + "->" + right); //$NON-NLS-1$ //$NON-NLS-2$
  908. }
  909. dependencyHelper.implication(left).implies(right.toArray()).named(name);
  910. }
  911. //Return IUPatches that are applicable for the given iu
  912. private IQueryResult<IInstallableUnit> getApplicablePatches(IInstallableUnit iu) {
  913. if (patches == null)
  914. patches = new QueryableArray(picker.query(QueryUtil.createIUPatchQuery(), null).toArray(IInstallableUnit.class));
  915. return patches.query(new ApplicablePatchQuery(iu), null);
  916. }
  917. //Create constraints to deal with singleton
  918. //When there is a mix of singleton and non singleton, several constraints are generated
  919. private void createConstraintsForSingleton() throws ContradictionException {
  920. Set<Entry<String, Map<Version, IInstallableUnit>>> s = slice.entrySet();
  921. for (Entry<String, Map<Version, IInstallableUnit>> entry : s) {
  922. Map<Version, IInstallableUnit> conflictingEntries = entry.getValue();
  923. if (conflictingEntries.size() < 2)
  924. continue;
  925. Collection<IInstallableUnit> conflictingVersions = conflictingEntries.values();
  926. List<IInstallableUnit> singletons = new ArrayList<IInstallableUnit>();
  927. List<IInstallableUnit> nonSingletons = new ArrayList<IInstallableUnit>();
  928. for (IInstallableUnit iu : conflictingVersions) {
  929. if (iu.isSingleton()) {
  930. singletons.add(iu);
  931. } else {
  932. nonSingletons.add(iu);
  933. }
  934. }
  935. if (singletons.isEmpty())
  936. continue;
  937. IInstallableUnit[] singletonArray;
  938. if (nonSingletons.isEmpty()) {
  939. singletonArray = singletons.toArray(new IInstallableUnit[singletons.size()]);
  940. createAtMostOne(singletonArray);
  941. } else {
  942. singletonArray = singletons.toArray(new IInstallableUnit[singletons.size() + 1]);
  943. for (IInstallableUnit nonSingleton : nonSingletons) {
  944. singletonArray[singletonArray.length - 1] = nonSingleton;
  945. createAtMostOne(singletonArray);
  946. }
  947. }
  948. }
  949. }
  950. private void createAtMostOne(IInstallableUnit[] ius) throws ContradictionException {
  951. if (DEBUG) {
  952. StringBuffer b = new StringBuffer();
  953. for (int i = 0; i < ius.length; i++) {
  954. b.append(ius[i].toString());
  955. }
  956. Tracing.debug("At most 1 of " + b); //$NON-NLS-1$
  957. }
  958. dependencyHelper.atMost(1, (Object[]) ius).named(new Explanation.Singleton(ius));
  959. }
  960. private void createIncompatibleValues(AbstractVariable v1, AbstractVariable v2) throws ContradictionException {
  961. AbstractVariable[] vars = {v1, v2};
  962. if (DEBUG) {
  963. StringBuffer b = new StringBuffer();
  964. for (int i = 0; i < vars.length; i++) {
  965. b.append(vars[i].toString());
  966. }
  967. Tracing.debug("At most 1 of " + b); //$NON-NLS-1$
  968. }
  969. dependencyHelper.atMost(1, (Object[]) vars).named(Explanation.OPTIONAL_REQUIREMENT);
  970. }
  971. private AbstractVariable getAbstractVariable(IRequirement req) {
  972. return getAbstractVariable(req, true);
  973. }
  974. private AbstractVariable getAbstractVariable(IRequirement req, boolean appearInOptFunction) {
  975. AbstractVariable abstractVariable = DEBUG_ENCODING ? new AbstractVariable("Abs_" + req.toString()) : new AbstractVariable(); //$NON-NLS-1$
  976. if (appearInOptFunction) {
  977. abstractVariables.add(abstractVariable);
  978. }
  979. return abstractVariable;
  980. }
  981. private AbstractVariable getNoOperationVariable(IInstallableUnit iu) {
  982. AbstractVariable v = noopVariables.get(iu);
  983. if (v == null) {
  984. v = DEBUG_ENCODING ? new AbstractVariable("Noop_" + iu.toString()) : new AbstractVariable(); //$NON-NLS-1$
  985. noopVariables.put(iu, v);
  986. }
  987. return v;
  988. }
  989. private AbstractVariable getNonGreedyVariable(IInstallableUnit iu) {
  990. AbstractVariable v = nonGreedyVariables.get(iu);
  991. if (v == null) {
  992. v = DEBUG_ENCODING ? new AbstractVariable("NG_" + iu.toString()) : new AbstractVariable(); //$NON-NLS-1$
  993. nonGreedyVariables.put(iu, v);
  994. }
  995. return v;
  996. }
  997. public IStatus invokeSolver(IProgressMonitor monitor) {
  998. if (result.getSeverity() == IStatus.ERROR)
  999. return result;
  1000. // CNF filename is given on the command line
  1001. long start = System.currentTimeMillis();
  1002. if (DEBUG)
  1003. Tracing.debug("Invoking solver: " + start); //$NON-NLS-1$
  1004. try {
  1005. if (monitor.isCanceled())
  1006. return Status.CANCEL_STATUS;
  1007. if (dependencyHelper.hasASolution(assumptions)) {
  1008. if (DEBUG) {
  1009. Tracing.debug("Satisfiable !"); //$NON-NLS-1$
  1010. }
  1011. backToIU();
  1012. long stop = System.currentTimeMillis();
  1013. if (DEBUG)
  1014. Tracing.debug("Solver solution found: " + (stop - start)); //$NON-NLS-1$
  1015. } else {
  1016. long stop = System.currentTimeMillis();
  1017. if (DEBUG) {
  1018. Tracing.debug("Unsatisfiable !"); //$NON-NLS-1$
  1019. Tracing.debug("Solver solution NOT found: " + (stop - start)); //$NON-NLS-1$
  1020. }
  1021. result = new MultiStatus(DirectorActivator.PI_DIRECTOR, SimplePlanner.UNSATISFIABLE, result.getChildren(), Messages.Planner_Unsatisfiable_problem, null);
  1022. result.merge(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, SimplePlanner.UNSATISFIABLE, Messages.Planner_Unsatisfiable_problem, null));
  1023. }
  1024. } catch (TimeoutException e) {
  1025. result.merge(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, Messages.Planner_Timeout));
  1026. } catch (Exception e) {
  1027. result.merge(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, Messages.Planner_Unexpected_problem, e));
  1028. }
  1029. if (DEBUG)
  1030. System.out.println();
  1031. return result;
  1032. }
  1033. private void backToIU() {
  1034. solution = new ArrayList<IInstallableUnit>();
  1035. IVec<Object> sat4jSolution = dependencyHelper.getSolution();
  1036. for (Iterator<Object> iter = sat4jSolution.iterator(); iter.hasNext();) {
  1037. Object var = iter.next();
  1038. if (var instanceof IInstallableUnit) {
  1039. IInstallableUnit iu = (IInstallableUnit) var;
  1040. if (iu == entryPoint)
  1041. continue;
  1042. solution.add(iu);
  1043. }
  1044. }
  1045. }
  1046. private void printSolution(Collection<IInstallableUnit> state) {
  1047. ArrayList<IInstallableUnit> l = new ArrayList<IInstallableUnit>(state);
  1048. Collections.sort(l);
  1049. Tracing.debug("Solution:"); //$NON-NLS-1$
  1050. Tracing.debug("Numbers of IUs selected: " + l.size()); //$NON-NLS-1$
  1051. for (IInstallableUnit s : l) {
  1052. Tracing.debug(s.toString());
  1053. }
  1054. }
  1055. public Collection<IInstallableUnit> extractSolution() {
  1056. if (DEBUG)
  1057. printSolution(solution);
  1058. return solution;
  1059. }
  1060. public Set<Explanation> getExplanation(IProgressMonitor monitor) {
  1061. ExplanationJob job = new ExplanationJob();
  1062. job.schedule();
  1063. monitor.setTaskName(Messages.Planner_NoSolution);
  1064. IProgressMonitor pm = new InfiniteProgress(monitor);
  1065. pm.beginTask(Messages.Planner_NoSolution, 1000);
  1066. try {
  1067. synchronized (job) {
  1068. while (job.getExplanationResult() == null && job.getState() != Job.NONE) {
  1069. if (monitor.isCanceled()) {
  1070. job.cancel();
  1071. throw new OperationCanceledException();
  1072. }
  1073. pm.worked(1);
  1074. try {
  1075. job.wait(100);
  1076. } catch (InterruptedException e) {
  1077. if (DEBUG)
  1078. Tracing.debug("Interrupted while computing explanations"); //$NON-NLS-1$
  1079. }
  1080. }
  1081. }
  1082. } finally {
  1083. monitor.done();
  1084. }
  1085. return job.getExplanationResult();
  1086. }
  1087. public Map<IInstallableUnitFragment, List<IInstallableUnit>> getFragmentAssociation() {
  1088. Map<IInstallableUnitFragment, List<IInstallableUnit>> resolvedFragments = new HashMap<IInstallableUnitFragment, List<IInstallableUnit>>(fragments.size());
  1089. for (Entry<IInstallableUnitFragment, Set<IInstallableUnit>> fragment : fragments.entrySet()) {
  1090. if (!dependencyHelper.getBooleanValueFor(fragment.getKey()))
  1091. continue;
  1092. Set<IInstallableUnit> potentialHosts = fragment.getValue();
  1093. List<IInstallableUnit> resolvedHost = new ArrayList<IInstallableUnit>(potentialHosts.size());
  1094. for (IInstallableUnit host : potentialHosts) {
  1095. if (dependencyHelper.getBooleanValueFor(host))
  1096. resolvedHost.add(host);
  1097. }
  1098. if (resolvedHost.size() != 0)
  1099. resolvedFragments.put(fragment.getKey(), resolvedHost);
  1100. }
  1101. return resolvedFragments;
  1102. }
  1103. private void rememberHostMatches(IInstallableUnitFragment fragment, List<IInstallableUnit> matches) {
  1104. Set<IInstallableUnit> existingMatches = fragments.get(fragment);
  1105. if (existingMatches == null) {
  1106. existingMatches = new HashSet<IInstallableUnit>();
  1107. fragments.put(fragment, existingMatches);
  1108. existingMatches.addAll(matches);
  1109. }
  1110. existingMatches.retainAll(matches);
  1111. }
  1112. }