/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.m2; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.text.ParseException; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.Configuration.Visibility; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder.PomDependencyDescriptor; import org.apache.ivy.plugins.parser.m2.PomReader.PomDependencyData; import org.apache.ivy.plugins.parser.m2.PomReader.PomDependencyMgtElement; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; import org.xml.sax.SAXException; /** * A parser for Maven 2 POM. *

* The configurations used in the generated module descriptor mimics the behavior defined by maven 2 * scopes, as documented here:
* http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html The * PomModuleDescriptorParser use a PomDomReader to read the pom, and the PomModuleDescriptorBuilder * to write the ivy module descriptor using the info read by the PomDomReader. */ public final class PomModuleDescriptorParser implements ModuleDescriptorParser { private static final PomModuleDescriptorParser INSTANCE = new PomModuleDescriptorParser(); public static PomModuleDescriptorParser getInstance() { return INSTANCE; } private PomModuleDescriptorParser() { } public void toIvyFile(InputStream is, Resource res, File destFile, ModuleDescriptor md) throws ParseException, IOException { try { XmlModuleDescriptorWriter.write(md, destFile); } finally { if (is != null) { is.close(); } } } public boolean accept(Resource res) { return res.getName().endsWith(".pom") || res.getName().endsWith("pom.xml") || res.getName().endsWith("project.xml"); } public String toString() { return "pom parser"; } public Artifact getMetadataArtifact(ModuleRevisionId mrid, Resource res) { return DefaultArtifact.newPomArtifact(mrid, new Date(res.getLastModified())); } public String getType() { return "pom"; } public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, boolean validate) throws ParseException, IOException { URLResource resource = new URLResource(descriptorURL); return parseDescriptor(ivySettings, descriptorURL, resource, validate); } public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, Resource res, boolean validate) throws ParseException, IOException { PomModuleDescriptorBuilder mdBuilder = new PomModuleDescriptorBuilder(this, res, ivySettings); try { PomReader domReader = new PomReader(descriptorURL, res); domReader.setProperty("parent.version", domReader.getParentVersion()); domReader.setProperty("parent.groupId", domReader.getParentGroupId()); domReader.setProperty("project.parent.version", domReader.getParentVersion()); domReader.setProperty("project.parent.groupId", domReader.getParentGroupId()); Map pomProperties = domReader.getPomProperties(); for (Iterator iter = pomProperties.entrySet().iterator(); iter.hasNext();) { Map.Entry prop = (Map.Entry) iter.next(); domReader.setProperty((String) prop.getKey(), (String) prop.getValue()); mdBuilder.addProperty((String) prop.getKey(), (String) prop.getValue()); } ModuleDescriptor parentDescr = null; if (domReader.hasParent()) { // Is there any other parent properties? ModuleRevisionId parentModRevID = ModuleRevisionId.newInstance( domReader.getParentGroupId(), domReader.getParentArtifactId(), domReader.getParentVersion()); ResolvedModuleRevision parentModule = parseOtherPom(ivySettings, parentModRevID); if (parentModule != null) { parentDescr = parentModule.getDescriptor(); } else { throw new IOException("Impossible to load parent for " + res.getName() + "." + " Parent=" + parentModRevID); } if (parentDescr != null) { Map parentPomProps = PomModuleDescriptorBuilder .extractPomProperties(parentDescr.getExtraInfos()); for (Iterator iter = parentPomProps.entrySet().iterator(); iter.hasNext();) { Map.Entry prop = (Map.Entry) iter.next(); domReader.setProperty((String) prop.getKey(), (String) prop.getValue()); } } } String groupId = domReader.getGroupId(); String artifactId = domReader.getArtifactId(); String version = domReader.getVersion(); mdBuilder.setModuleRevId(groupId, artifactId, version); mdBuilder.setHomePage(domReader.getHomePage()); mdBuilder.setDescription(domReader.getDescription()); mdBuilder.setLicenses(domReader.getLicenses()); ModuleRevisionId relocation = domReader.getRelocation(); if (relocation != null) { if (groupId != null && artifactId != null && artifactId.equals(relocation.getName()) && groupId.equals(relocation.getOrganisation())) { Message.error("Relocation to an other version number not supported in ivy : " + mdBuilder.getModuleDescriptor().getModuleRevisionId() + " relocated to " + relocation + ". Please update your dependency to directly use the right version."); Message.warn("Resolution will only pick dependencies of the relocated element." + " Artefact and other metadata will be ignored."); ResolvedModuleRevision relocatedModule = parseOtherPom(ivySettings, relocation); if (relocatedModule == null) { throw new ParseException("impossible to load module " + relocation + " to which " + mdBuilder.getModuleDescriptor().getModuleRevisionId() + " has been relocated", 0); } DependencyDescriptor[] dds = relocatedModule.getDescriptor().getDependencies(); for (int i = 0; i < dds.length; i++) { mdBuilder.addDependency(dds[i]); } } else { Message.info(mdBuilder.getModuleDescriptor().getModuleRevisionId() + " is relocated to " + relocation + ". Please update your dependencies."); Message.verbose("Relocated module will be considered as a dependency"); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor( mdBuilder.getModuleDescriptor(), relocation, true, false, true); /* Map all public dependencies */ Configuration[] m2Confs = PomModuleDescriptorBuilder.MAVEN2_CONFIGURATIONS; for (int i = 0; i < m2Confs.length; i++) { if (Visibility.PUBLIC.equals(m2Confs[i].getVisibility())) { dd.addDependencyConfiguration(m2Confs[i].getName(), m2Confs[i].getName()); } } mdBuilder.addDependency(dd); } } else { domReader.setProperty("project.groupId", groupId); domReader.setProperty("pom.groupId", groupId); domReader.setProperty("groupId", groupId); domReader.setProperty("project.artifactId", artifactId); domReader.setProperty("pom.artifactId", artifactId); domReader.setProperty("artifactId", artifactId); domReader.setProperty("project.version", version); domReader.setProperty("pom.version", version); domReader.setProperty("version", version); if (parentDescr != null) { mdBuilder.addExtraInfos(parentDescr.getExtraInfos()); // add dependency management info from parent List depMgt = PomModuleDescriptorBuilder.getDependencyManagements(parentDescr); for (Iterator it = depMgt.iterator(); it.hasNext();) { PomDependencyMgt dep = (PomDependencyMgt) it.next(); if (dep instanceof PomDependencyMgtElement) { dep = domReader.new PomDependencyMgtElement( (PomDependencyMgtElement) dep); } mdBuilder.addDependencyMgt(dep); } // add plugins from parent List /* */plugins = PomModuleDescriptorBuilder .getPlugins(parentDescr); for (Iterator it = plugins.iterator(); it.hasNext();) { mdBuilder.addPlugin((PomDependencyMgt) it.next()); } } for (Iterator it = domReader.getDependencyMgt().iterator(); it.hasNext();) { PomDependencyMgt dep = (PomDependencyMgt) it.next(); if ("import".equals(dep.getScope())) { ModuleRevisionId importModRevID = ModuleRevisionId.newInstance( dep.getGroupId(), dep.getArtifactId(), dep.getVersion()); ResolvedModuleRevision importModule = parseOtherPom(ivySettings, importModRevID); if (importModule != null) { ModuleDescriptor importDescr = importModule.getDescriptor(); // add dependency management info from imported module List depMgt = PomModuleDescriptorBuilder .getDependencyManagements(importDescr); for (Iterator it2 = depMgt.iterator(); it2.hasNext();) { PomDependencyMgt importedDepMgt = (PomDependencyMgt) it2.next(); mdBuilder.addDependencyMgt(new DefaultPomDependencyMgt( importedDepMgt.getGroupId(), importedDepMgt.getArtifactId(), importedDepMgt.getVersion(), importedDepMgt.getScope(), importedDepMgt.getExcludedModules())); } } else { throw new IOException("Impossible to import module for " + res.getName() + "." + " Import=" + importModRevID); } } else { mdBuilder.addDependencyMgt(dep); } } for (Iterator it = domReader.getDependencies().iterator(); it.hasNext();) { PomReader.PomDependencyData dep = (PomReader.PomDependencyData) it.next(); mdBuilder.addDependency(res, dep); } if (parentDescr != null) { for (int i = 0; i < parentDescr.getDependencies().length; i++) { DependencyDescriptor descriptor = parentDescr.getDependencies()[i]; if (descriptor instanceof PomDependencyDescriptor) { PomDependencyData parentDep = ((PomDependencyDescriptor) descriptor) .getPomDependencyData(); PomDependencyData dep = domReader.new PomDependencyData(parentDep); mdBuilder.addDependency(res, dep); } else { mdBuilder.addDependency(descriptor); } } } for (Iterator it = domReader.getPlugins().iterator(); it.hasNext();) { PomReader.PomPluginElement plugin = (PomReader.PomPluginElement) it.next(); mdBuilder.addPlugin(plugin); } mdBuilder.addMainArtifact(artifactId, domReader.getPackaging()); addSourcesAndJavadocArtifactsIfPresent(mdBuilder, ivySettings); } } catch (SAXException e) { throw newParserException(e); } return mdBuilder.getModuleDescriptor(); } private void addSourcesAndJavadocArtifactsIfPresent(PomModuleDescriptorBuilder mdBuilder, ParserSettings ivySettings) { if (mdBuilder.getMainArtifact() == null) { // no main artifact in pom, we don't need to search for meta artifacts return; } ModuleDescriptor md = mdBuilder.getModuleDescriptor(); ModuleRevisionId mrid = md.getModuleRevisionId(); DependencyResolver resolver = ivySettings.getResolver(mrid); if (resolver == null) { Message.debug("no resolver found for " + mrid + ": no source or javadoc artifact lookup"); } else { ArtifactOrigin mainArtifact = resolver.locate(mdBuilder.getMainArtifact()); if (!ArtifactOrigin.isUnknown(mainArtifact)) { String mainArtifactLocation = mainArtifact.getLocation(); ArtifactOrigin sourceArtifact = resolver.locate(mdBuilder.getSourceArtifact()); if (!ArtifactOrigin.isUnknown(sourceArtifact) && !sourceArtifact.getLocation().equals(mainArtifactLocation)) { Message.debug("source artifact found for " + mrid); mdBuilder.addSourceArtifact(); } else { // it seems that sometimes the 'src' classifier is used instead of 'sources' // Cfr. IVY-1138 ArtifactOrigin srcArtifact = resolver.locate(mdBuilder.getSrcArtifact()); if (!ArtifactOrigin.isUnknown(srcArtifact) && !srcArtifact.getLocation().equals(mainArtifactLocation)) { Message.debug("source artifact found for " + mrid); mdBuilder.addSrcArtifact(); } else { Message.debug("no source artifact found for " + mrid); } } ArtifactOrigin javadocArtifact = resolver.locate(mdBuilder.getJavadocArtifact()); if (!ArtifactOrigin.isUnknown(javadocArtifact) && !javadocArtifact.getLocation().equals(mainArtifactLocation)) { Message.debug("javadoc artifact found for " + mrid); mdBuilder.addJavadocArtifact(); } else { Message.debug("no javadoc artifact found for " + mrid); } } } } private ResolvedModuleRevision parseOtherPom(ParserSettings ivySettings, ModuleRevisionId parentModRevID) throws ParseException { DependencyDescriptor dd = new DefaultDependencyDescriptor(parentModRevID, true); ResolveData data = IvyContext.getContext().getResolveData(); if (data == null) { ResolveEngine engine = IvyContext.getContext().getIvy().getResolveEngine(); ResolveOptions options = new ResolveOptions(); options.setDownload(false); data = new ResolveData(engine, options); } DependencyResolver resolver = ivySettings.getResolver(parentModRevID); if (resolver == null) { // TODO: Throw exception here? return null; } else { dd = NameSpaceHelper.toSystem(dd, ivySettings.getContextNamespace()); ResolvedModuleRevision otherModule = resolver.getDependency(dd, data); return otherModule; } } private ParseException newParserException(Exception e) { Message.error(e.getMessage()); ParseException pe = new ParseException(e.getMessage(), 0); pe.initCause(e); return pe; } }