blob: f4d6206f8651d0d01b3839bba39e0308a38de4ff [file] [log] [blame]
/*
* 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.License;
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.
* <p>
* The configurations used in the generated module descriptor mimics the behavior defined by maven 2
* scopes, as documented here:<br/>
* 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());
// if this module doesn't have an explicit license, use the parent's license (if any)
final License[] licenses = domReader.getLicenses();
if (licenses != null && licenses.length > 0) {
mdBuilder.setLicenses(licenses);
} else {
if (parentDescr != null) {
mdBuilder.setLicenses(parentDescr.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 /* <PomDependencyMgt> */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;
}
}