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