1 package de.matthias_burbach.deputy.core.repository; 2 3 import java.io.File; 4 import java.util.ArrayList; 5 import java.util.Collections; 6 import java.util.HashMap; 7 import java.util.HashSet; 8 import java.util.List; 9 import java.util.Map; 10 import java.util.Set; 11 12 import org.jdom.Document; 13 import org.jdom.Element; 14 import org.jdom.xpath.XPath; 15 16 /*** 17 * Scans a given path and group id for all POMs of this group and returns 18 * all artifact ids of that group available there. 19 * 20 * @author Matthias Burbach 21 */ 22 public class ArtifactScanner { 23 /*** 24 * A temporary table to speed up the list method on a directory. 25 * Maps dir names of type {@link java.lang.String} to file name arrays of 26 * type String[]. 27 */ 28 private Map fileListMap = new HashMap(); 29 30 /*** 31 * The cache for lists of artifact ids that have been returned already, 32 * keyed by the group directories. 33 */ 34 private static Map resultCache = new HashMap(); 35 36 /*** 37 * Clears the internal cache of already scanned artifacts. 38 * The cache is shared by all instances of this class. 39 */ 40 public static void clearCache() { 41 resultCache = new HashMap(); 42 } 43 44 /*** 45 * Scans a given group directory for all artifact ids of the group.<br/> 46 * Returns the result from a local cache if possible. 47 * 48 * @param groupDir The absolute file system path of a group directory to 49 * scan for all artifact ids of the group. 50 * @return The list of artifact ids of type {@link String}. 51 * Is never <code>null</code>. 52 */ 53 public List getAllArtifactIds(final String groupDir) { 54 final String key = groupDir; 55 List result = (List) resultCache.get(key); 56 if (result == null) { 57 result = doGetAllArtifactIds(groupDir); 58 if (result != null) { 59 Collections.sort(result); 60 resultCache.put(key, result); 61 } 62 } 63 return result; 64 } 65 66 /*** 67 * Scans a given group directory for all artifact ids of the group.<br/> 68 * 69 * @param groupDir The absolute file system path of a group directory to 70 * scan for all artifact ids of the group. 71 * @return The list of artifact ids of type {@link String}. 72 * Is never <code>null</code>. 73 */ 74 private List doGetAllArtifactIds(final String groupDir) { 75 Set result = new HashSet(); 76 File pomsDir = new File(groupDir + File.separator + "poms"); 77 if (pomsDir.isDirectory()) { 78 String[] fileNames = list(pomsDir); 79 for (int i = 0; i < fileNames.length; i++) { 80 String fileName = fileNames[i]; 81 if (!isExcludedFileName(fileName)) { 82 String artifactId = 83 extractArtifactId(pomsDir.getAbsolutePath(), fileName); 84 if (artifactId != null 85 && fileName.startsWith(artifactId)) { 86 result.add(artifactId); 87 } 88 } 89 } 90 } 91 return new ArrayList(result); 92 } 93 94 /*** 95 * Loads and parses the POM XML document and returns the artifact id. 96 * 97 * @param path The absolute file system path of the file to parse 98 * without the file name. 99 * @param fileName The simple name of the file to parse. 100 * @return The artifact id parsed or null in case of any failure. 101 */ 102 private String extractArtifactId(final String path, final String fileName) { 103 String result = null; 104 if (fileName.startsWith("vrp-") && fileName.indexOf("SNAPSHOT") == -1) { 105 result = extractArtifactIdFromFileName(fileName); 106 } else { 107 Document document = PomLoader.getInstance().loadPom( 108 path + File.separator + fileName); 109 try { 110 result = parseElementText(document, "project/artifactId"); 111 } catch (Exception e) { 112 e.printStackTrace(); 113 } 114 } 115 return result; 116 } 117 118 /*** 119 * Optimizes overall performance by assuming that the file name is composed 120 * as artifactId-version.pom and that the version does not contain a '-'. 121 * 122 * @param fileName The file name to extract the artifact id from. 123 * @return The artifact id extracted. 124 */ 125 private String extractArtifactIdFromFileName(final String fileName) { 126 int artifactEndIndex = fileName.lastIndexOf("-"); 127 String result = fileName.substring(0, artifactEndIndex); 128 return result; 129 } 130 131 /*** 132 * Tries to parse the element named <code>elementName.</code>. 133 * 134 * @param xmlNode The XML node to that contains the element to parse. 135 * @param elementName The name of the element to parse. 136 * @return The contents of the element to parse or <code>null</code>. 137 * @throws Exception if anything goes unexpectedly wrong 138 */ 139 private String parseElementText( 140 final Object xmlNode, 141 final String elementName) 142 throws Exception { 143 Element element = 144 (Element) XPath.newInstance(elementName).selectSingleNode(xmlNode); 145 String result = null; 146 if (element != null) { 147 result = element.getText(); 148 } 149 return result; 150 } 151 152 /*** 153 * @param fileName The simple name of the file to check. 154 * @return <code>true</code> if the fileName is to be excluded from the 155 * artifact id scanning 156 */ 157 private boolean isExcludedFileName(final String fileName) { 158 boolean result = true; 159 String candidate = fileName.toLowerCase(); 160 if (candidate.endsWith(".pom") 161 && !candidate.endsWith("openedition.pom") 162 && candidate.indexOf("snapshot-") == -1) { 163 result = false; 164 } 165 return result; 166 } 167 168 /*** 169 * Returns a cached result of list performed on file, if 170 * available. Invokes the method and caches the result otherwise. 171 * 172 * @param dir A directory to list the contents of. 173 * @return The array of files and dirs in the directory. 174 */ 175 private String[] list(final File dir) { 176 String[] files = (String[]) fileListMap.get(dir); 177 if (files == null) { 178 files = dir.list(); 179 if (files != null) { 180 fileListMap.put(dir, files); 181 } 182 } 183 return files; 184 } 185 }