001package com.ganteater.ae;
002
003import java.awt.Color;
004import java.awt.Toolkit;
005import java.io.BufferedReader;
006import java.io.Console;
007import java.io.File;
008import java.io.FileInputStream;
009import java.io.FileOutputStream;
010import java.io.IOException;
011import java.io.InputStream;
012import java.io.InputStreamReader;
013import java.io.UnsupportedEncodingException;
014import java.lang.reflect.Method;
015import java.lang.reflect.Modifier;
016import java.net.Authenticator;
017import java.net.Inet4Address;
018import java.net.InetAddress;
019import java.net.NetworkInterface;
020import java.net.PasswordAuthentication;
021import java.net.SocketException;
022import java.net.URL;
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.Base64;
026import java.util.Enumeration;
027import java.util.HashMap;
028import java.util.HashSet;
029import java.util.Iterator;
030import java.util.LinkedHashMap;
031import java.util.List;
032import java.util.Locale;
033import java.util.Map;
034import java.util.Properties;
035import java.util.Set;
036import java.util.regex.Pattern;
037
038import org.apache.commons.collections.CollectionUtils;
039import org.apache.commons.collections.MapUtils;
040import org.apache.commons.io.IOUtils;
041import org.apache.commons.lang.ArrayUtils;
042import org.apache.commons.lang.BooleanUtils;
043import org.apache.commons.lang.ObjectUtils;
044import org.apache.commons.lang.StringUtils;
045import org.apache.commons.lang.SystemUtils;
046import org.apache.log4j.PropertyConfigurator;
047
048import com.ganteater.ae.processor.BaseProcessor;
049import com.ganteater.ae.processor.MessageHandler;
050import com.ganteater.ae.processor.Processor;
051import com.ganteater.ae.processor.SpecialCommands;
052import com.ganteater.ae.util.AEUtils;
053import com.ganteater.ae.util.Encryptor;
054import com.ganteater.ae.util.xml.easyparser.EasyParser;
055import com.ganteater.ae.util.xml.easyparser.Node;
056
057public class AEWorkspace implements AEManager {
058
059        public static final String CONFIGURATION_TITLE = "Configuration";
060
061        public static final String ENVIRONMENT_FILE_TITLE = "Environment file";
062
063        public static final String MESSAGE_PASSWORD_REQUIRED = "This configuration requires encryption for user preferences data.\nEnter the encryption password: ";
064
065        public static final String CONFIG_SUFIX_PROP_NAME = ".config";
066
067        private static ILogger log = new Logger("AEWorkspace");
068
069        private static String fUser = System.getProperty("user.name");
070
071        private static Properties fUserPreferences;
072
073        private long startTime = System.currentTimeMillis();
074
075        private Node allConfigNode;
076
077        private Map<String, Object> fSystemVariables = new HashMap<>();
078
079        private Node fConfigNode;
080
081        private Properties fTestsDescList = new Properties();
082
083        protected boolean defaultMode;
084
085        private String fConfigurationName;
086
087        private Set<RecipeRunner> runners = new HashSet<RecipeRunner>();
088
089        private File baseDir = SystemUtils.getUserDir();
090
091        private static AEWorkspace instance;
092
093        private Set<Class<?>> operationsClasses;
094
095        private Map<String, OperationHolder> opsMethods = new HashMap<String, OperationHolder>();
096
097        private Encryptor cryptoUtilAesGcm;
098
099        private List<Runnable> closeHooks = new ArrayList<>();
100
101        private RecipesScanner recipesScaner;
102
103        public AEWorkspace() {
104                this(new File(System.getProperty("user.dir")));
105        }
106
107        public AEWorkspace(File startDir) {
108                instance = this;
109                System.out.println("Start dir: " + startDir);
110                recipesScaner = new RecipesScanner(this, startDir);
111        }
112
113        public String loadConfiguration(String confName, boolean refreshTaskPath) {
114                getHomeConfigurationsDir().mkdirs();
115                File homeConfiguration = new File(getHomeConfigurationsDir(), ConfigConstants.AE_CONFIG_XML);
116
117                if (homeConfiguration.exists()) {
118                        System.out.println("User home configuration file: " + homeConfiguration.getAbsolutePath() + " - found");
119                }
120
121                Node configNodes;
122                try {
123                        configNodes = getConfiguration();
124
125                        String config = selectConfiguration(confName, configNodes, refreshTaskPath);
126                        TemplateProcessor tp = new TemplateProcessor(fSystemVariables, fConfigNode, getStartDir());
127                        recipesScaner.loadTaskPath(fConfigNode, tp);
128
129                        String password = System.getProperty("configEncriptKey");
130                        initUserPreferencesEncryption(password);
131                        return config;
132
133                } catch (TaskCancelingException e) {
134                        throw e;
135
136                } catch (Exception e) {
137                        throw new ConfigurationException("Configuration loading failed.", e);
138                }
139
140        }
141
142        protected Node getConfiguration() throws IOException {
143                Node configuration = null;
144                File configFile = getConfigurationFile();
145
146                if (configFile == null || !configFile.exists()) {
147
148                        try (InputStream openStream = AEWorkspace.class.getResourceAsStream("/" + ConfigConstants.AE_CONFIG_XML)) {
149                                if (openStream != null) {
150                                        String recipeXml = IOUtils.toString(openStream);
151                                        try {
152                                                configuration = new EasyParser().getObject(recipeXml);
153                                        } catch (Exception e) {
154                                                throw new IllegalArgumentException(recipeXml, null);
155                                        }
156                                } else {
157
158                                        File userDir = getBaseDir();
159                                        String confPropName = userDir.getPath() + CONFIG_SUFIX_PROP_NAME;
160                                        String config = AEWorkspace.getInstance().getDefaultUserConfiguration(confPropName,
161                                                        userDir.getAbsolutePath());
162                                        config = inputValue(ENVIRONMENT_FILE_TITLE, null, config, null, null);
163                                        AEWorkspace.getInstance().setDefaultUserConfiguration(confPropName, config);
164
165                                        configFile = new File(config);
166                                }
167                        }
168                }
169
170                if (configuration == null) {
171                        if (configFile != null && configFile.exists()) {
172                                this.baseDir = configFile.getParentFile();
173                                System.out.println(ENVIRONMENT_FILE_TITLE + ": " + configFile.getAbsolutePath());
174
175                                configuration = new EasyParser().getObject(configFile);
176                        } else {
177                                throw new ConfigurationException(ENVIRONMENT_FILE_TITLE + " (" + ConfigConstants.AE_CONFIG_XML
178                                                + ") must be defined in " + getHomeWorkingDir() + " or " + getStartDir() + ".");
179                        }
180                }
181
182                return configuration;
183        }
184
185        protected File getConfigurationFile() {
186                File confFile;
187
188                String theConfigurationFile = System.getProperty(ConfigConstants.AE_CONFIG_SYS_PROPERTY_NAME);
189                if (theConfigurationFile == null) {
190                        confFile = new File(SystemUtils.getUserDir(), ConfigConstants.AE_CONFIG_XML);
191                        if (!confFile.exists()) {
192                                confFile = new File(getHomeWorkingDir(), ConfigConstants.AE_CONFIG_XML);
193                                if (!confFile.exists()) {
194                                        confFile = new File(getStartDir(), ConfigConstants.AE_CONFIG_XML);
195                                }
196                        }
197                } else {
198                        confFile = new File(theConfigurationFile);
199                }
200
201                if (!confFile.exists()) {
202                        URL resource = AEWorkspace.class.getResource("/" + ConfigConstants.AE_CONFIG_XML);
203                        if (resource == null) {
204                                confFile = findAlternativeConfiguration();
205                        } else {
206                                confFile = new File(resource.toString());
207                        }
208                }
209
210                return confFile;
211        }
212
213        protected File findAlternativeConfiguration() {
214                return null;
215        }
216
217        public File getHomeWorkingDir() {
218                return new File(System.getProperty("user.home"), "anteater");
219        }
220
221        private void configuration() {
222                if (fConfigNode != null) {
223                        Node[] theLogNodes = fConfigNode.getNodes("Logger");
224                        if (!ArrayUtils.isEmpty(theLogNodes)) {
225                                Node logNode = theLogNodes[theLogNodes.length - 1];
226                                initLogger(logNode);
227                        }
228                }
229
230                final String username = (String) fSystemVariables.get("HTTP_USERNAME");
231                final String password = (String) fSystemVariables.get("HTTP_PASSWORD");
232                if (username != null && password != null) {
233                        Authenticator.setDefault(new Authenticator() {
234                                protected PasswordAuthentication getPasswordAuthentication() {
235                                        return new PasswordAuthentication(username, password.toCharArray());
236                                }
237                        });
238                }
239        }
240
241        protected String choicePriorityRecipeFolder(String text, String[] possibleValues) {
242                String result = inputChoice(text, null, possibleValues, possibleValues[0], null, false);
243                return result;
244        }
245
246        public void runSetupNodes() throws Exception {
247                if (!Boolean.valueOf(System.getProperty("skip.startup"))) {
248                        Node[] theNodes = fConfigNode.getNodes(SpecialCommands.STARTUP);
249                        TemplateProcessor tp = new TemplateProcessor(fSystemVariables, fConfigNode, getStartDir());
250                        if (theNodes != null) {
251                                for (Node node : theNodes) {
252                                        final String theAttribut = tp.replaceProperties(node.getAttribute("task"));
253                                        boolean async = false;
254                                        String asyncValue = tp.replaceProperties(node.getAttribute("async"));
255                                        if (asyncValue != null) {
256                                                async = Boolean.valueOf(asyncValue);
257                                        }
258                                        if (theAttribut != null) {
259                                                runTask(theAttribut, async);
260                                        } else {
261                                                RecipeRunner taskEditor = createTestRunner(null);
262                                                taskEditor.runTest(new Node[] { node });
263                                        }
264                                }
265                        }
266                }
267        }
268
269        private void loadCustomProperties() {
270                if (fUserPreferences == null) {
271                        fUserPreferences = new Properties();
272
273                        // loading users preferences
274                        File preferencesFile = getPreferencesFile();
275                        try {
276                                FileInputStream fileInputStream = new FileInputStream(preferencesFile);
277                                fUserPreferences.load(fileInputStream);
278                                fileInputStream.close();
279
280                        } catch (IOException e) {
281                                // System.out.println("User preferences configuration file is not found: " +
282                                // preferencesFile);
283                        }
284                }
285        }
286
287        protected File getPreferencesFile() {
288                String configurationName = getConfigurationName();
289                String fileName;
290                if (configurationName != null) {
291                        fileName = configurationName + ".properties";
292                } else {
293                        fileName = "configuration/user.properties";
294                }
295                return new File(getHomeWorkingDir(), fileName);
296        }
297
298        public String getCustomConfPropFileName(String configurationName) {
299                return getHomeConfigurationsDir() + "/" + fUser + "." + configurationName + ".properties";
300        }
301
302        public File getHomeConfigurationsDir() {
303                File file = new File(getHomeWorkingDir(), "configuration");
304                return file;
305        }
306
307        public void refreshTaskPath() throws IOException {
308                fTestsDescList.clear();
309                TemplateProcessor tp = new TemplateProcessor(fSystemVariables, fConfigNode, getStartDir());
310                getRecipesScaner().loadTaskPath(getConfigNode(), tp);
311        }
312
313        public void progressValue(int i, int length, boolean success) {
314
315        }
316
317        public void progressText(String name) {
318
319        }
320
321        public File getFile(String filePath) {
322                File file = null;
323                if (!StringUtils.startsWithAny(filePath, new String[] { "https:", "http:" })) {
324                        if (filePath != null) {
325                                if (filePath.startsWith("classpath:") || filePath.startsWith("jar:") || filePath.startsWith("file:")
326                                                || '/' == filePath.charAt(0) || '\\' == filePath.charAt(0) || filePath.indexOf(":\\") > 0
327                                                || '/' == filePath.charAt(0)) {
328                                        file = new File(filePath);
329                                } else {
330                                        file = new File(baseDir, filePath);
331                                }
332                        }
333                }
334
335                return file;
336        }
337
338        public String inputValue(String aName, String description, String aValue, ILogger log, String type,
339                        boolean notifyMe, Processor processor) {
340                System.out.print("Input ");
341                String line = inputValue(aName, description, null, type, null);
342                return line;
343        }
344
345        public String inputValue(String name, String description, String defaultValue, String type, Processor processor) {
346                if (defaultValue == null) {
347                        defaultValue = AEWorkspace.getInstance().getDefaultUserConfiguration(".inputValue." + name, defaultValue);
348                }
349
350                boolean password = "password".equalsIgnoreCase(type);
351
352                String showValue = !password ? defaultValue
353                                : (defaultValue != null ? StringUtils.repeat("*", defaultValue.length()) : "");
354                String message = "\"" + StringUtils.defaultIfEmpty(description, name) + "\""
355                                + (StringUtils.isEmpty(defaultValue) ? "" : " [" + showValue + "]") + ": ";
356                System.out.print(message);
357
358                String line = null;
359                if (!Processor.isSilentMode(processor)) {
360                        line = readLine(password);
361                        if (StringUtils.isEmpty(line)) {
362                                line = defaultValue;
363                        } else {
364                                AEWorkspace.getInstance().setDefaultUserConfiguration(".inputValue." + name, line);
365                        }
366                } else {
367                        line = defaultValue;
368                        System.out.println(defaultValue);
369                }
370                return line;
371        }
372
373        @Override
374        public boolean confirmation(String name, String message, Processor unit, boolean notifyMe) throws Exception {
375                if (StringUtils.isBlank(name)) {
376                        System.out.print(message + ", (yes/no): ");
377                } else {
378                        System.out.print(name + " [" + message + "], (yes/no): ");
379                }
380                boolean result = false;
381                String line = readLine(false);
382                result = BooleanUtils.toBoolean(line);
383                return result;
384        }
385
386        public void inputDataTable(Processor unit, Node aTableNode, boolean notifyMe) throws IOException {
387                Node[] theVariablesNodes = aTableNode.getNodes("var");
388                String theLine = null;
389
390                String theFileAttribut = aTableNode.getAttribute("file");
391                if (unit != null)
392                        theFileAttribut = unit.replaceProperties(aTableNode.getAttribute("file"));
393
394                if (theFileAttribut != null) {
395                        File file = unit.getFile(theFileAttribut);
396                        if (file.exists()) {
397                                while ((theLine = readLine(false)) != null) {
398                                        theLine = theLine.trim();
399                                        if (theLine.length() == 0) {
400                                                continue;
401                                        }
402                                        if (theLine.charAt(0) == '#') {
403                                                continue;
404                                        }
405                                        int thePbrk = theLine.indexOf('=');
406
407                                        String theName = StringUtils.upperCase(theLine.substring(0, thePbrk));
408                                        String theValue = theLine.substring(thePbrk + 1);
409
410                                        Node theNode = new Node("var");
411                                        theNode.setAttribute("name", theName);
412                                        theNode.setAttribute("value", theValue);
413
414                                        for (Node node : theVariablesNodes) {
415                                                if (node.getAttribute("name").equalsIgnoreCase(theName)) {
416                                                        node.setAttribute("value", theValue);
417                                                }
418                                        }
419
420                                }
421                        }
422                } else {
423                        String title = aTableNode.getAttribute("name");
424
425                        for (Node node : theVariablesNodes) {
426                                String name = node.getAttribute("name");
427                                String value = node.getAttribute("value");
428
429                                String defaultValue = value;
430
431                                String savedVarName = ".inputValue." + title + "." + StringUtils.upperCase(name);
432                                if (defaultValue == null) {
433                                        defaultValue = AEWorkspace.getInstance().getDefaultUserConfiguration(savedVarName, null);
434                                }
435                                if (defaultValue == null) {
436                                        defaultValue = node.getAttribute("default");
437                                }
438
439                                if (Processor.isSilentMode(unit)) {
440                                        value = defaultValue;
441                                } else {
442                                        value = inputValue(name, null, defaultValue, null, unit);
443                                        AEWorkspace.getInstance().setDefaultUserConfiguration(savedVarName, value);
444                                }
445
446                                unit.setVariableValue(name, value);
447                        }
448                }
449        }
450
451        public void loadConfProperties() throws IOException {
452
453                fSystemVariables.clear();
454
455                Properties properties = new Properties();
456                File theConfFile = new File(getCustomConfPropFileName(getConfigurationName()));
457                if (theConfFile.exists()) {
458                        FileInputStream theFile = new FileInputStream(theConfFile);
459                        properties.load(theFile);
460                        theFile.close();
461                }
462
463                Node[] theVarConfs = fConfigNode.getNodes("Var");
464                for (int i = 0; i < theVarConfs.length; i++) {
465                        Node varNode = theVarConfs[i];
466                        String name = StringUtils.upperCase(varNode.getAttribute("name"));
467
468                        if (name != null) {
469                                Map<String, String> variableDefinition = parseVariableDefinition(varNode);
470                                fSystemVariables.putAll(variableDefinition);
471
472                        } else {
473                                Processor templateProcessor = new BaseProcessor(fSystemVariables, fConfigNode, getStartDir());
474                                String filePath = templateProcessor.replaceProperties(varNode.getAttribute("file"));
475                                File file = getFile(filePath);
476                                templateProcessor.loadProperties(file, fSystemVariables, true);
477                        }
478                }
479
480                for (String key : properties.stringPropertyNames()) {
481                        fSystemVariables.put(key, properties.getProperty(key));
482                }
483
484                fSystemVariables.put("ENV", System.getenv());
485                fSystemVariables.put("SYSTEM", System.getProperties());
486
487                fSystemVariables.put("WORKINGDIR", getStartDir().getAbsolutePath());
488                fSystemVariables.put("HOME_WORKINGDIR", getHomeWorkingDir().getAbsolutePath());
489                fSystemVariables.put("START_TIME", Long.toString(startTime));
490                fSystemVariables.put("USER_NAME", fUser);
491
492                Node[] theTableVarConfs = fConfigNode.getNodes("Table");
493                Processor unit = new BaseProcessor(this, log, getStartDir());
494                Processor.setSilentMode(unit, true);
495
496                for (int i = 0; i < theTableVarConfs.length; i++) {
497                        inputDataTable(unit, theTableVarConfs[i], false);
498                        fSystemVariables.putAll(unit.getVariables());
499                }
500
501                boolean stopped = unit.isStopped();
502                if (stopped) {
503                        throw new TaskCancelingException();
504                }
505                
506        }
507
508        private Map<String, String> parseVariableDefinition(Node varNode) {
509                Map<String, String> properties = new HashMap<>();
510
511                String name = StringUtils.upperCase(varNode.getAttribute("name"));
512
513                String attribute = varNode.getAttribute("init");
514                String type = varNode.getAttribute("type");
515
516                Object inputValue;
517                String typeValue = StringUtils.defaultIfBlank(type, "string");
518                switch (typeValue) {
519                case "array":
520                        Node[] nodes = varNode.getNodes("item");
521                        inputValue = new ArrayList<String>();
522                        for (Node node : nodes) {
523                                String text = node.getInnerText();
524                                @SuppressWarnings("unchecked")
525                                List<String> valueList = (List<String>) inputValue;
526                                valueList.add(text);
527                        }
528                        break;
529                case "map":
530                        inputValue = getMap(varNode);
531                        break;
532
533                default:
534                        inputValue = varNode.getAttribute("value");
535                        if (inputValue == null) {
536                                inputValue = varNode.getInnerText();
537                                if (StringUtils.isEmpty((String) inputValue)) {
538                                        inputValue = getMap(varNode);
539                                }
540                        }
541                        break;
542                }
543
544                if ("mandatory".equals(attribute) && properties.get(name) == null) {
545                        attribute = "console";
546                }
547
548                if ("console".equals(attribute)) {
549                        inputValue = inputValue(name, null, ObjectUtils.toString(inputValue, null), log, type, false, null);
550
551                        switch (StringUtils.defaultIfBlank(type, "string")) {
552                        case "array":
553                                break;
554                        case "map":
555                                inputValue = AEUtils.convertStringToMap((String) inputValue);
556                                break;
557
558                        default:
559                                break;
560                        }
561                }
562
563                if (inputValue != null)
564                        fSystemVariables.put(StringUtils.upperCase(name), inputValue);
565                else
566                        fSystemVariables.remove(name);
567
568                String savedValue = (String) properties.get(name);
569                Object value = null;
570                if (savedValue != null) {
571                        switch (StringUtils.defaultIfBlank(type, "string")) {
572                        case "array":
573                                @SuppressWarnings("unchecked")
574                                List<String> list = (List<String>) inputValue;
575                                list.remove(savedValue);
576
577                                List<String> arrayList = new ArrayList<>();
578                                arrayList.add(savedValue);
579                                arrayList.addAll(list);
580                                value = arrayList;
581                                break;
582                        case "map":
583                                value = AEUtils.convertStringToMap(savedValue);
584                                break;
585
586                        default:
587                                value = savedValue;
588                                break;
589                        }
590
591                        fSystemVariables.put(StringUtils.upperCase(name), value);
592                }
593
594                return properties;
595        }
596
597        private Object getMap(Node varNode) {
598                Object result = null;
599                Node[] nodes = varNode.getNodes("item");
600                if (nodes.length > 0) {
601                        result = new LinkedHashMap<String, String>();
602                        for (Node node : nodes) {
603                                @SuppressWarnings("unchecked")
604                                Map<String, String> valueMap = (Map<String, String>) result;
605                                String value = node.getAttribute("value");
606                                if (value == null) {
607                                        value = node.getInnerText();
608                                }
609                                valueMap.put(node.getAttribute("key"), value);
610                        }
611                }
612                return result;
613        }
614
615        public String selectConfiguration(String confName, Node configNodes, boolean refreshTaskPath) throws IOException {
616
617                allConfigNode = configNodes;
618
619                String configurationName = System.getProperty(ConfigConstants.CONFIG_NAME_SYS_PRPERTY_NAME);
620                if (confName != null) {
621                        configurationName = confName;
622                }
623
624                fConfigNode = getCurrentConfig(allConfigNode, configurationName);
625
626                if (fConfigNode == null) {
627                        System.out.println("Configuration '" + configurationName + "' not found in " + ConfigConstants.AE_CONFIG_XML
628                                        + " file.");
629                        return configurationName;
630
631                } else {
632                        setConfigurationName(fConfigNode.getAttribute("name"));
633
634                        if (configurationName == null) {
635                                configurationName = fConfigNode.getAttribute("name");
636                                if (configurationName == null)
637                                        configurationName = fConfigNode.getAttribute("description");
638                        }
639
640                        loadConfProperties();
641
642                        Node[] theLocations = fConfigNode.getNodes("Locale");
643                        if (theLocations != null && theLocations.length > 0) {
644                                Node theLocation = theLocations[0];
645                                String theISO3Language = theLocation.getAttribute("ISO3Language");
646                                String theDisplayName = theLocation.getAttribute("DisplayName");
647                                Locale[] availableLocales = Locale.getAvailableLocales();
648
649                                boolean theFound = false;
650                                for (int l = 0; l < availableLocales.length; l++) {
651                                        if (availableLocales[l].getISO3Language().equals(theISO3Language)) {
652                                                Locale.setDefault(availableLocales[l]);
653                                                System.out.println("Set location ISO3Language: " + theISO3Language);
654                                                theFound = true;
655                                                break;
656                                        }
657                                        if (availableLocales[l].getDisplayName().equals(theDisplayName)) {
658                                                Locale.setDefault(availableLocales[l]);
659                                                System.out.println("Set location DisplayName: " + theDisplayName);
660                                                theFound = true;
661                                                break;
662                                        }
663                                }
664
665                                if (theFound == false) {
666                                        for (int j = 0; j < availableLocales.length; j++) {
667                                                System.out.println(j + ". " + availableLocales[j].getDisplayName());
668                                        }
669                                }
670                        }
671
672                        configuration();
673
674                        return fConfigurationName;
675                }
676
677        }
678
679        public void setDefaultUserConfiguration(String propertyName, String value) {
680
681                propertyName = getFullConfPropertyName(propertyName);
682
683                if (value != null) {
684                        if (cryptoUtilAesGcm != null) {
685                                value = cryptoUtilAesGcm.encrypt(value);
686                        }
687
688                        fUserPreferences.setProperty(propertyName, value);
689
690                        try {
691                                File preferencesFile = getPreferencesFile();
692                                FileOutputStream fileInputStream = new FileOutputStream(preferencesFile);
693
694                                fUserPreferences.store(fileInputStream, null);
695                                fileInputStream.close();
696
697                        } catch (IOException e) {
698                                System.out.println("Write default user setting is failed. Error: " + e.getMessage());
699                        }
700                } else {
701                        if (fUserPreferences.get(propertyName) != null) {
702                                fUserPreferences.remove(propertyName);
703                        }
704                }
705
706        }
707
708        private String getFullConfPropertyName(String propertyName) {
709                return propertyName;
710        }
711
712        public String getDefaultUserConfiguration(String aName, String theDefaultConfiguration) {
713                aName = getFullConfPropertyName(aName);
714
715                loadCustomProperties();
716                String theProperty = fUserPreferences.getProperty(aName);
717
718                if (theProperty != null) {
719                        if (cryptoUtilAesGcm != null) {
720                                theDefaultConfiguration = cryptoUtilAesGcm.decrypt(theProperty);
721                        } else {
722                                theDefaultConfiguration = theProperty;
723                        }
724                }
725
726                return theDefaultConfiguration;
727        }
728
729        public Node getCurrentConfig(Node configs, String aNameConfiguration) {
730                Node[] configNodes = configs.getNodes(CONFIGURATION_TITLE);
731
732                ArrayList<String> possibleValues = new ArrayList<>();
733
734                for (int i = 0; i < configNodes.length; i++) {
735                        Node node = configNodes[i];
736                        String name = node.getAttribute("name");
737                        String ip = node.getAttribute("ip");
738                        if (ip == null || isEnableIp(ip)) {
739
740                                if (possibleValues.contains(name)) {
741                                        throw new IllegalArgumentException("Duplication name configuration: " + name);
742                                }
743
744                                if (!name.startsWith("#")) {
745                                        possibleValues.add(name);
746                                }
747                        }
748                }
749
750                if (CollectionUtils.isNotEmpty(possibleValues)) {
751                        String configName = possibleValues.get(0);
752                        if (aNameConfiguration != null) {
753                                configName = aNameConfiguration;
754                        }
755
756                        if (possibleValues.size() > 1 && aNameConfiguration == null) {
757                                configName = selectConfiguration(possibleValues.toArray(new String[possibleValues.size()]));
758                        }
759
760                        Node theConfigNode = prepareConfigurationNode(configs, configName);
761                        return theConfigNode;
762                }
763
764                return null;
765        }
766
767        private boolean isEnableIp(String ip) {
768                Enumeration<NetworkInterface> networkInterfaces;
769                Pattern compile = Pattern.compile(ip);
770                try {
771                        networkInterfaces = NetworkInterface.getNetworkInterfaces();
772                        while (networkInterfaces.hasMoreElements()) {
773                                NetworkInterface nextElement = networkInterfaces.nextElement();
774                                Enumeration<InetAddress> inetAddresses = nextElement.getInetAddresses();
775                                while (inetAddresses.hasMoreElements()) {
776                                        InetAddress nextElement2 = inetAddresses.nextElement();
777                                        if (nextElement2 instanceof Inet4Address) {
778                                                Inet4Address address = (Inet4Address) nextElement2;
779                                                String hostAddress = address.getHostAddress();
780                                                if (compile.matcher(hostAddress).matches()) {
781                                                        return true;
782                                                }
783                                        }
784                                }
785                        }
786                } catch (SocketException e) {
787                        e.printStackTrace();
788                }
789                return false;
790        }
791
792        private Node prepareConfigurationNode(Node configs, String configName) {
793
794                Node configNode = configs.findNode(CONFIGURATION_TITLE, "name", configName);
795                Node baseNode = null;
796
797                if (configNode != null) {
798                        String baseConfig = configNode.getAttribute("base");
799
800                        if (baseConfig != null) {
801                                baseNode = prepareConfigurationNode(configs, baseConfig);
802
803                                if (baseNode != null) {
804                                        baseNode = (Node) baseNode.clone();
805                                        baseNode.setAttributes(configNode.getAttributes());
806
807                                        for (Iterator<Node> theIterator = configNode.iterator(); theIterator.hasNext();) {
808                                                Node theNode = theIterator.next();
809
810                                                String theTagName = theNode.getTag();
811                                                Node[] theNodeArray = baseNode.getNodes(theTagName);
812
813                                                if (theNodeArray.length > 1) {
814                                                        String theName = theNode.getAttribute("name");
815
816                                                        Node theBaseTag = baseNode.findNode(theTagName, "name", theName);
817
818                                                        if (theBaseTag != null) {
819                                                                System.out.println(
820                                                                                "Change node: " + theTagName + " name=" + theName + " Value: " + theNode);
821                                                                int indexOf = baseNode.indexOf(theBaseTag);
822                                                                Node object = baseNode.get(indexOf);
823                                                                if (object.getTag() == theTagName)
824                                                                        baseNode.remove(indexOf);
825                                                        }
826                                                }
827                                                baseNode.add(theNode);
828                                        }
829
830                                } else {
831                                        System.out.println("Base configuration is not found. Name: " + baseConfig);
832                                        baseNode = configNode;
833                                }
834                        } else
835                                baseNode = configNode;
836
837                } else
838                        baseNode = configNode;
839
840                return baseNode;
841        }
842
843        public File getStartDir() {
844                return getRecipesScaner().getStartDir();
845        }
846
847        public String inputChoice(String name, String description, String[] values, String defaultValue,
848                        Processor taskProcessor, boolean notifyMe) {
849                if (defaultValue == null && values.length > 0) {
850                        String value = getDefaultUserConfiguration(".choice." + name, null);
851                        if (value != null) {
852                                defaultValue = value;
853                        }
854                }
855
856                System.out.println("List of values for [" + name + "]:");
857                if (!Processor.isSilentMode(taskProcessor)) {
858                        int i = 1;
859                        for (String val : values) {
860                                println(String.format("%3s: ", i++) + val, Color.green);
861                        }
862                        defaultValue = inputInteger(name, values, defaultValue);
863                } else {
864                        System.out.println("Saved selection applied: " + defaultValue);
865                }
866
867                return defaultValue;
868        }
869
870        public String[] inputMultiChoice(String name, String[] values, String defaultValue, Processor taskProcessor) {
871                String[] result = null;
872
873                if (defaultValue == null && values.length > 0) {
874                        String value = getDefaultUserConfiguration("MultiTaskRunDialog:" + name, null);
875                        if (value != null) {
876                                defaultValue = value;
877                        }
878                }
879                boolean silent = taskProcessor != null && Processor.isSilentMode(taskProcessor);
880
881                boolean isDone = false;
882                do {
883                        try {
884                                System.out.println("List of values for [" + name + "]:");
885                                if (!silent) {
886                                        int i = 1;
887
888                                        for (String val : values) {
889                                                println(String.format("%3s: ", i++) + val, Color.green);
890                                        }
891                                        String preset = null;
892                                        System.out.print("Please select ");
893                                        defaultValue = inputValue(name, preset, defaultValue, null, taskProcessor);
894                                        result = getValue(values, defaultValue);
895                                        isDone = true;
896
897                                        AEWorkspace.getInstance().setDefaultUserConfiguration("MultiTaskRunDialog:" + name, defaultValue);
898                                } else {
899                                        if (defaultValue != null) {
900                                                result = getValue(values, defaultValue);
901                                                System.out.println("Saved selection applied: [" + StringUtils.join(result, ",") + "]");
902                                        }
903                                }
904                        } catch (ArrayIndexOutOfBoundsException e) {
905                                System.out.println(defaultValue + " - invalid value.");
906                                isDone = false;
907                        }
908                } while (!isDone && !silent);
909
910                return result;
911        }
912
913        private void println(String text, Color color) {
914                System.out.println(text);
915        }
916
917        protected String[] getValue(String[] values, String defaultValue) {
918                String[] result = null;
919                if (defaultValue != null) {
920                        String[] split = StringUtils.split(defaultValue, ";");
921
922                        try {
923                                result = new String[split.length];
924                                for (int j = 0; j < split.length; j++) {
925                                        result[j] = values[Integer.parseInt(split[j]) - 1];
926                                }
927                        } catch (NumberFormatException e) {
928                                result = split;
929                        }
930                }
931                return result;
932        }
933
934        public String inputInteger(String name, String[] values, String defaultValue) {
935
936                boolean isDone = false;
937                do {
938                        System.out.print(
939                                        "Please select" + (StringUtils.isEmpty(defaultValue) ? "" : " [" + defaultValue + "]") + ": ");
940
941                        int inputValue;
942                        String readLine = null;
943                        try {
944                                readLine = readLine(false);
945                                if (!StringUtils.isEmpty(readLine)) {
946                                        inputValue = Integer.parseInt(readLine) - 1;
947                                        defaultValue = values[inputValue];
948                                        setDefaultUserConfiguration(".choice." + name, defaultValue);
949                                }
950
951                                isDone = true;
952
953                        } catch (Exception e) {
954                                System.out.println(readLine + " - invalid value.");
955                                defaultValue = null;
956                        }
957                } while (!isDone);
958
959                return defaultValue;
960        }
961
962        public String inputFile(String name, String description, File aDefaultFile, ILogger log, Processor taskProcessor) {
963                String theResult = getDefaultUserConfiguration(".inputFile",
964                                aDefaultFile == null ? null : aDefaultFile.getAbsolutePath());
965                return theResult;
966        }
967
968        protected String selectConfiguration(String[] configNames) {
969                String configName = choiceValue(CONFIGURATION_TITLE, null, configNames, null, true, null);
970                return configName;
971        }
972
973        public String getTestPath(String name) {
974                String recipePath = null;
975                if (name != null) {
976                        recipePath = fTestsDescList.getProperty(name);
977                }
978                return recipePath;
979        }
980
981        public RecipeRunner runTask(String name, boolean async) {
982                RecipeRunner runner = null;
983                if (name != null) {
984                        runner = createTestRunner(name);
985                        String testPath = getTestPath(name);
986                        if (testPath != null) {
987                                if (async) {
988                                        TaskThread theThread = new TaskThread(runner, testPath);
989                                        theThread.start();
990
991                                } else {
992                                        try {
993                                                runner.makeRecipe(testPath);
994                                        } catch (CommandException e) {
995                                                log.error("Task failed.", e);
996                                        }
997                                }
998                        }
999                }
1000
1001                return runner;
1002        }
1003
1004        protected RecipeRunner createTestRunner(String name) {
1005                RecipeRunner runner = new RecipeRunner(this);
1006                Processor processor = new BaseProcessor(this, log, getStartDir());
1007                processor.setTestListener(runner);
1008                runner.setProcessor(processor);
1009                runner.setLog(log);
1010                return runner;
1011        }
1012
1013        public void removeTestPath(String name) {
1014                if (fTestsDescList.get(name) != null)
1015                        fTestsDescList.remove(name);
1016        }
1017
1018        public void setTestPath(String name, String path) {
1019                fTestsDescList.put(name, path);
1020        }
1021
1022        public String getWorkingDir() {
1023                return getStartDir().getAbsolutePath();
1024        }
1025
1026        public MultiTaskRunDialog tasksChoice(MultiTaskRunDialog dialog, String[] list, boolean exceptionIgnoreFlag,
1027                        Object setup, Processor taskProcessor, boolean visible) {
1028
1029                if (setup == null) {
1030                        boolean consoleDefaultInput = isConsoleDefaultInput(dialog.getName(), null);
1031                        setup = inputMultiChoice(dialog.getName(), list, null, taskProcessor);
1032                        dialog.select((String[]) setup, consoleDefaultInput);
1033                }
1034
1035                dialog.setExceptionIgnore(exceptionIgnoreFlag);
1036                dialog.setVisible(visible);
1037                dialog.showDialog(dialog.getName(), list, taskProcessor.getListener().isNotifyMe());
1038
1039                return dialog;
1040        }
1041
1042        public Map<String, Object> getSystemVariables() {
1043                return fSystemVariables;
1044        }
1045
1046        public void setConsoleDefaultInput(boolean defaultMode) {
1047                this.defaultMode = defaultMode;
1048        }
1049
1050        public boolean isConsoleDefaultInput(String varName, String description) {
1051                return defaultMode;
1052        }
1053
1054        public Node getConfigNode() {
1055                return fConfigNode;
1056        }
1057
1058        public Node getAllConfigNode() {
1059                return allConfigNode;
1060        }
1061
1062        public Properties getTasksMap() {
1063                return fTestsDescList;
1064        }
1065
1066        public Properties getTestsDescList() {
1067                return fTestsDescList;
1068        }
1069
1070        public Object[] getPublicTestsList() {
1071                Enumeration<Object> keys = fTestsDescList.keys();
1072                List<String> result = new ArrayList<String>();
1073                while (keys.hasMoreElements()) {
1074                        String key = (String) keys.nextElement();
1075                        if (!key.startsWith("#")) {
1076                                result.add(key);
1077                        }
1078                }
1079                String[] a = result.toArray(new String[result.size()]);
1080                Arrays.sort(a);
1081                return a;
1082        }
1083
1084        public void startTaskNotify(RecipeRunner task) {
1085
1086        }
1087
1088        public String choiceValue(String name, String description, Object[] possibleValues, ILogger log, boolean notifyMe,
1089                        Processor processor) {
1090                String result = null;
1091                description = StringUtils.defaultString(description, name);
1092
1093                if (possibleValues != null && possibleValues.length > 0) {
1094                        result = getDefaultUserConfiguration(".choiceValue." + name, null);
1095
1096                        String[] values = Arrays.copyOf(possibleValues, possibleValues.length, String[].class);
1097                        result = inputChoice(description, null, values, result, processor, notifyMe);
1098
1099                        AEWorkspace.getInstance().setDefaultUserConfiguration(".choiceValue." + name, result);
1100                } else {
1101                        result = (String) possibleValues[0];
1102                }
1103
1104                return result;
1105        }
1106
1107        public static AEWorkspace getInstance() {
1108                return instance;
1109        }
1110
1111        public void resetConfiguration() {
1112                fConfigNode = null;
1113        }
1114
1115        public void resetConfigurationName() {
1116                setConfigurationName(null);
1117        }
1118
1119        public String getConfigurationName() {
1120                return this.fConfigurationName;
1121        }
1122
1123        public void loadConfiguration(boolean refreshTaskMap) {
1124                loadConfiguration(null, refreshTaskMap);
1125        }
1126
1127        public void addRunner(RecipeRunner testRunner) {
1128                runners.add(testRunner);
1129        }
1130
1131        public void removeRunner(RecipeRunner testRunner) {
1132                runners.remove(testRunner);
1133        }
1134
1135        public void stopAllRunners() {
1136                RecipeRunner[] array = runners.toArray(new RecipeRunner[runners.size()]);
1137                for (RecipeRunner runner : array) {
1138                        runner.stopTest();
1139                }
1140        }
1141
1142        public void setBaseDir(File baseDir) {
1143                this.baseDir = baseDir;
1144        }
1145
1146        public File getBaseDir() {
1147                return this.baseDir;
1148        }
1149
1150        public Set<Class<?>> getOperationsClasses() {
1151                return operationsClasses;
1152        }
1153
1154        public void setOperationsClasses(@SuppressWarnings("rawtypes") Set<Class> operationsClasses) {
1155                if (operationsClasses != null) {
1156                        opsMethods = new HashMap<String, OperationHolder>();
1157                        try {
1158                                Method[] methods = Object.class.getMethods();
1159                                String exclude[] = new String[methods.length];
1160                                for (int i = 0; i < exclude.length; i++) {
1161                                        exclude[i] = methods[i].getName();
1162                                }
1163                                Arrays.sort(exclude);
1164
1165                                for (Class<?> operationClass : operationsClasses) {
1166                                        methods = operationClass.getMethods();
1167                                        for (Method method : methods) {
1168                                                if (Arrays.binarySearch(exclude, method.getName()) < 0
1169                                                                && method.getModifiers() == Modifier.PUBLIC) {
1170                                                        String shortClassName = operationClass.getName();
1171                                                        opsMethods.put(shortClassName + "." + method.getName(),
1172                                                                        new OperationHolder(operationClass, method));
1173                                                }
1174                                        }
1175                                }
1176                        } catch (Exception e) {
1177                                throw new IllegalArgumentException(e);
1178                        }
1179                }
1180        }
1181
1182        public OperationHolder getOperationsMethod(String name) {
1183                return opsMethods.get(name);
1184        }
1185
1186        public Map<String, OperationHolder> getOperationsMethods() {
1187                return opsMethods;
1188        }
1189
1190        public Set<RecipeRunner> getRunners() {
1191                return runners;
1192        }
1193
1194        @Override
1195        public void finished(String aTestFile) {
1196        }
1197
1198        public static Properties getUserPreferences() {
1199                return fUserPreferences;
1200        }
1201
1202        public String[] getTestsList() {
1203                String[] array = fTestsDescList.keySet().toArray(new String[fTestsDescList.size()]);
1204                Arrays.sort(array);
1205                return array;
1206        }
1207
1208        @Override
1209        public MessageHandler message(Processor taskProcessor, String description, String message, boolean notifyMe) {
1210                return new MessageHandler();
1211        }
1212
1213        public void setConfigurationName(String fConfigurationName) {
1214                this.fConfigurationName = fConfigurationName;
1215                fUserPreferences = null;
1216                loadCustomProperties();
1217        }
1218
1219        public void initUserPreferencesEncryption(String password) {
1220                Node configNode = getConfigNode();
1221                boolean userPreferencesEncryption = Boolean.parseBoolean(configNode.getAttribute("userPreferencesEncryption"));
1222
1223                if (userPreferencesEncryption) {
1224                        if (password == null) {
1225                                System.out.print(MESSAGE_PASSWORD_REQUIRED);
1226
1227                                Console console = System.console();
1228                                if (console == null) {
1229                                        password = readLine(true);
1230                                } else {
1231                                        char[] pwd = console.readPassword();
1232                                        password = new String(pwd);
1233                                }
1234                        }
1235
1236                        byte[] pwdBytes;
1237                        try {
1238                                pwdBytes = new String(password).getBytes("UTF-8");
1239                        } catch (UnsupportedEncodingException e) {
1240                                throw new IllegalArgumentException(e);
1241                        }
1242                        password = Base64.getEncoder().encodeToString(pwdBytes);
1243                        cryptoUtilAesGcm = new Encryptor(password);
1244                        Enumeration<Object> keys = fUserPreferences.keys();
1245                        while (keys.hasMoreElements()) {
1246                                String name = (String) keys.nextElement();
1247                                getDefaultUserConfiguration(name, name);
1248                                break;
1249                        }
1250                }
1251        }
1252
1253        public void close() {
1254                closeHooks.forEach(e -> e.run());
1255        }
1256
1257        public void addCloseHook(Runnable shutdownHook) {
1258                closeHooks.add(shutdownHook);
1259        }
1260
1261        public RecipesScanner getRecipesScaner() {
1262                return recipesScaner;
1263        }
1264
1265        public void setStartDir(File startDir) {
1266                recipesScaner.setStartDir(startDir);
1267        }
1268
1269        private String readLine(boolean password) {
1270                try {
1271                        Console console = System.console();
1272                        String line;
1273                        Toolkit.getDefaultToolkit().beep();
1274                        if (console != null) {
1275                                if (password) {
1276                                        line = new String(console.readPassword());
1277                                } else {
1278                                        line = console.readLine();
1279                                }
1280                        } else {
1281                                InputStreamReader inputStreamReader = new InputStreamReader(System.in);
1282                                BufferedReader reader = new BufferedReader(inputStreamReader);
1283                                try {
1284                                        line = reader.readLine();
1285                                } catch (IOException e) {
1286                                        line = null;
1287                                }
1288                        }
1289
1290                        return line;
1291
1292                } catch (RuntimeException e) {
1293                        throw new TaskCancelingException();
1294                }
1295        }
1296
1297        protected void initLogger(Node configNode) {
1298                Properties logProperties = fillLogProperties(configNode);
1299                PropertyConfigurator.configure(logProperties);
1300                log = new Logger("AEWorkspace");
1301        }
1302
1303        protected Properties fillLogProperties(Node configNode) {
1304                Properties logProperties = new Properties();
1305                if (configNode != null) {
1306                        logProperties = MapUtils.toProperties(configNode.getAttributes());
1307                }
1308                Node[] theLoggerNodes = fConfigNode.getNodes("Logger");
1309                Node node = theLoggerNodes[0];
1310                boolean consoleOn = false;
1311                if (theLoggerNodes != null && theLoggerNodes.length > 0) {
1312                        node = theLoggerNodes[0];
1313                        logProperties.putAll(node.getAttributes());
1314                }
1315
1316                TemplateProcessor templateProcessor = new TemplateProcessor(fSystemVariables, fConfigNode, getStartDir());
1317
1318                if (logProperties.getProperty("rootLogger") != null) {
1319                        String rootLogger = templateProcessor.replaceProperties(logProperties.getProperty("rootLogger"));
1320
1321                        consoleOn = rootLogger.indexOf("CONSOLE") >= 0;
1322
1323                        logProperties.setProperty("log4j.rootLogger", rootLogger);
1324                        logProperties.remove("rootLogger");
1325                }
1326                if (logProperties.getProperty("File") != null) {
1327                        String lofFileName = templateProcessor.replaceProperties(logProperties.getProperty("File"));
1328                        File file = new File(lofFileName);
1329                        if (file != null && file.getParentFile() != null && file.getParentFile().exists() == false)
1330                                file.getParentFile().mkdirs();
1331                        logProperties.setProperty("log4j.appender.LOGFILE.File", lofFileName);
1332                }
1333                if (logProperties.getProperty("Threshold") != null) {
1334                        logProperties.setProperty("log4j.appender.LOGFILE.Threshold",
1335                                        templateProcessor.replaceProperties(logProperties.getProperty("Threshold")));
1336                        if (consoleOn)
1337                                logProperties.setProperty("log4j.appender.CONSOLE.Threshold",
1338                                                templateProcessor.replaceProperties(logProperties.getProperty("Threshold")));
1339                        logProperties.remove("Threshold");
1340                }
1341                if (logProperties.getProperty("ConversionPattern") != null) {
1342                        logProperties.setProperty("log4j.appender.LOGFILE.layout.ConversionPattern",
1343                                        templateProcessor.replaceProperties(logProperties.getProperty("ConversionPattern")));
1344                        if (consoleOn)
1345                                logProperties.setProperty("log4j.appender.CONSOLE.layout.ConversionPattern",
1346                                                templateProcessor.replaceProperties(logProperties.getProperty("ConversionPattern")));
1347                        logProperties.remove("ConversionPattern");
1348                } else {
1349                        logProperties.setProperty("log4j.appender.LOGFILE.layout.ConversionPattern",
1350                                        "%d{dd.MM.yyyy HH:mm:ss} %-5p %m %n");
1351                        if (consoleOn)
1352                                logProperties.setProperty("log4j.appender.CONSOLE.layout.ConversionPattern",
1353                                                "%d{dd.MM.yyyy HH:mm:ss} %-5p %m %n");
1354                }
1355                logProperties.setProperty("log4j.appender.logfile.DatePattern", "'.'yyyy-MM-dd");
1356                logProperties.setProperty("log4j.appender.LOGFILE", "org.apache.log4j.DailyRollingFileAppender");
1357                if (consoleOn)
1358                        logProperties.setProperty("log4j.appender.CONSOLE", "org.apache.log4j.ConsoleAppender");
1359                logProperties.setProperty("log4j.appender.LOGFILE.layout", "org.apache.log4j.PatternLayout");
1360                if (consoleOn)
1361                        logProperties.setProperty("log4j.appender.CONSOLE.layout", "org.apache.log4j.PatternLayout");
1362
1363                logProperties.setProperty("log4j.logger.java.desktop", "ERROR");
1364                return logProperties;
1365        }
1366
1367}