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