/*******************************************************************************
* 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.rmap.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.eclipse.buckminster.core.Messages;
import org.eclipse.buckminster.core.reader.IReaderType;
import org.eclipse.buckminster.core.resolver.NodeQuery;
import org.eclipse.buckminster.core.resolver.ResolverDecisionType;
import org.eclipse.buckminster.core.version.ProviderMatch;
import org.eclipse.buckminster.osgi.filter.Filter;
import org.eclipse.buckminster.runtime.MonitorUtils;
import org.eclipse.buckminster.sax.AbstractSaxableElement;
import org.eclipse.buckminster.sax.Utils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.osgi.util.NLS;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* @author Thomas Hallgren
*/
public class SearchPath extends AbstractSaxableElement {
public static final String TAG = "searchPath"; //$NON-NLS-1$
public static final String ATTR_NAME = "name"; //$NON-NLS-1$
private final String name;
private final ArrayList<Provider> providers = new ArrayList<Provider>();
private final ResourceMap resourceMap;
public SearchPath(ResourceMap rmap, String name) {
this.resourceMap = rmap;
this.name = name;
}
public void addPrefixMappings(HashMap<String, String> prefixMappings) {
for (Provider provider : providers)
provider.addPrefixMappings(prefixMappings);
}
public final void addProvider(Provider provider) {
providers.add(provider);
}
@Override
public String getDefaultTag() {
return TAG;
}
/**
* @return Returns the name.
*/
public final String getName() {
return name;
}
/**
* Find a provider that meets the requirements as closely as possible.
*/
public ProviderMatch getProvider(NodeQuery query, List<Provider> noGoodList, MultiStatus problemCollector, IProgressMonitor monitor)
throws CoreException {
int provCnt = providers.size();
if (provCnt == 0)
throw new CoreException(problemCollector);
monitor.beginTask("Matching providers", provCnt * 1000); //$NON-NLS-1$
try {
ProviderMatch bestMatch = null;
VersionRange desiredVersion = query.getVersionRange();
for (Provider provider : providers) {
if (noGoodList.contains(provider))
continue;
Filter[] filterHandle = new Filter[1];
if (!provider.isFilterMatchFor(query, filterHandle)) {
query.logDecision(ResolverDecisionType.FILTER_MISMATCH, filterHandle[0]);
continue;
}
query.logDecision(ResolverDecisionType.TRYING_PROVIDER, provider.getReaderTypeId(), getProviderURI(query, provider));
ProviderMatch match = provider.findMatch(query, problemCollector, MonitorUtils.subMonitor(monitor, 1000));
if (match == null) {
noGoodList.add(provider);
continue;
}
String readerType = provider.getReaderTypeId();
ProviderScore score = match.getProviderScore();
if ((score.ordinal() >= ProviderScore.FAIR.ordinal() && IReaderType.LOCAL.equals(readerType))
|| (score.ordinal() >= ProviderScore.GOOD.ordinal() && desiredVersion != null
&& desiredVersion.getMinimum().equals(match.getVersionMatch().getVersion()) && desiredVersion.getMinimum().equals(
desiredVersion.getMaximum()))) {
// No use continuing the search. It won't get better
// than this.
//
bestMatch = match;
break;
}
if (bestMatch == null || match.compareTo(bestMatch) > 0) {
if (bestMatch != null) {
Provider rejected = bestMatch.getOriginalProvider();
query.logDecision(ResolverDecisionType.REJECTING_PROVIDER, rejected.getReaderTypeId(), getProviderURI(query, rejected),
NLS.bind(Messages._0_1_is_producing_a_better_match, provider.getReaderTypeId(), getProviderURI(query, provider)));
}
bestMatch = match;
continue;
}
Provider best = bestMatch.getOriginalProvider();
query.logDecision(ResolverDecisionType.REJECTING_PROVIDER, provider.getReaderTypeId(), getProviderURI(query, provider),
NLS.bind(Messages._0_1_is_producing_a_better_match, best.getReaderTypeId(), getProviderURI(query, best)));
}
if (bestMatch == null) {
query.logDecision(ResolverDecisionType.PROVIDER_NOT_FOUND);
throw new CoreException(problemCollector);
}
Provider best = bestMatch.getOriginalProvider();
query.logDecision(ResolverDecisionType.USING_PROVIDER, best.getReaderTypeId(), getProviderURI(query, best));
return bestMatch;
} finally {
monitor.done();
}
}
public List<Provider> getProviders() {
return providers;
}
/**
* Returns the resource map in which this search path is defined
*
* @return the resource map
*/
public ResourceMap getResourceMap() {
return resourceMap;
}
@Override
protected void addAttributes(AttributesImpl attrs) throws SAXException {
Utils.addAttribute(attrs, ATTR_NAME, name);
}
@Override
protected void emitElements(ContentHandler handler, String namespace, String prefix) throws SAXException {
for (Provider provider : providers)
provider.toSax(handler, namespace, prefix, provider.getDefaultTag());
}
String getProviderURI(NodeQuery query, Provider provider) {
String providerURI = provider.getURI().toString();
if (provider.getURIMatcher() == null)
providerURI += '[' + provider.getURI(provider.getProperties(query.getProperties())) + ']';
return providerURI;
}
}