/*******************************************************************************
* 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.rmap.model;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.PatternSyntaxException;
import org.eclipse.buckminster.core.CorePlugin;
import org.eclipse.buckminster.core.common.model.ExpandingProperties;
import org.eclipse.buckminster.core.common.model.RxAssembly;
import org.eclipse.buckminster.core.common.model.RxPart;
import org.eclipse.buckminster.core.common.model.TaggedRxPattern;
import org.eclipse.buckminster.core.cspec.builder.CSpecBuilder;
import org.eclipse.buckminster.core.cspec.model.ComponentRequest;
import org.eclipse.buckminster.core.ctype.IComponentType;
import org.eclipse.buckminster.core.helpers.DateAndTimeUtils;
import org.eclipse.buckminster.core.helpers.FilterUtils;
import org.eclipse.buckminster.core.metadata.builder.ResolutionBuilder;
import org.eclipse.buckminster.core.metadata.model.Resolution;
import org.eclipse.buckminster.core.reader.URLCatalogReaderType;
import org.eclipse.buckminster.core.resolver.NodeQuery;
import org.eclipse.buckminster.core.version.ProviderMatch;
import org.eclipse.buckminster.core.version.VersionHelper;
import org.eclipse.buckminster.core.version.VersionMatch;
import org.eclipse.buckminster.core.version.VersionSelector;
import org.eclipse.buckminster.download.DownloadManager;
import org.eclipse.buckminster.osgi.filter.Filter;
import org.eclipse.buckminster.runtime.BuckminsterException;
import org.eclipse.buckminster.runtime.IFileInfo;
import org.eclipse.buckminster.runtime.Logger;
import org.eclipse.buckminster.runtime.URLUtils;
import org.eclipse.buckminster.sax.Utils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.equinox.p2.metadata.IVersionFormat;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* @author Thomas Hallgren
*
*/
public class URIMatcher extends RxAssembly {
@SuppressWarnings("hiding")
public static final String TAG = "matcher"; //$NON-NLS-1$
public static final String ATTR_BASE = "base"; //$NON-NLS-1$
public static final String ATTR_VERSION_FORMAT = "versionFormat"; //$NON-NLS-1$
public static final String ATTR_VERSION_TYPE = "versionType"; //$NON-NLS-1$
public static final String COMPONENT_NAME_PARAM = TaggedRxPattern.TAGGED_PREFIX + "name"; //$NON-NLS-1$
public static final String COMPONENT_VERSION_PARAM = TaggedRxPattern.TAGGED_PREFIX + "version"; //$NON-NLS-1$
public static final String BRANCH_PARAM = TaggedRxPattern.TAGGED_PREFIX + "branch"; //$NON-NLS-1$
public static final String TAG_PARAM = TaggedRxPattern.TAGGED_PREFIX + "tag"; //$NON-NLS-1$
public static final String REVISION_PARAM = TaggedRxPattern.TAGGED_PREFIX + "revision"; //$NON-NLS-1$
public static final String TIMESTAMP_PARAM = TaggedRxPattern.TAGGED_PREFIX + "timestamp"; //$NON-NLS-1$
public static final String OS_PARAM = TaggedRxPattern.TAGGED_PREFIX + "os"; //$NON-NLS-1$
public static final String WS_PARAM = TaggedRxPattern.TAGGED_PREFIX + "ws"; //$NON-NLS-1$
public static final String ARCH_PARAM = TaggedRxPattern.TAGGED_PREFIX + "arch"; //$NON-NLS-1$
public static final String NL_PARAM = TaggedRxPattern.TAGGED_PREFIX + "nl"; //$NON-NLS-1$
public static final String ARTIFACT_INFO_PREFIX = "URIMetaData:"; //$NON-NLS-1$
private static Filter getFilter(Map<String, String> matchMap) {
return FilterUtils.createFilter(matchMap.get(OS_PARAM), matchMap.get(WS_PARAM), matchMap.get(ARCH_PARAM), matchMap.get(NL_PARAM));
}
private final String base;
private final IVersionFormat versionFormat;
private final String componentType;
public URIMatcher(List<RxPart> parts, String base, IVersionFormat versionFormat, String componentType) throws CoreException,
PatternSyntaxException {
super(parts);
this.base = base;
this.versionFormat = versionFormat == null ? VersionHelper.getOSGiFormat() : versionFormat;
this.componentType = componentType;
}
public Resolution createResolution(ProviderMatch pm) throws CoreException {
Map<String, String> matchMap = pm.getMatcherMap();
if (matchMap == null)
return null;
CSpecBuilder bld = new CSpecBuilder();
bld.setName(matchMap.get(COMPONENT_NAME_PARAM));
String tmp = matchMap.get(COMPONENT_VERSION_PARAM);
if (tmp != null) {
try {
bld.setVersion(versionFormat.parse(tmp));
} catch (IllegalArgumentException e) {
throw BuckminsterException.wrap(e);
}
}
IComponentType ctype = pm.getComponentType();
bld.setComponentTypeID(ctype.getId());
bld.setFilter(getFilter(matchMap));
try {
IFileInfo info = DownloadManager.readInfo(URLUtils.normalizeToURL(pm.getRepositoryURI()), pm.getConnectContext());
NodeQuery nq = pm.getNodeQuery();
ResolutionBuilder resBld = new ResolutionBuilder(bld);
resBld.getRequest().initFrom(nq.getComponentRequest());
resBld.setAttributes(nq.getRequiredAttributes());
resBld.setProvider(pm.getProvider());
resBld.setRepository(pm.getProvider().getURI(nq.getProperties()));
resBld.setComponentTypeId(ctype.getId());
resBld.setVersionMatch(pm.getVersionMatch());
resBld.setFileInfo(info);
return new Resolution(resBld);
} catch (FileNotFoundException e) {
return null;
} catch (MalformedURLException e) {
throw BuckminsterException.wrap(e);
}
}
public String getBase() {
return base;
}
@Override
public String getDefaultTag() {
return TAG;
}
public ProviderMatch getMatch(Provider provider, NodeQuery query, IProgressMonitor monitor) throws CoreException {
Logger logger = CorePlugin.getLogger();
ComponentRequest cq = query.getComponentRequest();
VersionMatch candidate = null;
Map<String, String> candidateMap = null;
Map<String, ? extends Object> providerProperties = provider.getProperties(query.getProperties());
URL baseURL;
try {
baseURL = new URL(ExpandingProperties.expand(providerProperties, base, 0));
} catch (MalformedURLException e) {
throw BuckminsterException.wrap(e);
}
URL[] urlsToMatch = URLCatalogReaderType.list(baseURL, query.getComponentQuery().getConnectContext(), monitor);
if (urlsToMatch.length == 0) {
logger.debug("No URL's for %s found on page %s", cq.getName(), baseURL); //$NON-NLS-1$
return null;
}
for (URL urlToMatch : urlsToMatch) {
Map<String, String> matchMap = getMatchMap(urlToMatch.toString());
if (matchMap == null)
continue;
String matchedName = matchMap.get(COMPONENT_NAME_PARAM);
if (!cq.getName().equals(matchedName)) {
logger.debug("URI name %s does not match %s", matchedName, cq.getName()); //$NON-NLS-1$
continue;
}
Version version = null;
String tmp = matchMap.get(COMPONENT_VERSION_PARAM);
if (tmp != null) {
try {
version = versionFormat.parse(tmp);
VersionRange vd = cq.getVersionRange();
if (!(vd == null || vd.isIncluded(version))) {
logger.debug("URI version %s is not designated by %s", version, vd); //$NON-NLS-1$
continue;
}
} catch (IllegalArgumentException e) {
logger.warning(e, e.getMessage());
continue;
}
}
Filter filter = getFilter(matchMap);
if (!(filter == null || filter.matchCase(providerProperties))) {
logger.debug("URI filter %s does not match current environment", filter); //$NON-NLS-1$
continue;
}
VersionSelector vs = null;
tmp = matchMap.get(BRANCH_PARAM);
if (tmp != null)
vs = VersionSelector.branch(tmp);
else {
tmp = matchMap.get(TAG_PARAM);
if (tmp != null)
vs = VersionSelector.tag(tmp);
}
long revision = -1;
tmp = matchMap.get(REVISION_PARAM);
if (tmp != null) {
try {
revision = Long.parseLong(tmp);
} catch (NumberFormatException e) {
logger.warning(e, e.getMessage());
}
}
Date timestamp = null;
tmp = matchMap.get(TIMESTAMP_PARAM);
if (tmp != null) {
try {
timestamp = DateAndTimeUtils.fromString(tmp);
} catch (ParseException e) {
logger.warning(e, e.getMessage());
}
}
VersionMatch vm = new VersionMatch(version, vs, revision, timestamp, null);
if (candidate == null || query.compare(vm, candidate) > 0) {
// Verify that the URI created using this matchMap is readable
//
candidate = vm;
candidateMap = matchMap;
}
}
if (candidate == null)
return null;
query = query.getContext().getNodeQuery(query.getQualifiedDependency());
query = new NodeQuery(query, candidateMap);
ProviderMatch pm = new ProviderMatch(provider, CorePlugin.getDefault().getComponentType(componentType), candidate, query);
pm.setMatcherMap(candidateMap);
return pm;
}
public IVersionFormat getVersionType() {
return versionFormat;
}
@Override
protected void addAttributes(AttributesImpl attrs) throws SAXException {
super.addAttributes(attrs);
Utils.addAttribute(attrs, ATTR_BASE, base);
if (!versionFormat.equals(VersionHelper.getOSGiFormat()))
Utils.addAttribute(attrs, ATTR_VERSION_FORMAT, versionFormat.toString());
}
}