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}