package org.jboss.windup.rules.apps.java.archives.ignore; import java.io.File; import java.io.FileInputStream; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; import org.jboss.forge.addon.dependencies.Coordinate; import org.jboss.forge.addon.dependencies.builder.CoordinateBuilder; import org.jboss.forge.furnace.util.Assert; import org.jboss.forge.furnace.versions.EmptyVersionRange; import org.jboss.forge.furnace.versions.SingleVersion; import org.jboss.forge.furnace.versions.SingleVersionRange; import org.jboss.forge.furnace.versions.VersionRange; import org.jboss.forge.furnace.versions.Versions; import org.jboss.windup.rules.apps.java.archives.model.ArchiveCoordinateModel; import org.jboss.windup.util.exception.WindupException; /** * A service class keeping the set of skipped archives and handling their lookup. * * Data file format: GROUP_ID:ARTIFACT_ID:VERSION_OR_RANGE[:CLASSIFIER] * * Examples: org.apache.commons.*:*:* org.hibernate.*:hibernate-core:(3.2,4.0]:jar * * @author <a href="mailto:ozizka@redhat.com">Ondrej Zizka</a> * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> */ public class SkippedArchives { private static final Map<Coordinate, VersionRange> map = new HashMap<>(); /** * Load the given configuration file. */ public static void load(File file) { try(FileInputStream inputStream = new FileInputStream(file)) { LineIterator it = IOUtils.lineIterator(inputStream, "UTF-8"); while (it.hasNext()) { String line = it.next(); if (!line.startsWith("#") && !line.trim().isEmpty()) { add(line); } } } catch (Exception e) { throw new WindupException("Failed loading archive ignore patterns from [" + file.toString() + "]", e); } } public static void add(String line) { Assert.notNull(line, "Archive coordinate pattern must not be null."); CoordinatePattern pattern = fromCoordinatePattern(line); map.put(pattern.getCoordinate(), pattern.getVersion()); } static CoordinatePattern fromCoordinatePattern(String coordinates) { String[] parts = coordinates.split("\\s*:\\s*"); if (parts.length < 3) throw new IllegalArgumentException("Expected GAV definition format is 'GROUP_ID:ARTIFACT_ID:VERSION_OR_RANGE[:CLASSIFIER]', was: " + coordinates); CoordinateBuilder coordinate = CoordinateBuilder.create() .setGroupId(parts[0]) .setArtifactId(parts[1]); VersionRange version = null; if (parts[2].equals("*")) version = new EmptyVersionRange(); // Range - (1.0,2.0] or [1.0,2.0) etc. else if (parts[2].matches("^(\\[|\\()[^,]+(,[^,]+)?(\\]|\\))$")) version = Versions.parseMultipleVersionRange(parts[2]); else version = new SingleVersionRange(new SingleVersion(parts[2])); if (parts.length >= 4) coordinate.setClassifier(parts[3]); return new CoordinatePattern(coordinate, version); } public static boolean isSkipped(ArchiveCoordinateModel coordinate) { return isSkipped(CoordinateBuilder.create() .setArtifactId(coordinate.getArtifactId()) .setGroupId(coordinate.getGroupId()) .setClassifier(coordinate.getClassifier()) .setVersion(coordinate.getVersion())); } /* * Public for testing purposes */ public static boolean isSkipped(Coordinate coordinate) { for (Entry<Coordinate, VersionRange> entry : map.entrySet()) { Coordinate pattern = entry.getKey(); VersionRange range = entry.getValue(); if (isPatternMatch(pattern.getGroupId(), coordinate.getGroupId()) && isPatternMatch(pattern.getArtifactId(), coordinate.getArtifactId()) && isPatternMatch(pattern.getClassifier(), coordinate.getClassifier())) { if (range.isEmpty() || range.includes(new SingleVersion(coordinate.getVersion()))) return true; } } return false; } private static boolean isPatternMatch(String pattern, String value) { if ("*".equals(pattern)) return true; if(pattern == value) return true; if (pattern != null && pattern.equals(value)) return true; if (pattern != null && pattern.endsWith("*")) if (value != null && value.startsWith(pattern.substring(0, pattern.length() - 1))) return true; return false; } /* * Public for testing purposes. */ public static int getCount() { return map.size(); } private static class CoordinatePattern { private final CoordinateBuilder coordinate; private final VersionRange version; public CoordinatePattern(CoordinateBuilder coordinate, VersionRange version) { this.coordinate = coordinate; this.version = version; } public CoordinateBuilder getCoordinate() { return coordinate; } public VersionRange getVersion() { return version; } } }