/* * Copyright 2012 James Moger * * Licensed 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.moxie; import java.io.Serializable; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.moxie.utils.StringUtils; /** * Dependency represents a retrievable artifact. */ public class Dependency implements Serializable { private static final long serialVersionUID = 1L; public String groupId; public String artifactId; public String version; public String revision; public String type; public String extension; public String classifier; public boolean optional; public boolean apt; public boolean resolveDependencies; public Set<String> exclusions; public Set<String> tags; public int ring; public String origin; public Scope definedScope; public Dependency() { type = "jar"; extension = type; resolveDependencies = true; exclusions = new TreeSet<String>(); tags = new TreeSet<String>(); } public Dependency(String def) { String [] principals = def.trim().split(" "); String coordinates = StringUtils.stripQuotes(principals[0]); if (coordinates.indexOf('@') > -1) { // strip @ext extension = coordinates.substring(coordinates.indexOf('@') + 1); type = extension; coordinates = coordinates.substring(0, coordinates.indexOf('@')); resolveDependencies = false; } else { extension = "jar"; type = extension; resolveDependencies = true; } // determine Maven artifact coordinates String [] fields = { groupId, artifactId, version, classifier, extension }; // append trailing colon for custom splitting algorithm coordinates = coordinates + ":"; // custom string split for performance, blanks are considered null StringBuilder sb = new StringBuilder(); int field = 0; for (int i = 0, len = coordinates.length(); i < len; i++) { char c = coordinates.charAt(i); switch(c) { case ' ': break; case ':': fields[field] = sb.toString().trim(); if (fields[field].length() == 0) { fields[field] = null; } sb.setLength(0); field++; break; default: sb.append(c); break; } } this.groupId = fields[0].replace('/', '.'); this.artifactId = fields[1]; this.version = fields[2]; this.classifier = fields[3]; this.extension = fields[4]; // determine dependency options and transitive dependency exclusions exclusions = new TreeSet<String>(); tags = new TreeSet<String>(); Set<String> options = new TreeSet<String>(); for (String option : principals) { if (option.charAt(0) == '-' || option.charAt(0) == '!') { // exclusion exclusions.add(option.substring(1)); } else if (option.charAt(0) == '@') { // fixed extension retrieval extension = option.substring(1); resolveDependencies = false; } else if (option.charAt(0) == ':') { // tag tags.add(option.substring(1).toLowerCase()); } else if (option.charAt(0) == '#') { // comment break; } else { // option options.add(option.toLowerCase()); } } optional = options.contains("optional"); apt = options.contains("apt"); if (!isMavenObject()) { // forge dependency, filename is version field int dot = version.lastIndexOf('.'); if (dot > -1) { extension = version.substring(dot + 1); version = version.substring(0, dot); } } } public boolean isMavenObject() { return groupId.charAt(0) != '<'; } public boolean isSnapshot() { if (version == null) { throw new MoxieException(MessageFormat.format("Version is undefined for \"{0}\"!", getCoordinates())); } return version.contains("-SNAPSHOT"); } public boolean isMetaVersion() { return isRangedVersion() || isSnapshot() || version.equalsIgnoreCase(Constants.RELEASE) || version.equalsIgnoreCase(Constants.LATEST); } public boolean isRangedVersion() { return version.indexOf('[') > -1 || version.indexOf('(') > -1; } public boolean isJavaBinary() { return Constants.isJavaBinary(extension); } public Dependency getPomArtifact() { Dependency pom = new Dependency(getDetailedCoordinates()); pom.revision = revision; pom.extension = Constants.POM; return pom; } public Dependency getSourcesArtifact() { Dependency sources = new Dependency(getDetailedCoordinates()); sources.revision = revision; sources.classifier = "sources"; return sources; } public Dependency getJavadocArtifact() { Dependency javadoc = new Dependency(getDetailedCoordinates()); javadoc.revision = revision; javadoc.classifier = "javadoc"; return javadoc; } public String getGroupId() { return groupId; } public String getArtifactId() { return artifactId; } public String getVersion() { return version; } public String getMediationId() { return groupId + ":" + artifactId + (classifier == null ? "" : (":" + classifier)) + ":" + extension; } public String getManagementId() { return groupId + ":" + artifactId; } public String getCoordinates() { return groupId + ":" + artifactId + ":" + version; } public String getDetailedCoordinates() { return groupId + ":" + artifactId + ":" + version + ":" + (classifier == null ? "" : classifier) + ":" + extension; } public String getPrefix() { String [] chunks = groupId.split("\\."); if (chunks.length < 2) { // single path return "/" + chunks[0]; } else { // add first two paths return "/" + chunks[0] + "/" + chunks[1]; } } public boolean excludes(Dependency dependency) { return exclusions.contains(dependency.getMediationId()) || exclusions.contains(dependency.getManagementId()) || exclusions.contains(dependency.groupId) || exclusions.contains("*:*") || exclusions.contains("*"); } public String getOrigin() { return origin; } public void setOrigin(String origin) { this.origin = origin; } @Override public int hashCode() { return getDetailedCoordinates().hashCode(); } @Override public boolean equals(Object o) { if (o instanceof Dependency) { return hashCode() == o.hashCode(); } return false; } @Override public String toString() { return getDetailedCoordinates() + (resolveDependencies ? " transitive":"") + (optional ? " optional":""); } public String toXML(Scope scope) { StringBuilder sb = new StringBuilder(); sb.append("<dependency>\n"); sb.append(StringUtils.toXML("groupId", groupId)); sb.append(StringUtils.toXML("artifactId", artifactId)); sb.append(StringUtils.toXML("version", version)); sb.append(StringUtils.toXML("type", type)); if (!StringUtils.isEmpty(classifier)) { sb.append(StringUtils.toXML("classifier", classifier)); } sb.append(StringUtils.toXML("scope", scope)); if (optional) { sb.append(StringUtils.toXML("optional", true)); } Set<String> excludes = new TreeSet<String>(exclusions); if (!resolveDependencies) { excludes.add("*:*"); } if (excludes.size() > 0) { StringBuilder nodelist = new StringBuilder(); nodelist.append("<exclusions>\n"); for (String exclusion : excludes) { StringBuilder node = new StringBuilder(); node.append("<exclusion>\n"); String [] e = exclusion.split(":"); node.append(StringUtils.toXML("groupId", e[0])); if (e.length > 1) { node.append(StringUtils.toXML("artifactId", e[1])); } node.append("</exclusion>\n"); nodelist.append(StringUtils.insertHalfTab(node.toString())); } nodelist.append("</exclusions>\n"); sb.append(StringUtils.insertHalfTab(nodelist.toString())); } sb.append("</dependency>\n"); return sb.toString(); } public static String getArtifactPath(Dependency dep, String ext, String pattern) { return getPath(dep, ext, pattern, true); } public static String getFilename(Dependency dep, String ext, String pattern) { return getPath(dep, ext, pattern, false); } private static String getPath(Dependency dep, String ext, String pattern, boolean splitGroupId) { Map<String, String> optionals = new HashMap<String, String>(); String newpattern = pattern; int op = -1; while ((op = pattern.indexOf('(', op + 1)) > -1) { int cp = pattern.indexOf(')', op) + 1; if (cp > 0) { String s = pattern.substring(op, cp); int ob = s.indexOf('['); int cb = s.indexOf(']', ob) + 1; String field = s.substring(ob, cb); optionals.put(field, s.substring(1, s.length() - 1)); newpattern = newpattern.replace(s, field); } } String url = newpattern; if (splitGroupId) { // Maven-style: groupId is split into paths url = replace(url, "[groupId]", dep.groupId.replace('.', '/'), optionals); } else { // Ivy-style: groupId is left in dot-notation url = replace(url, "[groupId]", dep.groupId, optionals); } url = replace(url, "[artifactId]", dep.artifactId, optionals); url = replace(url, "[version]", dep.version, optionals); url = replace(url, "[revision]", StringUtils.isEmpty(dep.revision) ? dep.version : dep.revision, optionals); if (ext != null && ext.equalsIgnoreCase(Constants.POM)) { // POMs do not have classifiers url = url.replace("[classifier]", ""); } else { url = replace(url, "[classifier]", dep.classifier, optionals); } if (ext != null) { url = replace(url, "[ext]", ext, optionals); } return url; } private static String replace(String target, String key, String value, Map<String, String> substitutes) { String newtarget; if (StringUtils.isEmpty(value)) { newtarget = target.replace(key, ""); } else if (substitutes.containsKey(key)) { String sub = substitutes.get(key).replace(key, value); newtarget = target.replace(key, sub); } else { newtarget = target.replace(key, value); } return newtarget; } }