package org.handwerkszeug.mvnhack.repository.impl; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.handwerkszeug.common.util.Streams; import org.handwerkszeug.common.util.StringUtil; import org.handwerkszeug.common.util.XMLEventParser; import org.handwerkszeug.common.util.XMLEventParser.DefaultHandler; import org.handwerkszeug.mvnhack.Constants; import org.handwerkszeug.mvnhack.repository.Artifact; import org.handwerkszeug.mvnhack.repository.ArtifactBuilder; import org.handwerkszeug.mvnhack.repository.Context; public class StAXArtifactBuilder implements ArtifactBuilder { @Override public Artifact build(Context context, InputStream pom) { DefaultArtifact result = new DefaultArtifact(); try { XMLEventParser parser = new XMLEventParser(pom); addArtifactParseHandlers(parser, result); parser.add(new DefaultHandler("project")); parser.add(new Type(result, "packaging")); Parent parent = new Parent(); parser.add(parent); parser.add(new Dependencies(result)); Set<Artifact> managed = new HashSet<Artifact>(); parser.add(new DependencyManagement(managed)); try { parser.parse(); } finally { Streams.close(pom); } resolveParent(context, parent.getArtifact()); reconcile(context, result, parent, managed); if (validate(result)) { return result; } } catch (Exception e) { Constants.LOG.log(Level.WARNING, e.getMessage(), e); } return null; } protected void resolveParent(Context context, Artifact parent) { if (validate(parent)) { context.resolve(parent.getGroupId(), parent.getArtifactId(), parent .getVersion()); } } protected void reconcile(Context context, DefaultArtifact result, Parent parent, Set<Artifact> managed) { Map<String, String> m = new HashMap<String, String>(); putContextValues(m, parent.getArtifact(), "parent."); reconcileProject(parent.getArtifact(), result, m); reconcileDependencies(context, result, managed, m); } protected void putContextValues(Map<String, String> m, Artifact a, String prefix) { m.put(prefix + "groupId", a.getGroupId()); m.put(prefix + "artifactId", a.getArtifactId()); m.put(prefix + "version", a.getVersion()); } protected void reconcileProject(Artifact parent, DefaultArtifact project, Map<String, String> m) { reconcile(project, project, m); if (StringUtil.isEmpty(project.getGroupId())) { project.setGroupId(parent.getGroupId()); } if (StringUtil.isEmpty(project.getArtifactId())) { project.setArtifactId(parent.getArtifactId()); } if (StringUtil.isEmpty(project.getVersion())) { project.setVersion(parent.getVersion()); } putContextValues(m, project, ""); putContextValues(m, project, "pom."); putContextValues(m, project, "project."); } protected void reconcile(Artifact src, DefaultArtifact dest, Map<String, String> m) { dest.setGroupId(StringUtil.replace(src.getGroupId(), m)); dest.setArtifactId(StringUtil.replace(src.getArtifactId(), m)); dest.setVersion(StringUtil.replace(src.getVersion(), m)); } protected void reconcileDependencies(Context context, DefaultArtifact project, Set<Artifact> managed, Map<String, String> m) { for (Artifact a : managed) { DefaultArtifact newone = new DefaultArtifact(); reconcile(a, newone, m); context.addManagedDependency(newone); } List<Artifact> copy = new ArrayList<Artifact>(project.getDependencies()); project.dependencies.clear(); for (Artifact a : copy) { DefaultArtifact newone = new DefaultArtifact(); reconcile(a, newone, m); if (StringUtil.isEmpty(newone.getVersion())) { newone.setVersion(context.getManagedDependency(a)); } // in the case of RELEASE , // get maven-metadata.xml from repository and find <release> if (validate(newone)) { String v = newone.getVersion(); if ("RELEASE".equals(v) || 0 < v.indexOf('[')) { Constants.LOG .log(Level.INFO, "Unsupported Versioning " + v); } else { project.add(newone); } } } } protected boolean validate(Artifact a) { return validate(a.getGroupId(), a.getArtifactId(), a.getVersion()); } protected boolean validate(String... ids) { for (String s : ids) { if (StringUtil.isEmpty(s)) { return false; } } return true; } protected void addArtifactParseHandlers(XMLEventParser parser, DefaultArtifact a) { parser.add(new GroupId(a)); parser.add(new ArtifactId(a)); parser.add(new Version(a)); } protected class GroupId extends DefaultHandler { protected DefaultArtifact a; protected GroupId(DefaultArtifact a) { super("groupId"); this.a = a; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { a.setGroupId(reader.getElementText()); } } protected class ArtifactId extends DefaultHandler { protected DefaultArtifact a; protected ArtifactId(DefaultArtifact a) { super("artifactId"); this.a = a; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { a.setArtifactId(reader.getElementText()); } } protected class Version extends DefaultHandler { protected DefaultArtifact a; protected Version(DefaultArtifact a) { super("version"); this.a = a; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { a.setVersion(reader.getElementText()); } } protected class Type extends DefaultHandler { protected DefaultArtifact a; protected Type(DefaultArtifact a) { this(a, "type"); } protected Type(DefaultArtifact a, String tag) { super(tag); this.a = a; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { a.setType(reader.getElementText()); } } protected class Parent extends DefaultHandler { protected DefaultArtifact a; protected Parent() { super("parent"); this.a = new DefaultArtifact(); } public Artifact getArtifact() { return this.a; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { XMLEventParser parser = new XMLEventParser(reader); addArtifactParseHandlers(parser, a); parser.parse(getTagName()); } } protected class Dependencies extends DefaultHandler { protected DefaultArtifact project; protected Dependencies(DefaultArtifact project) { super("dependencies"); this.project = project; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { XMLEventParser parser = new XMLEventParser(reader); parser.add(new Dependency(this.project)); parser.parse(getTagName()); } } protected class Dependency extends DefaultHandler { protected DefaultArtifact project; protected Dependency(DefaultArtifact a) { super("dependency"); this.project = a; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { DefaultArtifact newone = new DefaultArtifact(); XMLEventParser parser = new XMLEventParser(reader); addArtifactParseHandlers(parser, newone); parser.add(new Type(newone)); Scope scope = new Scope(); parser.add(scope); Optional optional = new Optional(newone); parser.add(optional); parser.parse(getTagName()); if (scope.isNotTest() && newone.isOptional() == false) { this.project.add(newone); } } } protected class Scope extends DefaultHandler { protected String scope; protected Scope() { super("scope"); } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { this.scope = reader.getElementText(); } protected boolean isNotTest() { return StringUtil.isEmpty(scope) || "test".equalsIgnoreCase(scope) == false; } } protected class Optional extends DefaultHandler { protected DefaultArtifact a; protected Optional(DefaultArtifact a) { super("optional"); this.a = a; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { String optional = reader.getElementText(); a.setOptional(isOptional(optional)); } protected boolean isOptional(String optional) { return StringUtil.isEmpty(optional) == false && Boolean.parseBoolean(optional); } } protected class DependencyManagement extends DefaultHandler { protected Set<Artifact> managed; protected DependencyManagement(Set<Artifact> managed) { super("dependencyManagement"); this.managed = managed; } @Override public void handle(XMLStreamReader reader) throws XMLStreamException { XMLEventParser parser = new XMLEventParser(reader); DefaultArtifact newone = new DefaultArtifact(); parser.add(new Dependencies(newone)); parser.parse(getTagName()); for (Artifact a : newone.getDependencies()) { if (validate(a)) { this.managed.add(a); } } } } }