/*******************************************************************************
* 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.mspec.model;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.buckminster.core.CorePlugin;
import org.eclipse.buckminster.core.RMContext;
import org.eclipse.buckminster.core.XMLConstants;
import org.eclipse.buckminster.core.common.model.ExpandingProperties;
import org.eclipse.buckminster.core.cspec.IComponentIdentifier;
import org.eclipse.buckminster.core.cspec.IComponentName;
import org.eclipse.buckminster.core.cspec.model.ComponentName;
import org.eclipse.buckminster.core.ctype.IComponentType;
import org.eclipse.buckminster.core.materializer.IMaterializer;
import org.eclipse.buckminster.core.metadata.model.BillOfMaterials;
import org.eclipse.buckminster.core.metadata.model.Resolution;
import org.eclipse.buckminster.core.mspec.ConflictResolution;
import org.eclipse.buckminster.core.mspec.IMaterializationNode;
import org.eclipse.buckminster.core.mspec.IMaterializationSpec;
import org.eclipse.buckminster.core.mspec.builder.MaterializationNodeBuilder;
import org.eclipse.buckminster.core.mspec.builder.MaterializationSpecBuilder;
import org.eclipse.buckminster.core.parser.IParser;
import org.eclipse.buckminster.core.parser.IParserFactory;
import org.eclipse.buckminster.download.DownloadManager;
import org.eclipse.buckminster.osgi.filter.Filter;
import org.eclipse.buckminster.runtime.BuckminsterException;
import org.eclipse.buckminster.runtime.IOUtils;
import org.eclipse.buckminster.runtime.URLUtils;
import org.eclipse.buckminster.sax.ISaxable;
import org.eclipse.buckminster.sax.Utils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* @author Thomas Hallgren
*/
public class MaterializationSpec extends MaterializationDirective implements ISaxable, IMaterializationSpec {
public static final String TAG = "mspec"; //$NON-NLS-1$
public static final String ATTR_NAME = "name"; //$NON-NLS-1$
public static final String ATTR_SHORT_DESC = "shortDesc"; //$NON-NLS-1$
public static final String ATTR_URL = "url"; //$NON-NLS-1$
public static MaterializationSpec fromStream(String systemId, InputStream stream) throws CoreException {
try {
IParserFactory pf = CorePlugin.getDefault().getParserFactory();
IParser<MaterializationSpec> parser = pf.getMaterializationSpecParser(false);
return parser.parse(systemId, stream);
} catch (Exception e) {
throw BuckminsterException.wrap(e);
}
}
public static MaterializationSpec fromURL(URL url) throws CoreException {
InputStream stream = null;
try {
stream = DownloadManager.read(url, null);
return fromStream(url.toString(), stream);
} catch (IOException e) {
throw BuckminsterException.wrap(e);
} finally {
IOUtils.close(stream);
}
}
private final String name;
private final String shortDesc;
private final String url;
private final List<MaterializationNode> nodes;
private final URL contextURL;
private BillOfMaterials currentBom;
public MaterializationSpec(MaterializationSpecBuilder builder) {
super(builder);
this.name = builder.getName();
this.shortDesc = builder.getShortDesc();
this.url = builder.getURL();
this.contextURL = builder.getContextURL();
ArrayList<MaterializationNode> nodeList = new ArrayList<MaterializationNode>();
for (MaterializationNodeBuilder nodeBuilder : builder.getNodeBuilders())
nodeList.add(nodeBuilder.createMaterializationNode());
this.nodes = Utils.createUnmodifiableList(nodeList);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Object getAdapter(Class adapter) {
if (adapter.isAssignableFrom(MaterializationSpecBuilder.class)) {
MaterializationSpecBuilder bld = new MaterializationSpecBuilder();
bld.initFrom(this);
return bld;
}
return super.getAdapter(adapter);
}
public ConflictResolution getConflictResolution(Resolution res) {
return getConflictResolution(getMatchingNode(res));
}
@Override
public URL getContextURL() {
return contextURL;
}
@Override
public String getDefaultTag() {
return TAG;
}
public IPath getLeafArtifact(Resolution resolution) {
IMaterializationNode node = getMatchingNode(resolution);
return node == null ? null : node.getLeafArtifact();
}
@Override
public IMaterializationNode getMatchingNode(IComponentName cName) {
if (currentBom != null && cName instanceof IComponentIdentifier) {
try {
return getMatchingNode(currentBom.getResolvedNode(((IComponentIdentifier) cName)).getResolution());
} catch (CoreException e) {
}
}
return getMatchingNode(cName, ((ComponentName) cName).getProperties());
}
@Override
public IMaterializationNode getMatchingNode(Resolution res) {
return getMatchingNode(res.getComponentIdentifier(), res.getProperties());
}
public IMaterializer getMaterializer(Resolution resolution) throws CoreException {
return CorePlugin.getDefault().getMaterializer(getMaterializerID(resolution));
}
public String getMaterializerID(Resolution resolution) throws CoreException {
IMaterializationNode node = getMatchingNode(resolution);
String materializer = (node == null) ? null : node.getMaterializerID();
if (materializer == null) {
materializer = getMaterializerID();
if (materializer == null) {
if ((IComponentType.OSGI_BUNDLE.equals(resolution.getComponentTypeId()) || IComponentType.ECLIPSE_FEATURE.equals(resolution
.getComponentTypeId())) && !resolution.getProvider().hasSource()) {
materializer = IMaterializer.P2;
} else {
materializer = resolution.getProvider().getReaderType().getRecommendedMaterializer();
}
}
}
return materializer;
}
@Override
public String getName() {
return name;
}
@Override
public List<? extends IMaterializationNode> getNodes() {
return nodes;
}
public String getProjectName(Resolution res) throws CoreException {
return getProjectName(res.getComponentIdentifier(), getMatchingNode(res));
}
@Override
public URL getResolvedURL() {
return URLUtils.resolveURL(contextURL, ExpandingProperties.expand(RMContext.getGlobalPropertyAdditions(), url, 0));
}
public IPath getResourcePath(Resolution res) {
IMaterializationNode node = getMatchingNode(res);
return node == null ? null : node.getResourcePath();
}
@Override
public String getShortDesc() {
return shortDesc;
}
public String getSuffix(Resolution res) {
IMaterializationNode node = getMatchingNode(res);
return node == null ? null : node.getSuffix();
}
@Override
public String getURL() {
return url;
}
public boolean isExcluded(IComponentName cname) {
IMaterializationNode node = getMatchingNode(cname);
return node != null && node.isExclude();
}
public boolean isExcluded(Resolution res) {
IMaterializationNode node = getMatchingNode(res);
return node != null && node.isExclude();
}
public boolean isExpand(Resolution res) {
IMaterializationNode node = getMatchingNode(res);
return node != null && (node.isUnpack() && node.isExpand());
}
public boolean isUnpack(Resolution res) {
IMaterializationNode node = getMatchingNode(res);
return node != null && node.isUnpack();
}
@Override
public void toSax(ContentHandler handler) throws SAXException {
handler.startDocument();
toSax(handler, XMLConstants.BM_METADATA_NS, XMLConstants.BM_METADATA_PREFIX, getDefaultTag());
handler.endDocument();
}
@Override
protected void addAttributes(AttributesImpl attrs) throws SAXException {
super.addAttributes(attrs);
Utils.addAttribute(attrs, ATTR_NAME, name);
Utils.addAttribute(attrs, ATTR_URL, url);
if (shortDesc != null)
Utils.addAttribute(attrs, ATTR_SHORT_DESC, shortDesc);
}
@Override
protected void emitElements(ContentHandler receiver, String namespace, String prefix) throws SAXException {
super.emitElements(receiver, namespace, prefix);
for (MaterializationNode node : nodes)
node.toSax(receiver, namespace, prefix, node.getDefaultTag());
}
private ConflictResolution getConflictResolution(IMaterializationNode node) {
ConflictResolution cr = null;
if (node != null)
cr = node.getConflictResolution();
if (cr == null) {
cr = getConflictResolution();
if (cr == null)
cr = ConflictResolution.getDefault();
}
return cr;
}
private IMaterializationNode getMatchingNode(IComponentName cName, Map<String, ? extends Object> props) {
for (MaterializationNode aNode : nodes) {
Pattern pattern = aNode.getNamePattern();
if (!(pattern == null || pattern.matcher(cName.getName()).find()))
continue;
String matchingCType = aNode.getComponentTypeID();
if (!(matchingCType == null || matchingCType.equals(cName.getComponentTypeID())))
continue;
Filter filter = aNode.getFilter();
if (!(filter == null || filter.matches(props)))
continue;
return aNode;
}
return null;
}
private String getProjectName(ComponentName cName, IMaterializationNode node) throws CoreException {
if (node == null)
return cName.getProjectName();
Pattern bindingNamePattern = node.getBindingNamePattern();
String bindingNameReplacement = node.getBindingNameReplacement();
if (bindingNamePattern == null || bindingNameReplacement == null)
return cName.getProjectName();
Matcher matcher = bindingNamePattern.matcher(cName.getName());
if (matcher.matches()) {
String repl = matcher.replaceAll(bindingNameReplacement).trim();
if (repl.length() > 0)
return repl;
}
return cName.getProjectName();
}
}