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