/***************************************************************************** * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. *****************************************************************************/ package org.eclipse.buckminster.core.resolver; import java.util.List; import org.eclipse.buckminster.core.Messages; import org.eclipse.buckminster.core.cspec.model.ComponentRequest; import org.eclipse.buckminster.core.metadata.model.BillOfMaterials; import org.eclipse.buckminster.core.metadata.model.UnresolvedNode; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.MonitorUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; /** * @author Thomas Hallgren */ public class MainResolver implements IResolver { private static final int MAX_ITERATIONS = 8; // TODO: Perhaps this should be // a preference setting private final ResolutionContext context; private boolean recursiveResolve = true; public MainResolver(ResolutionContext context) { this.context = context; } @Override public ResolutionContext getContext() { return context; } @Override public boolean isRecursiveResolve() { return recursiveResolve; } @Override public ResolverDecision logDecision(ComponentRequest request, ResolverDecisionType decisionType, Object... args) { return context.logDecision(request, decisionType, args); } @Override public ResolverDecision logDecision(ResolverDecisionType decisionType, Object... args) { return context.logDecision(decisionType, args); } @Override public BillOfMaterials resolve(ComponentRequest request, IProgressMonitor monitor) throws CoreException { NodeQuery query = context.getNodeQuery(request); BillOfMaterials bom = BillOfMaterials.create(new UnresolvedNode(query.getQualifiedDependency()), context.getComponentQuery()); return resolveRemaining(bom, monitor); } @Override public BillOfMaterials resolve(IProgressMonitor monitor) throws CoreException { return resolve(context.getComponentQuery().getExpandedRootRequest(context), monitor); } @Override public BillOfMaterials resolveRemaining(BillOfMaterials bom, IProgressMonitor monitor) throws CoreException { if (bom.isFullyResolved(context)) return bom; context.addTagInfo(bom.getRequest(), bom.getQuery().getTagInfo()); IResolverFactory[] resolverFactories = ResolverFactoryMaintainer.getInstance().getActiveResolverFactories(); int numFactories = resolverFactories.length; if (numFactories == 1) { // Only one factory? Just delegate to it. // IResolverFactory factory = resolverFactories[0]; logDecision(ResolverDecisionType.USING_RESOLVER, factory.getId()); bom = factory.createResolver(context).resolveRemaining(bom, monitor); } else { monitor.beginTask(null, numFactories * 100); // Since all factories but the last should continue on error // we must save our status here. The last factory should use // our status always since it must fail if we are setup to // fail. // boolean continueOnError = context.isContinueOnError(); boolean silentStatus = context.isSilentStatus(); context.setContinueOnError(true); context.setSilentStatus(true); try { IResolver[] resolvers = new IResolver[numFactories]; for (int idx = 0; idx < numFactories; ++idx) resolvers[idx] = resolverFactories[idx].createResolver(context); for (int iteration = 0; iteration < MAX_ITERATIONS; ++iteration) { BillOfMaterials bomAtIterationStart = bom; for (int idx = 0; idx < numFactories; ++idx) { IResolver resolver = resolvers[idx]; logDecision(ResolverDecisionType.USING_RESOLVER, resolverFactories[idx].getId()); resolver.setRecursiveResolve(recursiveResolve); BillOfMaterials newBom = resolver.resolveRemaining(bom, MonitorUtils.subMonitor(monitor, 100)); if (bom.contentEqual(newBom)) continue; if (idx == 0) // // There is no reason to reiterate if the only // iteration that changed // the bom was the first. // bomAtIterationStart = bom; bom = newBom; if (!recursiveResolve || bom.isFullyResolved(context)) { // Something happened with the BOM so we consider // ourselves done here // iteration = MAX_ITERATIONS; break; } } if (bomAtIterationStart.equals(bom)) // // A full iteration over all resolvers gave us nothing. // Then // it's safe to assume that the same thing would happen // again // break; } if (!(continueOnError || bom.isFullyResolved(context))) { IStatus status = context.getStatus(); if (status.getSeverity() == IStatus.ERROR) { List<ComponentRequest> unresolvedList = bom.getUnresolvedList(); int top = unresolvedList.size(); if (top == 0) throw new CoreException(status); StringBuilder bld = new StringBuilder(); bld.append(Messages.Unable_to_resolve); for (int idx = 0; idx < top; ++idx) { if (idx > 0) bld.append(", "); //$NON-NLS-1$ unresolvedList.get(idx).toString(bld); } throw BuckminsterException.fromMessage(bld.toString()); } } } finally { context.setContinueOnError(continueOnError); context.setSilentStatus(silentStatus); monitor.done(); } } return bom; } @Override public void setRecursiveResolve(boolean flag) { recursiveResolve = flag; } }