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}