/******************************************************************************* * 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.maven.internal; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.XMLConstants; import org.eclipse.buckminster.core.common.model.Documentation; import org.eclipse.buckminster.core.common.model.Format; import org.eclipse.buckminster.core.rmap.model.BidirectionalTransformer; import org.eclipse.buckminster.core.rmap.model.Provider; import org.eclipse.buckminster.core.rmap.model.SearchPath; import org.eclipse.buckminster.core.rmap.model.VersionConverterDesc; import org.eclipse.buckminster.core.version.IVersionConverter; import org.eclipse.buckminster.maven.Messages; import org.eclipse.buckminster.osgi.filter.Filter; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.sax.ISaxableElement; import org.eclipse.buckminster.sax.Utils; import org.eclipse.core.runtime.CoreException; import org.eclipse.ecf.core.security.ConnectContextFactory; import org.eclipse.ecf.core.security.IConnectContext; import org.eclipse.osgi.util.NLS; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; public class MavenProvider extends Provider { public static final String MAVEN_PASSWORD_PROPERTY_KEY = "maven.password"; //$NON-NLS-1$ public static final String MAVEN_USERNAME_PROPERTY_KEY = "maven.username"; //$NON-NLS-1$ public static final String BM_MAVEN_PROVIDER_NS = XMLConstants.BM_PREFIX + "MavenProvider-1.0"; //$NON-NLS-1$ public static final String BM_MAVEN_PROVIDER_PREFIX = "mp"; //$NON-NLS-1$ public static final String ELEM_MAPPINGS = "mappings"; //$NON-NLS-1$ public static final String ELEM_RULE = "rule"; //$NON-NLS-1$ public static final String ELEM_SCOPES = "scopes"; //$NON-NLS-1$ public static final String ATTR_TRANSITIVE = "transitive"; //$NON-NLS-1$ /** * Apply default rules. I.e. * <ul> * <li>If the component name contains a dot, then separate the group and * artifact using the last dot.</li> * <li>If no dot is found, then use the same name for the group and artifact * </li> * </ul> * * @param name * the name of the component * @return an entry with a Maven groupId and artifactId */ public static IMapEntry getDefaultGroupAndArtifact(String name) { int dotIdx = name.lastIndexOf('/'); return (dotIdx > 0) ? new MapEntry(name, name.substring(0, dotIdx), name.substring(dotIdx + 1), null) : new MapEntry(name, name, name, null); } public static boolean getDefaultIsScopeExcluded() { return false; } /** * Apply default rules. I.e. * <ul> * <li>If the <code>groupId</code> and <code>artifactId</code> are equal, * use the <code>artifactId</code></li> * <li>If the <code>groupId</code> and <code>artifactId</code> are * different, use <code>groupId.artifactId</code></li> * </ul> * * @param groupId * the Maven group id * @param artifactId * the Maven artifact id * @return The default component name. */ public static String getDefaultName(String groupId, String artifactId) { if (groupId.equals(artifactId)) { // Contructs like <groupId>:<artifactId> are known to exist // int colonIdx = artifactId.indexOf(':'); if (colonIdx < 0) return artifactId; groupId = artifactId.substring(0, colonIdx); artifactId = artifactId.substring(colonIdx + 1); } return groupId + '/' + artifactId; } public static boolean getDefaultTransitive() { return true; } private final Map<String, MapEntry> mappings; private final List<BidirectionalTransformer> rules; private final Map<String, Scope> scopes; private final boolean transitive; private IConnectContext connectContext; public MavenProvider(SearchPath searchPath, String remoteReaderType, String[] componentTypes, VersionConverterDesc versionConverterDesc, Format uri, Filter resolutionFilter, Map<String, String> properties, Documentation documentation, Map<String, MapEntry> mappings, List<BidirectionalTransformer> rules) { this(searchPath, remoteReaderType, componentTypes, versionConverterDesc, uri, resolutionFilter, properties, documentation, mappings, rules, Collections.<String, Scope> emptyMap(), true); } public MavenProvider(SearchPath searchPath, String remoteReaderType, String[] componentTypes, VersionConverterDesc versionConverterDesc, Format uri, Filter resolutionFilter, Map<String, String> properties, Documentation documentation, Map<String, MapEntry> mappings, List<BidirectionalTransformer> rules, Map<String, Scope> scopes, boolean transitive) { super(searchPath, remoteReaderType, componentTypes, versionConverterDesc, uri, null, null, resolutionFilter, properties, null, documentation); if (mappings == null) mappings = Collections.emptyMap(); if (rules == null) rules = Collections.emptyList(); if (scopes == null) scopes = Collections.emptyMap(); this.mappings = mappings; this.rules = rules; this.scopes = scopes; this.transitive = transitive; } @Override public void addPrefixMappings(HashMap<String, String> prefixMappings) { super.addPrefixMappings(prefixMappings); prefixMappings.put(BM_MAVEN_PROVIDER_PREFIX, BM_MAVEN_PROVIDER_NS); } @Override public IVersionConverter getVersionConverter() throws CoreException { return CorePlugin.getDefault().getVersionConverter(IVersionConverter.TAG); } @Override public boolean hasLocalCache() { return true; } @Override protected void addAttributes(AttributesImpl attrs) throws SAXException { super.addAttributes(attrs); attrs.addAttribute(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type", "xsi:type", //$NON-NLS-1$ //$NON-NLS-2$ "CDATA", BM_MAVEN_PROVIDER_PREFIX + ":MavenProvider"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override protected void emitElements(ContentHandler handler, String namespace, String prefix) throws SAXException { super.emitElements(handler, namespace, prefix); if (mappings.size() == 0 && rules.size() == 0 && scopes.size() == 0) return; String qName = Utils.makeQualifiedName(BM_MAVEN_PROVIDER_PREFIX, ELEM_MAPPINGS); handler.startElement(BM_MAVEN_PROVIDER_NS, ELEM_MAPPINGS, qName, ISaxableElement.EMPTY_ATTRIBUTES); for (MapEntry mapping : mappings.values()) mapping.toSax(handler, BM_MAVEN_PROVIDER_NS, BM_MAVEN_PROVIDER_PREFIX, mapping.getDefaultTag()); for (BidirectionalTransformer rule : rules) rule.toSax(handler, BM_MAVEN_PROVIDER_NS, BM_MAVEN_PROVIDER_PREFIX, ELEM_RULE); handler.endElement(BM_MAVEN_PROVIDER_NS, ELEM_MAPPINGS, qName); String sqName = Utils.makeQualifiedName(BM_MAVEN_PROVIDER_PREFIX, ELEM_SCOPES); handler.startElement(BM_MAVEN_PROVIDER_NS, ELEM_SCOPES, sqName, ISaxableElement.EMPTY_ATTRIBUTES); for (Scope scope : scopes.values()) scope.toSax(handler, BM_MAVEN_PROVIDER_NS, BM_MAVEN_PROVIDER_PREFIX, scope.getDefaultTag()); handler.endElement(BM_MAVEN_PROVIDER_NS, ELEM_SCOPES, sqName); } String getComponentName(String groupId, String artifactId) throws CoreException { for (IMapEntry me : mappings.values()) { if (me.isMatchFor(groupId, artifactId)) return me.getName(); List<GroupAndArtifact> aliases = me.getAliases(); int idx = aliases.size(); while (--idx >= 0) { GroupAndArtifact alias = aliases.get(idx); if (alias.isMatchFor(groupId, artifactId)) return me.getName(); } } if (rules.size() > 0) { String compiled = groupId + '/' + artifactId; for (BidirectionalTransformer rule : rules) { String transformed = rule.transformTo(compiled); if (transformed != null) return transformed; } } return getDefaultName(groupId, artifactId); } /** * Get connection context for {@link MavenProvider} using two optional * properties, {@value #MAVEN_USERNAME_PROPERTY_KEY} and * {@value #MAVEN_PASSWORD_PROPERTY_KEY}. These properties can be specified * in the provider, the rmap or the props parameter and allow for property * expansion. * * @param props * A property Map of additional properties (combined with the * provider and rmap properties) * @return A connect context or <code>null</code>. */ @Override public IConnectContext getConnectContext(Map<String, ? extends Object> props) { if (this.connectContext == null) { props = getProperties(props); String username = (String) props.get(MAVEN_USERNAME_PROPERTY_KEY); String password = (String) props.get(MAVEN_PASSWORD_PROPERTY_KEY); if (username == null && password == null) { connectContext = super.getConnectContext(props); } if (username != null) { if (password != null) { connectContext = ConnectContextFactory.createUsernamePasswordConnectContext(username, password); } connectContext = ConnectContextFactory.createUsernamePasswordConnectContext(username, null); } else if (password != null) { connectContext = ConnectContextFactory.createPasswordConnectContext(password); } } return this.connectContext; } IMapEntry getGroupAndArtifact(String name) throws CoreException { if (name.endsWith(".source")) //$NON-NLS-1$ return new SourceMapEntry(getGroupAndArtifact(name.substring(0, name.length() - 7))); IMapEntry entry = mappings.get(name); if (entry != null) return entry; String transformed = null; for (BidirectionalTransformer rule : rules) { transformed = rule.transformFrom(name); if (transformed != null) break; } if (transformed == null) return getDefaultGroupAndArtifact(name); int slashPos = transformed.indexOf('/'); if (slashPos < 0) throw BuckminsterException.fromMessage(NLS.bind(Messages.the_result_of_applying_a_match_rule_had_no_separator_slash_0, transformed)); return new MapEntry(name, transformed.substring(0, slashPos), transformed.substring(slashPos + 1), null); } boolean isScopeExcluded(String name) { if (name == null) return getDefaultIsScopeExcluded(); if (scopes.size() == 0) // This specific scope isn't found, and no other scopes are // mentioned so default behaviour will be to fall back to default // behaviour of getting everything return getDefaultIsScopeExcluded(); Scope scope = scopes.get(name); if (scope == null) // This specific scope isn't found, but our config does mention // other scopes so this should be excluded. We assume the user using // scopes will only want to mention scopes they care about, // otherwise they would have to know the names of every single scope // used throughout their maven repository return true; return scope.isExcluded(); } boolean isTransitive() { return transitive; } }