001package com.ganteater.ae; 002 003import java.io.File; 004import java.io.IOException; 005import java.io.InputStream; 006import java.net.URL; 007import java.security.CodeSource; 008import java.util.ArrayList; 009import java.util.Enumeration; 010import java.util.List; 011import java.util.Properties; 012import java.util.Set; 013import java.util.jar.JarEntry; 014import java.util.jar.JarFile; 015 016import org.apache.commons.io.FileUtils; 017import org.apache.commons.io.FilenameUtils; 018import org.apache.commons.io.IOUtils; 019import org.apache.commons.lang.StringUtils; 020 021import com.ganteater.ae.util.xml.easyparser.EasyParser; 022import com.ganteater.ae.util.xml.easyparser.Node; 023 024public class RecipesScanner { 025 026 private AEWorkspace workspace; 027 028 private File startDir; 029 030 private List<String> fPriorityFolders = new ArrayList<String>(); 031 032 public RecipesScanner(AEWorkspace workspace, File startDir) { 033 super(); 034 this.startDir = startDir; 035 this.workspace = workspace; 036 } 037 038 public Properties scanRecipeSource(String path, Set<Object> skipNames) throws IOException { 039 040 CodeSource codeSource = getClass().getProtectionDomain().getCodeSource(); 041 URL location = codeSource.getLocation(); 042 String jarFile = location.toString(); 043 044 Properties aTestsDescList = new Properties(); 045 String extension = FilenameUtils.getExtension(jarFile); 046 if ("jar".equalsIgnoreCase(extension) || "zip".equalsIgnoreCase(extension)) { 047 if (StringUtils.startsWith(jarFile, "file:/")) { 048 jarFile = StringUtils.substringAfter(jarFile, "file:/").replace("%20", " "); 049 } 050 051 File file = new File(jarFile); 052 scanTasksJar(file, path, aTestsDescList, skipNames); 053 } 054 055 return aTestsDescList; 056 } 057 058 private void scanRecipeDir(String path, Properties aTestsDescList, Set<Object> skipNames) { 059 try { 060 String extension = StringUtils.substringAfterLast(path, "."); 061 File file = workspace.getFile(path); 062 if (file != null && file.exists()) { 063 if (file.isDirectory()) { 064 scanTasksDir(file, aTestsDescList, skipNames); 065 } else { 066 if ("jar".equalsIgnoreCase(extension) || "zip".equalsIgnoreCase(extension)) { 067 scanTasksJar(file, "", aTestsDescList, skipNames); 068 } else if ("recipe".equalsIgnoreCase(extension)) { 069 regTestFile(file.getAbsolutePath(), aTestsDescList, skipNames); 070 } 071 } 072 } else { 073 URL source = new URL(path); 074 075 String urlPath = StringUtils.substringBeforeLast(source.getPath(), "/"); 076 if (urlPath.startsWith("/")) { 077 urlPath = urlPath.substring(1); 078 } 079 String dirPath = "/recipes/" + source.getHost() + "/" + urlPath.replace("/", "-"); 080 File destination = new File(workspace.getHomeWorkingDir(), dirPath); 081 String urlFile = StringUtils.substringAfterLast(source.getFile(), "/"); 082 destination = new File(destination, urlFile); 083 if (!destination.exists()) { 084 URL url = new URL(path.replace(" ", "%20")); 085 FileUtils.copyURLToFile(url, destination); 086 } 087 String absolutePath = destination.getAbsolutePath(); 088 scanRecipeDir(absolutePath, aTestsDescList, skipNames); 089 } 090 }catch (Exception e) { 091 throw new IllegalArgumentException("Path: " + path, e); 092 } 093 } 094 095 private void scanTasksJar(File jar, String dir, Properties recipes, Set<Object> skipNames) throws IOException { 096 097 try (JarFile jarFile = new JarFile(jar)) { 098 099 Enumeration<?> jents = jarFile.entries(); 100 while (jents.hasMoreElements()) { 101 JarEntry entry = (JarEntry) jents.nextElement(); 102 103 String name = entry.getName(); 104 105 if (StringUtils.startsWith(name, dir)) { 106 if (!entry.isDirectory()) { 107 String spec = "jar:file:" + jar.getAbsolutePath() + "!/" + name.replace("#", "%23"); 108 regTestURL(new URL(spec), recipes, skipNames); 109 } 110 } 111 } 112 } 113 } 114 115 private void regTestURL(URL url, Properties aTestsDescList, Set<Object> skipNames) { 116 String name = url.toString(); 117 if (name.toLowerCase().endsWith(".recipe")) { 118 119 Node theNode = null; 120 try { 121 theNode = new EasyParser().getObject(url.openStream()); 122 123 if (!"Recipe".equals(theNode.getTag())) { 124 return; 125 } 126 127 String recipeName = theNode.getAttribute("name"); 128 129 if (!skipNames.contains(recipeName)) { 130 String theCurrentFile = aTestsDescList.getProperty(recipeName); 131 if (theCurrentFile != null && theCurrentFile.equals(url.toString()) == false) { 132 theCurrentFile = taskFileNameConflict(recipeName, theCurrentFile, url.toString()); 133 } else { 134 theCurrentFile = url.toString(); 135 } 136 aTestsDescList.setProperty(recipeName, theCurrentFile); 137 } 138 139 } catch (Exception e) { 140 e.printStackTrace(); 141 } 142 143 } 144 } 145 146 private Properties scanTasksDir(File aDir, Properties aTestsDescList, Set<Object> skipNames) throws IOException { 147 File[] theFiles = aDir.listFiles(); 148 149 if (theFiles == null) { 150 return aTestsDescList; 151 } 152 153 for (int i = 0; i < theFiles.length; i++) { 154 155 File file = theFiles[i]; 156 157 if (file.isDirectory()) { 158 scanRecipeDir(file.getAbsolutePath(), aTestsDescList, skipNames); 159 160 } else { 161 regTestFile(file.getAbsolutePath(), aTestsDescList, skipNames); 162 } 163 } 164 165 return aTestsDescList; 166 } 167 168 private void regTestFile(String file, Properties aTestsDescList, Set<Object> skipNames) { 169 file = file.replace('\\', '/'); 170 String name = StringUtils.substringAfterLast(file, "/"); 171 workspace.progressText(name); 172 173 if (name.toLowerCase().endsWith(".recipe")) { 174 175 Node theNode = null; 176 try { 177 178 File theXMLFile = new File(file); 179 if (theXMLFile.exists()) { 180 theNode = new EasyParser().getObject(theXMLFile); 181 } else { 182 String resourceName = "/" + file; 183 try (InputStream resourceAsStream = RecipesScanner.class.getResourceAsStream(resourceName)) { 184 String recipeXml = IOUtils.toString(resourceAsStream); 185 186 theNode = new EasyParser().getObject(recipeXml); 187 file = RecipesScanner.class.getResource(resourceName).toString(); 188 } 189 } 190 191 } catch (Exception e) { 192 e.printStackTrace(); 193 theNode = null; 194 } 195 196 if (theNode == null || "Recipe".equals(theNode.getTag()) == false) { 197 return; 198 } 199 200 String recipeName = theNode.getAttribute("name"); 201 if (!skipNames.contains(recipeName)) { 202 String theCurrentFile = aTestsDescList.getProperty(recipeName); 203 String predefinedFile = workspace.getTestsDescList().getProperty(recipeName); 204 if (predefinedFile == null) { 205 if (theCurrentFile != null && theCurrentFile.equals(file) == false) { 206 String conflictFile = file; 207 theCurrentFile = taskFileNameConflict(recipeName, theCurrentFile, conflictFile); 208 } else { 209 theCurrentFile = file; 210 } 211 } else { 212 theCurrentFile = predefinedFile; 213 } 214 aTestsDescList.setProperty(recipeName, theCurrentFile); 215 } 216 } 217 } 218 219 public String taskFileNameConflict(String aKey, String aCurrentFile, String aNewFile) { 220 StringBuilder theStringBuffer = new StringBuilder(); 221 222 theStringBuffer.append("Duplication file for task with name: '" + aKey + "'\n"); 223 theStringBuffer.append("Registration file: '" + aCurrentFile + "'\n"); 224 theStringBuffer.append("Conflict file: '" + aNewFile + "'\n"); 225 theStringBuffer.append("\n"); 226 theStringBuffer.append("Please select priority folder:\n"); 227 228 String theFirstFile = new File(aNewFile).getParent(); 229 String theSecondFile = new File(aCurrentFile).getParent(); 230 231 StringBuffer theMessageBuffer = new StringBuffer(); 232 theMessageBuffer.append("Duplication file for task with name: '" + aKey + "' "); 233 234 String thePriorityFolder = null; 235 if (fPriorityFolders.contains(theFirstFile)) { 236 thePriorityFolder = theFirstFile; 237 theMessageBuffer.append("presetting selection file: " + aNewFile); 238 } else if (fPriorityFolders.contains(theSecondFile)) { 239 thePriorityFolder = theSecondFile; 240 theMessageBuffer.append("presetting selection file: " + aCurrentFile); 241 } else { 242 String message = theStringBuffer.toString(); 243 String[] possibleValues = new String[] { aCurrentFile, aNewFile }; 244 245 thePriorityFolder = workspace.choicePriorityRecipeFolder(message, possibleValues); 246 247 theMessageBuffer.append("manual selection priority folder: " + thePriorityFolder); 248 } 249 250 fPriorityFolders.add(new File(thePriorityFolder).getParent()); 251 252 if (thePriorityFolder == null) { 253 StringBuffer fBuffer = new StringBuffer(); 254 fBuffer.append("Duplication file for task with name: '" + aKey + "': "); 255 fBuffer.append("Registration file: '" + aCurrentFile + "', "); 256 fBuffer.append("Conflict file: '" + aNewFile + "'"); 257 // log.warn(fBuffer.toString()); 258 throw new ConfigurationException(fBuffer.toString()); 259 } 260 261 if (theSecondFile != null && theSecondFile.equals(thePriorityFolder)) 262 aNewFile = aCurrentFile; 263 264 return aNewFile; 265 } 266 267 public File getStartDir() { 268 return startDir; 269 } 270 271 public List<String> getPriorityFolders() { 272 return fPriorityFolders; 273 } 274 275 public void setStartDir(File startDir) { 276 this.startDir = startDir; 277 } 278 279 public void loadTaskPath(Node configNode, TemplateProcessor tp) throws IOException { 280 Node[] recipesNodes = configNode.getNodes("Recipes"); 281 Properties testsDescList = workspace.getTestsDescList(); 282 for (int i = recipesNodes.length - 1; i >= 0; i--) { 283 Node node = recipesNodes[i]; 284 String path = node.getAttribute("path"); 285 path = tp.replaceProperties(path); 286 Properties aTestsDescList = new Properties(); 287 Set<Object> keySet = testsDescList.keySet(); 288 scanRecipeDir(path, aTestsDescList, keySet); 289 testsDescList.putAll(aTestsDescList); 290 291 Properties scanRecipeSource = scanRecipeSource(path, testsDescList.keySet()); 292 testsDescList.putAll(scanRecipeSource); 293 } 294 } 295 296}