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