/******************************************************************************* * Copyright (c) 2004, 2006 * Thomas Hallgren, Kenneth Olwing, Mitch Sonies * Pontus Rydin, Nils Unden, Peer Torngren * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the individual * copyright holders listed above, as Initial Contributors under such license. * The text of such license is available at www.eclipse.org. *******************************************************************************/ package org.eclipse.buckminster.core.resolver; import java.util.ArrayList; import java.util.List; import org.eclipse.buckminster.core.RMContext; import org.eclipse.buckminster.core.cspec.QualifiedDependency; import org.eclipse.buckminster.core.cspec.model.CSpec; import org.eclipse.buckminster.core.materializer.IMaterializer; import org.eclipse.buckminster.core.metadata.model.BOMNode; import org.eclipse.buckminster.core.metadata.model.GeneratorNode; import org.eclipse.buckminster.core.metadata.model.Resolution; import org.eclipse.buckminster.core.query.model.ComponentQuery; 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; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; class ResolverNodeWithJob extends ResolverNode { class NodeResolutionJob extends Job { private boolean scheduled; NodeResolutionJob(String name) { super(name); } @Override public boolean belongsTo(Object family) { return family == resolver; } @Override protected IStatus run(IProgressMonitor monitor) { return ResolverNodeWithJob.this.run(monitor); } ResolverNodeWithJob getNode() { return ResolverNodeWithJob.this; } boolean isScheduled() { return scheduled; } void setScheduled(boolean flag) { scheduled = flag; } } private final ResourceMapResolver resolver; private final NodeResolutionJob job; private static final String SOURCE_SUFFIX = ".source"; //$NON-NLS-1$ private static final String SOURCE_FEATURE_SUFFIX = ".source.feature"; //$NON-NLS-1$ public static String getIdWithoutSource(String sourceId) { if (sourceId.endsWith(SOURCE_SUFFIX)) return sourceId.substring(0, sourceId.length() - SOURCE_SUFFIX.length()); if (sourceId.endsWith(SOURCE_FEATURE_SUFFIX)) return sourceId.substring(0, sourceId.length() - SOURCE_FEATURE_SUFFIX.length()) + ".feature"; //$NON-NLS-1$ return null; } ResolverNodeWithJob(ResourceMapResolver resolver, ResolutionContext context, QualifiedDependency qDep, String requestorInfo) { super(context.getNodeQuery(qDep), requestorInfo); this.job = new NodeResolutionJob(qDep.getRequest().toString()); this.resolver = resolver; } @Override public synchronized void addDependencyQualification(QualifiedDependency newQDep, String tagInfo) throws CoreException { super.addDependencyQualification(newQDep, tagInfo); if (isInvalidated() && !(isForceUnresolved() || isScheduled())) resolver.schedule(this); } protected IStatus run(IProgressMonitor monitor) { if (isForceUnresolved()) { resolver.resolutionPartDone(); return Status.OK_STATUS; } clearInvalidationFlag(); resolver.addJobMonitor(monitor); BOMNode node = null; try { node = resolve(monitor); if (node != null) { resolver.resolutionPartDone(); buildTree(node); } } catch (CoreException e) { RMContext context = resolver.getContext(); context.addRequestStatus(getQuery().getComponentRequest(), e.getStatus()); if (!context.isContinueOnError()) resolver.cancelTopMonitor(); } catch (OperationCanceledException e) { return Status.CANCEL_STATUS; } catch (Throwable e) { resolver.getContext().addRequestStatus(getQuery().getComponentRequest(), BuckminsterException.wrap(e).getStatus()); } finally { resolver.removeJobMonitor(monitor); if (node == null) resolver.resolutionPartDone(); } return Status.OK_STATUS; } NodeResolutionJob getJob() { return job; } boolean isScheduled() { return job.isScheduled(); } boolean rebuildTree(BOMNode node) throws CoreException { clearInvalidationFlag(); return buildTree(node); } void setScheduled(boolean scheduled) { job.setScheduled(scheduled); } private boolean buildTree(BOMNode node) throws CoreException { if (isInvalidated()) return false; ResolutionContext context = getQuery().getResolutionContext(); GeneratorNode generatorNode = context.getGeneratorNode(node.getRequest()); if (generatorNode != null) { setGeneratorNode(generatorNode); return false; } Resolution resolution = node.getResolution(); if (resolution == null) return resolver.schedule(this); context = startResolvingChildren(node); if (context == null) // // Must have been invalidated // return false; List<BOMNode> nodeChildren = node.getChildren(); int top = nodeChildren.size(); if (top == 0) { setResolution(resolution, null); return false; } // This section can *not* be synchronized. If it is, we risk running // into // deadlocks. // CSpec cspec = resolution.getCSpec(); String tagInfo = cspec.getTagInfo(getTagInfo()); boolean isInSourceForm = IMaterializer.WORKSPACE.equals(resolution.getProvider().getReaderType().getRecommendedMaterializer()); List<ResolverNode> children = null; boolean didSchedule = false; for (int idx = 0; idx < top; ++idx) { if (isInvalidated()) return false; BOMNode childNode = nodeChildren.get(idx); QualifiedDependency childReq = childNode.getQualifiedDependency(); if (isInSourceForm && childReq.getRequest().isSyntheticSource()) { String name = childReq.getRequest().getName(); if (getIdWithoutSource(name).equals(cspec.getName())) // Don't resolve source for source components continue; } ComponentQuery childQuery = childNode.getQuery(); ResolutionContext childContext = (childQuery == null) ? context : new ResolutionContext(childQuery, context); ResolverNode child = resolver.getResolverNode(childContext, childReq, tagInfo); if (children == null) children = new ArrayList<ResolverNode>(); children.add(child); if (((ResolverNodeWithJob) child).buildTree(childNode)) didSchedule = true; } setResolution(resolution, children == null ? null : children.toArray(new ResolverNode[children.size()])); return didSchedule; } private BOMNode resolve(IProgressMonitor monitor) throws CoreException { NodeQuery query; synchronized (this) { query = getQuery(); if (query.skipComponent() || isResolved()) { MonitorUtils.complete(monitor); return null; } } if (isInvalidated()) return null; return resolver.innerResolve(query, monitor); } }