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.Enumeration; 011import java.util.List; 012import java.util.Properties; 013import java.util.Set; 014import java.util.zip.ZipEntry; 015import java.util.zip.ZipFile; 016 017import org.apache.commons.io.FileUtils; 018import org.apache.commons.io.FilenameUtils; 019import org.apache.commons.io.IOUtils; 020import org.apache.commons.lang.StringUtils; 021 022import com.ganteater.ae.util.xml.easyparser.EasyParser; 023import com.ganteater.ae.util.xml.easyparser.Node; 024 025public class RecipesScanner { 026 027 private AEWorkspace workspace; 028 029 private File startDir; 030 031 private List<String> fPriorityFolders = new ArrayList<String>(); 032 033 public RecipesScanner(AEWorkspace workspace, File startDir) { 034 super(); 035 this.startDir = startDir; 036 this.workspace = workspace; 037 } 038 039 public Properties scanRecipeSource(String path, Set<Object> skipNames) throws IOException { 040 041 CodeSource codeSource = getClass().getProtectionDomain().getCodeSource(); 042 URL location = codeSource.getLocation(); 043 String jarFile = location.toString(); 044 045 Properties aTestsDescList = new Properties(); 046 String extension = FilenameUtils.getExtension(jarFile); 047 if ("jar".equalsIgnoreCase(extension) || "zip".equalsIgnoreCase(extension)) { 048 if (StringUtils.startsWith(jarFile, "file:/")) { 049 jarFile = StringUtils.substringAfter(jarFile, "file:/").replace("%20", " "); 050 } 051 052 File file = new File(jarFile); 053 scanTasksJar(file, path, aTestsDescList, skipNames); 054 } 055 056 return aTestsDescList; 057 } 058 059 private void scanRecipeDir(String path, Properties aTestsDescList, Set<Object> skipNames) throws IOException { 060 try { 061 URL source = new URL(path); 062 String urlPath = StringUtils.substringBeforeLast(source.getPath(), "/"); 063 if (urlPath.startsWith("/")) { 064 urlPath = urlPath.substring(1); 065 } 066 String dirPath = "/recipes/" + source.getHost() + "/" + urlPath.replace("/", "-"); 067 File destination = new File(workspace.getHomeWorkingDir(), dirPath); 068 String urlFile = StringUtils.substringAfterLast(source.getFile(), "/"); 069 destination = new File(destination, urlFile); 070 if (!destination.exists()) { 071 URL url = new URL(path.replace(" ", "%20")); 072 FileUtils.copyURLToFile(url, destination); 073 } 074 String absolutePath = destination.getAbsolutePath(); 075 scanRecipeDir(absolutePath, aTestsDescList, skipNames); 076 077 } catch (MalformedURLException e) { 078 String extension = StringUtils.substringAfterLast(path, "."); 079 File file = workspace.getFile(path); 080 081 if (file.isDirectory()) { 082 scanTasksDir(file, aTestsDescList, skipNames); 083 } else { 084 if ("jar".equalsIgnoreCase(extension) || "zip".equalsIgnoreCase(extension) 085 || StringUtils.contains(path, ".zip")) { 086 scanTasksJar(file, "", aTestsDescList, skipNames); 087 } else if ("recipe".equalsIgnoreCase(extension)) { 088 regTestFile(file.getAbsolutePath(), aTestsDescList, skipNames); 089 } 090 } 091 } 092 } 093 094 private void scanTasksJar(final File jar, final String dir, final Properties recipes, final Set<Object> skipNames) 095 throws IOException { 096 097 try (ZipFile jarFile = new ZipFile(jar)) { 098 jarFile.stream().forEach(entry -> { 099 String name = entry.getName(); 100 if (name.startsWith(dir) && !entry.isDirectory()) { 101 try (InputStream inputStream = jarFile.getInputStream(entry)) { 102 URL url = new URL("jar:file:" + jar.getAbsolutePath() + "!/" + name); 103 regTestURL(url.toString(), inputStream, recipes, skipNames); 104 } catch (IOException e) { 105 e.printStackTrace(); 106 } 107 } 108 }); 109 } 110 111 } 112 113 private void regTestURL(String name, InputStream entityStream, Properties aTestsDescList, Set<Object> skipNames) { 114 if (name.toLowerCase().endsWith(".recipe")) { 115 116 Node theNode = null; 117 try { 118 theNode = new EasyParser().getObject(entityStream); 119 120 if (!"Recipe".equals(theNode.getTag())) { 121 return; 122 } 123 124 String recipeName = theNode.getAttribute("name"); 125 126 if (!skipNames.contains(recipeName)) { 127 String theCurrentFile = aTestsDescList.getProperty(recipeName); 128 if (theCurrentFile != null && theCurrentFile.equals(name) == false) { 129 theCurrentFile = taskFileNameConflict(recipeName, theCurrentFile, name); 130 } else { 131 theCurrentFile = name; 132 } 133 aTestsDescList.setProperty(recipeName, theCurrentFile); 134 } 135 136 } catch (Exception e) { 137 e.printStackTrace(); 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 System.out.println("Incorrect file: " + file + ", Error: " + e.getMessage()); 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 if (recipesNodes.length == 0) { 278 recipesNodes = new Node[] { new EasyParser().getObject("<Recipes path=\"recipes\" />") }; 279 } 280 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}