/******************************************************************************* * 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.ctype; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.Messages; import org.eclipse.buckminster.core.cspec.WellKnownExports; import org.eclipse.buckminster.core.cspec.builder.CSpecBuilder; import org.eclipse.buckminster.core.cspec.builder.GroupBuilder; import org.eclipse.buckminster.core.cspec.model.AttributeAlreadyDefinedException; import org.eclipse.buckminster.core.cspec.model.ComponentRequest; import org.eclipse.buckminster.core.cspec.model.PrerequisiteAlreadyDefinedException; import org.eclipse.buckminster.core.helpers.AbstractExtension; import org.eclipse.buckminster.core.helpers.TextUtils; import org.eclipse.buckminster.core.metadata.model.BOMNode; import org.eclipse.buckminster.core.reader.IComponentReader; import org.eclipse.buckminster.core.reader.IReaderType; import org.eclipse.buckminster.core.reader.P2ReaderType; import org.eclipse.buckminster.core.version.ProviderMatch; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.buckminster.runtime.MonitorUtils; import org.eclipse.buckminster.runtime.Trivial; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.osgi.util.NLS; /** * @author Thomas Hallgren */ public abstract class AbstractComponentType extends AbstractExtension implements IComponentType { static class MetaFile implements IMetaFile { private final IPath[] aliases; private final boolean optional; private final IPath path; public MetaFile(IPath path, boolean optional, IPath[] aliases) { this.path = path; this.optional = optional; this.aliases = aliases; } @Override public IPath[] getAliases() { return aliases; } @Override public IPath getPath() { return path; } @Override public boolean isOptional() { return optional; } } private static final IMetaFile[] noMetaFiles = new IMetaFile[0]; /** * Helper methods used by component types that manifest themselfs as one * single jar file. * * @param cspec * @return An export where other jars that this component depends on can be * added */ public static GroupBuilder addSelfAsJarArtifactGroups(CSpecBuilder cspec) throws PrerequisiteAlreadyDefinedException, AttributeAlreadyDefinedException { GroupBuilder archives = cspec.createGroupBuilder(); archives.setName(WellKnownExports.JAVA_BINARY_ARCHIVES); archives.setPublic(true); archives.addSelfRequirement(); cspec.addAttribute(archives); GroupBuilder generic = cspec.createGroupBuilder(); generic.setName(WellKnownExports.JAVA_BINARIES); generic.setPublic(true); generic.addLocalPrerequisite(archives); cspec.addAttribute(generic); return generic; } public static String[] getComponentTypeIDs(boolean includeEmptyEntry) { IConfigurationElement[] elems = getElements(); int idx = elems.length; ArrayList<String> names = new ArrayList<String>(idx + 1); if (includeEmptyEntry) names.add(""); //$NON-NLS-1$ while (--idx >= 0) names.add(elems[idx].getAttribute("id")); //$NON-NLS-1$ Collections.sort(names); return names.toArray(new String[names.size()]); } public static IComponentType[] getComponentTypes() throws CoreException { CorePlugin plugin = CorePlugin.getDefault(); String[] cids = getComponentTypeIDs(false); int idx = cids.length; IComponentType[] ctypes = new IComponentType[idx]; while (--idx >= 0) ctypes[idx] = plugin.getComponentType(cids[idx]); return ctypes; } private static IConfigurationElement[] getElements() { IExtensionRegistry exReg = Platform.getExtensionRegistry(); return exReg.getConfigurationElementsFor(CorePlugin.COMPONENT_TYPE_POINT); } private Pattern desiredNamePattern; private IMetaFile[] metaFiles = noMetaFiles; private String nameSubstitution; private IPath relativeLocation; private Pattern substituteNamePattern; @Override public Version getComponentVersion(ProviderMatch rInfo, IProgressMonitor monitor) throws CoreException { BOMNode node = getResolution(rInfo, true, monitor); return node.getResolution().getComponentIdentifier().getVersion(); } @Override public Pattern getDesiredNamePattern() { return desiredNamePattern; } @Override public IMetaFile[] getMetaFiles() { return metaFiles; } @Override public String getNameSubstitution() { return nameSubstitution; } @Override public String getProjectName(String componentName) throws CoreException { if (componentName == null) return null; Pattern desiredMatch = getDesiredNamePattern(); if (desiredMatch == null || desiredMatch.matcher(componentName).find()) // // We have a component type but no desire to change the name // return componentName; Pattern repFrom = getSubstituteNamePattern(); String repTo = getNameSubstitution(); if (repFrom == null || repTo == null) throw BuckminsterException.fromMessage(NLS.bind(Messages.Component_type_0_defines_desiredNamePattern_but_no_substitution, getId())); Matcher matcher = repFrom.matcher(componentName); if (matcher.matches()) { String repl = matcher.replaceAll(repTo).trim(); if (repl.length() > 0) componentName = repl; } return componentName; } @Override public IPath getRelativeLocation() { return relativeLocation; } @Override public final BOMNode getResolution(ProviderMatch rInfo, IProgressMonitor monitor) throws CoreException { return getResolution(rInfo, false, monitor); } @Override public Pattern getSubstituteNamePattern() { return substituteNamePattern; } @Override public VersionRange getTypeSpecificDesignator(VersionRange designator) { return designator; } @Override public boolean hasAllRequiredMetaFiles(IPath path) { for (IMetaFile metaFile : getMetaFiles()) { if (metaFile.isOptional() || path.append(metaFile.getPath()).toFile().exists()) continue; boolean found = false; for (IPath alias : metaFile.getAliases()) { if (path.append(alias).toFile().exists()) { found = true; break; } } if (!found) return false; } return true; } @Override public boolean isMetaFileBased() { for (IMetaFile metaFile : getMetaFiles()) if (!metaFile.isOptional()) return true; return false; } @Override public void setExtensionParameter(String key, String value) throws CoreException { if ("relativeLocation".equals(key)) //$NON-NLS-1$ relativeLocation = value == null ? null : Path.fromPortableString(value); else if ("desiredNamePattern".equals(key)) //$NON-NLS-1$ desiredNamePattern = value == null ? null : Pattern.compile(value); else if ("substituteNamePattern".equals(key)) //$NON-NLS-1$ substituteNamePattern = value == null ? null : Pattern.compile(value); else if ("nameSubstitution".equals(key)) //$NON-NLS-1$ nameSubstitution = value; else super.setExtensionParameter(key, value); } @Override public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { super.setInitializationData(config, propertyName, data); String tmp = config.getAttribute("relativeLocation"); //$NON-NLS-1$ this.relativeLocation = tmp == null ? null : Path.fromPortableString(tmp); tmp = config.getAttribute("desiredNamePattern"); //$NON-NLS-1$ this.desiredNamePattern = tmp == null ? null : Pattern.compile(tmp); tmp = config.getAttribute("substituteNamePattern"); //$NON-NLS-1$ this.substituteNamePattern = tmp == null ? null : Pattern.compile(tmp); this.nameSubstitution = config.getAttribute("nameSubstitution"); //$NON-NLS-1$ ArrayList<IMetaFile> metaFileList = null; for (IConfigurationElement metaFile : config.getChildren("metaFile")) //$NON-NLS-1$ { tmp = metaFile.getAttribute("path"); //$NON-NLS-1$ if (tmp != null) { tmp = tmp.trim(); if (tmp.length() == 0) tmp = null; } if (tmp == null) continue; IPath path = Path.fromPortableString(tmp); boolean optional = "true".equalsIgnoreCase(metaFile.getAttribute("optional")); //$NON-NLS-1$ //$NON-NLS-2$ List<IPath> aliasesBld = null; for (String alias : TextUtils.split(metaFile.getAttribute("aliases"), ",")) //$NON-NLS-1$ //$NON-NLS-2$ { alias = alias.trim(); if (alias.length() > 0) { if (aliasesBld == null) aliasesBld = new ArrayList<IPath>(); aliasesBld.add(new Path(alias)); } } IPath[] aliases = (aliasesBld == null) ? Trivial.EMPTY_PATH_ARRAY : aliasesBld.toArray(new IPath[aliasesBld.size()]); if (metaFileList == null) metaFileList = new ArrayList<IMetaFile>(); metaFileList.add(new MetaFile(path, optional, aliases)); } this.metaFiles = (metaFileList == null) ? noMetaFiles : metaFileList.toArray(new IMetaFile[metaFileList.size()]); } protected BOMNode getResolution(ProviderMatch rInfo, boolean forResolutionAidOnly, IProgressMonitor monitor) throws CoreException { IReaderType readerType = rInfo.getReaderType(); if (readerType instanceof P2ReaderType) { // Component type etc. is given by the IU return ((P2ReaderType) readerType).getResolution(rInfo, monitor); } monitor.beginTask(null, 2000); IComponentReader[] readerHandle = new IComponentReader[1]; try { IComponentReader reader = rInfo.getReader(MonitorUtils.subMonitor(monitor, 200)); if (forResolutionAidOnly && reader.isFileSystemReader()) forResolutionAidOnly = false; readerHandle[0] = reader; ComponentRequest request = rInfo.getNodeQuery().getComponentRequest(); String componentType = request.getComponentTypeID(); if (componentType != null && !getId().equals(componentType)) throw new ComponentTypeMismatchException(request.getName(), componentType, getId()); IResolutionBuilder builder = getResolutionBuilder(readerHandle[0], MonitorUtils.subMonitor(monitor, 800)); return builder.build(readerHandle, forResolutionAidOnly, MonitorUtils.subMonitor(monitor, 1000)); } finally { IOUtils.close(readerHandle[0]); } } }