Index: src/java/org/apache/ivy/plugins/parser/m2/PomDependencyManagementParser.java =================================================================== --- src/java/org/apache/ivy/plugins/parser/m2/PomDependencyManagementParser.java (revision 0) +++ src/java/org/apache/ivy/plugins/parser/m2/PomDependencyManagementParser.java (revision 0) @@ -0,0 +1,190 @@ +package org.apache.ivy.plugins.parser.m2; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.ivy.core.IvyPatternHelper; +import org.apache.ivy.core.module.id.ModuleId; +import org.apache.ivy.core.module.id.ModuleRevisionId; +import org.apache.ivy.util.XMLHelper; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * A maven 2 parser for walking the parent poms to aggregate the dependency management information + * + */ +public final class PomDependencyManagementParser extends DefaultHandler { + private Stack contextStack = new Stack(); + private StringBuffer buffer = new StringBuffer(); + + private String organisation; + + private String name; + + private String revision; + + private Map properties = new HashMap(); + + private Map dependencyManagement; + + private static final PomDependencyManagementParser INSTANCE = new PomDependencyManagementParser(); + + public static PomDependencyManagementParser getInstance() { + return INSTANCE; + } + + private PomDependencyManagementParser() { + } + + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + contextStack.push(qName); + String context = getContext(); + + if ("project/dependencyManagement/dependencies/dependency".equals(context)) { + // get the next one. + organisation = null; + name = null; + revision = null; + } + } + + public void endElement(String uri, String localName, String qName) throws SAXException { + processTextContent(); + String context = getContext(); + + if ("project/dependencyManagement/dependencies/dependency".equals(context)) { + if ( organisation != null && name != null && revision != null ) { + dependencyManagement.put(new ModuleId(organisation, name), revision); + } + } + if (context.equals("project/parent")) { + // walk up the parent chain building dependencyManagement + buildDependencyManagement(); + } + contextStack.pop(); + } + + private void processTextContent() { + if (buffer != null) { + String txt = IvyPatternHelper.substituteVariables(buffer.toString(), properties).trim(); + buffer = null; + + if (txt.length() == 0) { + return; + } + String context = getContext(); + if (context.equals("project/artifactId") ) { + properties.put("pom.artifactId", txt); + properties.put("project.artifactId", txt); + return; + } + if (context.equals("project/version") ) { + properties.put("pom.version", txt); + properties.put("project.version", txt); + return; + } + if (context.equals("project/groupId") ) { + properties.put("pom.groupId", txt); + properties.put("project.groupId", txt); + return; + } + if (context.equals("project/parent/groupId") && organisation == null) { + properties.put("parent.groupId", txt); + return; + } + if (context.equals("project/parent/version") && revision == null) { + properties.put("parent.version", txt); + return; + } + if (context.equals("project/parent/artifactId") && properties.get("parent.artifactId") == null) { + properties.put("parent.artifactId", txt); + return; + } + + if (context.equals("project/dependencyManagement/dependencies/dependency/groupId") && organisation == null) { + organisation = txt; + return; + } + if (context.equals("project/dependencyManagement/dependencies/dependency/artifactId") && name == null) { + name = txt; + return; + } + if (context.equals("project/dependencyManagement/dependencies/dependency/version") && revision == null) { + revision = txt; + return; + } + } + } + + public void characters(char[] ch, int start, int length) throws SAXException { + if (buffer == null) { + buffer = new StringBuffer(); + } + buffer.append(ch, start, length); + } + + private String getContext() { + StringBuffer buf = new StringBuffer(); + for (Iterator iter = contextStack.iterator(); iter.hasNext();) { + String ctx = (String) iter.next(); + buf.append(ctx).append("/"); + } + if (buf.length() > 0) { + buf.setLength(buf.length() - 1); + } + return buf.toString(); + } + + public Map getDependencyManagement() { + return dependencyManagement; + } + + public void setDependencyManagement(Map dependencyManagement) { + this.dependencyManagement = dependencyManagement; + } + + protected void buildDependencyManagement() throws SAXException { + String parentOrg = (String) properties.get("parent.groupId"); + String parentName = (String) properties.get("parent.artifactId"); + String parentVersion = (String) properties.get("parent.version"); + ModuleRevisionId mrid = ModuleRevisionId.newInstance(parentOrg, parentName, + parentVersion); + List pomUris = DependencyManagement.getPomUrl( mrid); + for ( int i = 0; i < pomUris.size(); i++ ) { + String pomUri = (String) pomUris.get(i); + try { + PomDependencyManagementParser parser = PomDependencyManagementParser.getInstance(); + // since a singleton, the dependency management is already set + XMLHelper.parse(new URL(pomUri), null, parser); + } + catch (ParserConfigurationException ex) { + IllegalStateException ise = new IllegalStateException(ex.getMessage()); + ise.initCause(ex); + throw ise; + } + catch ( MalformedURLException ex ) { + IllegalStateException ise = new IllegalStateException(ex.getMessage() + " in " + + pomUri); + ise.initCause(ex); + throw ise; + } + catch ( IOException ex ) { + IllegalStateException ise = new IllegalStateException(ex.getMessage() + " in " + + pomUri); + ise.initCause(ex); + throw ise; + } + } + } +} Index: src/java/org/apache/ivy/plugins/parser/m2/DependencyManagement.java =================================================================== --- src/java/org/apache/ivy/plugins/parser/m2/DependencyManagement.java (revision 0) +++ src/java/org/apache/ivy/plugins/parser/m2/DependencyManagement.java (revision 0) @@ -0,0 +1,145 @@ +package org.apache.ivy.plugins.parser.m2; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.ivy.core.IvyContext; +import org.apache.ivy.core.IvyPatternHelper; +import org.apache.ivy.core.module.descriptor.Artifact; +import org.apache.ivy.core.module.descriptor.DefaultArtifact; +import org.apache.ivy.core.module.id.ModuleId; +import org.apache.ivy.core.module.id.ModuleRevisionId; +import org.apache.ivy.plugins.resolver.DependencyResolver; +import org.apache.ivy.plugins.resolver.IBiblioResolver; +import org.apache.ivy.util.XMLHelper; +import org.xml.sax.SAXException; +public class DependencyManagement { + + private static Map dmCache; + + static { + /* use an in memory cache for the dependency management information */ + dmCache = new HashMap(); + } + + /** + * Get the dependency management information from the cache + * + * @param parent + * @return + */ + protected static Map getDependencyManagementFromCache(ModuleRevisionId parent) { + return (Map) dmCache.get(parent); + } + + /** + * Put the dependency management information in the cache + * + * @param parent + * @param dm + */ + protected static void putDependencyManagementInCache(ModuleRevisionId parent, Map dm) { + dmCache.put(parent, dm); + } + + /** + * Get the revision for dependency from the parent mrid. + * + * @param mrid the parent information from the pom + * @param dependency the dependency that does not have revision + * @return revision, can be null + * @throws SAXException + */ + public static String getRevision(ModuleRevisionId mrid, ModuleId dependency ) throws SAXException { + String revision = null; + Map dm = getDependencyManagementFromCache(mrid); + if ( dm == null ) { + dm = new HashMap(); + // lazy load the dependency management information + buildDependencyManagement(mrid, dm); + putDependencyManagementInCache(mrid, dm); + } + revision = (String) dm.get(dependency); + return revision; + } + + /** + * Build the dependency management information by walking up the parent poms + * + * @param mrid module revision id of parent + * @param dm the dependency management information + * @throws SAXException + */ + protected static void buildDependencyManagement(ModuleRevisionId mrid, Map dm) throws SAXException { + List pomUris = DependencyManagement.getPomUrl( mrid); + for ( int i = 0; i < pomUris.size(); i++ ) { + String pomUri = (String) pomUris.get(i); + try { + PomDependencyManagementParser parser = PomDependencyManagementParser.getInstance(); + parser.setDependencyManagement(dm); + XMLHelper.parse(new URL(pomUri), null, parser); + } + catch (ParserConfigurationException ex) { + IllegalStateException ise = new IllegalStateException(ex.getMessage()); + ise.initCause(ex); + throw ise; + } + catch ( MalformedURLException ex ) { + IllegalStateException ise = new IllegalStateException(ex.getMessage() + " in " + + pomUri); + ise.initCause(ex); + throw ise; + } + catch ( IOException ex ) { + IllegalStateException ise = new IllegalStateException(ex.getMessage() + " in " + + pomUri); + ise.initCause(ex); + throw ise; + } + } + } + + protected static List getPomUrl(ModuleRevisionId parent) { + List result = new ArrayList(); + // need to build url for parent + IvyContext context = IvyContext.getContext(); + DependencyResolver resolver = context.getSettings().getResolver(); + + if ( resolver instanceof IBiblioResolver ) { + IBiblioResolver iResolver = (IBiblioResolver) resolver; + if ( iResolver.isUsepoms()) { + ModuleRevisionId mrid = ModuleRevisionId.newInstance(parent.getOrganisation(), + parent.getName(), parent.getRevision()); + if (iResolver.isM2compatible()) { + mrid = convertM2IdForResourceSearch(mrid); + } + + Artifact artifact = DefaultArtifact.newPomArtifact(mrid, new Date()); + List patterns = iResolver.getArtifactPatterns(); + for ( int i = 0; i < patterns.size(); i++ ) { + Object pattern = patterns.get(i); + String url = IvyPatternHelper.substitute((String) pattern, mrid, artifact); + result.add(url); + } + } + } + return result; + } + + public static ModuleRevisionId convertM2IdForResourceSearch(ModuleRevisionId mrid) { + if (mrid.getOrganisation().indexOf('.') == -1) { + return mrid; + } + return ModuleRevisionId.newInstance(mrid.getOrganisation().replace('.', '/'), mrid + .getName(), mrid.getBranch(), mrid.getRevision(), mrid.getExtraAttributes()); + } + +} Index: src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java =================================================================== --- src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java (revision 597138) +++ src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java (working copy) @@ -229,8 +229,21 @@ fillMrid(); } else if ("project/parent/version".equals(context)) { properties.put("parent.version", revision); - } else if (((organisation != null && module != null && revision != null) || dd != null) + } else if (((organisation != null && module != null) || dd != null) && "project/dependencies/dependency".equals(context)) { + if ( revision == null ) { + String parentOrg = (String) properties.get("parent.groupId"); + String parentName = (String) properties.get("parent.artifactId"); + String parentVersion = (String) properties.get("parent.version"); + if ( parentOrg != null && parentName != null && parentVersion != null ) { + revision = DependencyManagement.getRevision( + ModuleRevisionId.newInstance(parentOrg, parentName, parentVersion), + new ModuleId(organisation,module)); + } + } + if ( revision == null ) { + return; + } if (dd == null) { dd = new DefaultDependencyDescriptor(md, ModuleRevisionId.newInstance( organisation, module, revision), true, false, true); @@ -332,6 +345,7 @@ String context = getContext(); if (context.equals("project/parent/groupId") && organisation == null) { organisation = txt; + properties.put("parent.groupId", txt); return; } if (context.equals("project/parent/version") && revision == null) { @@ -343,6 +357,12 @@ ext = txt; return; } + if (context.equals("project/parent/artifactId")) { + if ( properties.get("parent.artifactId") == null ) { + properties.put("parent.artifactId", txt); + } + return; + } if (context.equals("project/distributionManagement/relocation/groupId")) { relocationOrganisation= txt; return;