001package com.ganteater.ae.desktop;
002
003import java.awt.BorderLayout;
004import java.awt.Component;
005import java.awt.Container;
006import java.awt.Frame;
007import java.awt.HeadlessException;
008import java.awt.event.WindowAdapter;
009import java.awt.event.WindowEvent;
010import java.io.BufferedReader;
011import java.io.File;
012import java.io.FileOutputStream;
013import java.io.FileReader;
014import java.io.FileWriter;
015import java.io.IOException;
016import java.io.InputStream;
017import java.io.InputStreamReader;
018import java.net.URL;
019import java.nio.file.Files;
020import java.nio.file.Path;
021import java.nio.file.Paths;
022import java.util.ArrayList;
023import java.util.List;
024import java.util.stream.Collectors;
025import java.util.stream.Stream;
026
027import javax.swing.Icon;
028import javax.swing.JDialog;
029import javax.swing.JFileChooser;
030import javax.swing.JLabel;
031import javax.swing.JOptionPane;
032import javax.swing.JPanel;
033import javax.swing.JPasswordField;
034import javax.swing.JScrollPane;
035import javax.swing.JTable;
036import javax.swing.WindowConstants;
037import javax.swing.filechooser.FileFilter;
038import javax.swing.table.AbstractTableModel;
039
040import org.apache.commons.io.FilenameUtils;
041import org.apache.commons.io.IOUtils;
042import org.apache.commons.lang.ObjectUtils;
043import org.apache.commons.lang.StringUtils;
044import org.apache.commons.lang.SystemUtils;
045
046import com.ganteater.ae.AEWorkspace;
047import com.ganteater.ae.ConfigConstants;
048import com.ganteater.ae.ConfigurationException;
049import com.ganteater.ae.ILogger;
050import com.ganteater.ae.MultiTaskRunDialog;
051import com.ganteater.ae.RecipeRunner;
052import com.ganteater.ae.desktop.editor.TaskEditor;
053import com.ganteater.ae.desktop.ui.AEFrame;
054import com.ganteater.ae.desktop.ui.CheckPointBox;
055import com.ganteater.ae.desktop.ui.InputTableModel;
056import com.ganteater.ae.desktop.ui.OptionPane;
057import com.ganteater.ae.desktop.ui.AEFrame.UIChoiceTaskRunner;
058import com.ganteater.ae.desktop.util.SoundManager;
059import com.ganteater.ae.desktop.util.UIUtils;
060import com.ganteater.ae.processor.MessageHandler;
061import com.ganteater.ae.processor.Processor;
062import com.ganteater.ae.util.xml.easyparser.EasyParser;
063import com.ganteater.ae.util.xml.easyparser.Node;
064
065public class DesktopWorkspace extends AEWorkspace {
066
067        private static final String INPUT_FILE_NAME = ".inputFile";
068
069        private final class JFileChooserExtension extends JFileChooser {
070                private static final long serialVersionUID = 1L;
071                private final String name;
072                private int returnValue;
073
074                private JFileChooserExtension(String name) {
075                        this.name = name;
076                }
077
078                @Override
079                protected JDialog createDialog(Component parent) throws HeadlessException {
080                        JDialog dialog = super.createDialog(parent);
081                        Container contentPane = dialog.getContentPane();
082                        CheckPointBox vip = new CheckPointBox(name, null, InputDialogType.FILE);
083                        contentPane.add(vip, BorderLayout.SOUTH);
084
085                        dialog.addWindowListener(new WindowAdapter() {
086
087                                @Override
088                                public void windowClosing(WindowEvent e) {
089                                        returnValue = -1;
090                                }
091                        });
092                        return dialog;
093                }
094
095                @Override
096                public int showDialog(Component parent, String approveButtonText) throws HeadlessException {
097                        int showDialog = super.showDialog(parent, approveButtonText);
098                        return returnValue == -1 ? -1 : showDialog;
099                }
100        }
101
102        private AEFrame frame;
103
104        public DesktopWorkspace(AEFrame frame) {
105                this.frame = frame;
106        }
107
108        protected void executeAnteater(File aeConfigFile) {
109                try {
110                        System.out.println("Starting: " + aeConfigFile.getAbsolutePath());
111                        ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "mvn", "ae:run");
112                        builder.directory(aeConfigFile);
113                        builder.redirectErrorStream(true);
114                        Process process = builder.start();
115                        InputStream inputStream = process.getInputStream();
116
117                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
118
119                        String line;
120                        while ((line = reader.readLine()) != null) {
121                                System.out.println(line);
122                        }
123
124                        System.exit(0);
125
126                } catch (Exception e) {
127                        e.printStackTrace();
128                }
129        }
130
131        protected List<String> findAEconfigs(File path) {
132                if (path == null) {
133                        path = SystemUtils.getUserDir();
134                }
135
136                List<String> confFiles = new ArrayList<>();
137                try (Stream<Path> stream = Files.walk(Paths.get(path.getAbsolutePath()), 10)) {
138                        stream.filter(f -> f.endsWith(ConfigConstants.AE_CONFIG_XML)).forEach(f -> confFiles.add(f.toString()));
139                } catch (IOException e) {
140                        e.printStackTrace();
141                }
142                return confFiles;
143        }
144
145        @Override
146        protected String selectConfiguration(String[] aPossibleValues) {
147                String theValue;
148
149                String theDefaultConfiguration = aPossibleValues[0];
150                theDefaultConfiguration = AEWorkspace.getInstance().getDefaultUserConfiguration(".defaultConfiguration",
151                                theDefaultConfiguration);
152
153                frame.setAlwaysOnTop(true);
154                Icon fWelcomeLogo = AEFrame.getIcon(AEFrame.LOGO_JPG);
155                theValue = (String) JOptionPane.showInputDialog(frame, "Environments:", "Giant anteater looking for food ...",
156                                JOptionPane.QUESTION_MESSAGE, fWelcomeLogo, aPossibleValues, theDefaultConfiguration);
157                frame.setAlwaysOnTop(false);
158                if (theValue == null)
159                        throw new IllegalArgumentException("Configuration is not selected.");
160
161                AEWorkspace.getInstance().setDefaultUserConfiguration(".defaultConfiguration", theValue);
162
163                return theValue;
164        }
165
166        @Override
167        public MultiTaskRunDialog tasksChoice(MultiTaskRunDialog dialog, String[] list, boolean exceptionIgnoreFlag,
168                        Object setup, Processor taskProcessor, boolean visible) {
169                UIChoiceTaskRunner runner = frame.getChoiceTaskRunner(dialog, taskProcessor, setup);
170
171                String name = runner.getName();
172                boolean consoleDefaultInput = isConsoleDefaultInput(name, null);
173
174                if (setup != null) {
175                        if (setup instanceof String[])
176                                runner.select((String[]) setup, consoleDefaultInput);
177                        else if (setup instanceof List) {
178                                @SuppressWarnings("unchecked")
179                                List<String> setupList = (List<String>) setup;
180                                String[] array = setupList.toArray(new String[setupList.size()]);
181                                runner.select(array, consoleDefaultInput);
182                        } else if (setup instanceof String) {
183                                String[] attribute = new String[] { (String) setup };
184                                runner.select(attribute, consoleDefaultInput);
185                        }
186                }
187
188                runner.setExceptionIgnore(exceptionIgnoreFlag);
189                runner.setVisible(visible);
190                boolean notifyMe = taskProcessor.getListener().isNotifyMe();
191
192                runner.showDialog(name, list, notifyMe);
193
194                return runner;
195        }
196
197        @Override
198        public void startTaskNotify(RecipeRunner task) {
199                TaskEditor editor = (TaskEditor) task;
200                super.startTaskNotify(editor);
201                frame.startTaskNotify(editor);
202        }
203
204        @Override
205        public void progressValue(int i, int length, boolean success) {
206                frame.progressValue(i, length, success);
207        }
208
209        @Override
210        public void removeRunner(RecipeRunner testRunner) {
211                super.removeRunner(testRunner);
212                frame.endTask(testRunner);
213        }
214
215        @Override
216        public String inputValue(String name, String description, String value, ILogger log, String type, boolean notifyMe,
217                        Processor processor) {
218                String inputValue = null;
219                if ("path".equalsIgnoreCase(type)) {
220                        File defaultFile;
221                        if (value != null) {
222                                defaultFile = new File(value);
223                        } else {
224                                defaultFile = new File(getWorkingDir());
225                        }
226                        inputValue = inputFile(name, description, defaultFile, log, processor);
227                } else {
228                        inputValue = frame.inputValue(name, description, value, type, notifyMe);
229                }
230                return inputValue;
231        }
232
233        @Override
234        public boolean isConsoleDefaultInput(String varName, String description) {
235                varName = StringUtils.defaultString(description, varName);
236                boolean consoleDefaultInput = "Error Trace".equals(varName) || frame.isConsoleDefaultInput();
237                if (varName != null && consoleDefaultInput) {
238                        Boolean checkPointFlag = false;
239                        InputDialogType[] values = InputDialogType.values();
240                        for (InputDialogType inputDialogType : values) {
241                                checkPointFlag = CheckPointBox.getCheckPointFlag(inputDialogType, varName);
242                                if (checkPointFlag != null) {
243                                        break;
244                                }
245                        }
246                        consoleDefaultInput = checkPointFlag != null && !checkPointFlag;
247                }
248                return consoleDefaultInput;
249        }
250
251        @Override
252        protected RecipeRunner createTestRunner(String name) {
253                return frame.editTask(name);
254        }
255
256        @Override
257        public String inputChoice(String name, String description, String[] aValues, String aDefaultValue,
258                        Processor taskProcessor, boolean notifyMe) {
259                return frame.inputSelectChoice(name, description, aValues, aDefaultValue, notifyMe);
260        }
261
262        public String inputFile(String name, String description, File defaultFile, ILogger log, Processor taskProcessor) {
263                String result = null;
264                description = StringUtils.defaultString(description, name);
265
266                String defaultUserConfiguration = getDefaultUserConfiguration(INPUT_FILE_NAME,
267                                defaultFile == null ? null : defaultFile.getAbsolutePath());
268                if (defaultUserConfiguration != null)
269                        defaultFile = new File(defaultUserConfiguration);
270
271                result = defaultUserConfiguration;
272
273                if (defaultUserConfiguration == null || !isConsoleDefaultInput(name, null)) {
274
275                        JFileChooser chooser = new JFileChooserExtension(name);
276
277                        if (defaultFile != null) {
278                                String path = defaultFile.getPath();
279                                if (path != null && !"null".equals(path)) {
280                                        if (defaultFile.isDirectory()) {
281                                                chooser.setCurrentDirectory(defaultFile.getParentFile());
282                                        } else {
283                                                chooser.setSelectedFile(defaultFile);
284                                        }
285                                }
286                        }
287
288                        chooser.setDialogTitle(description);
289                        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
290                        int showOpenDialog = chooser.showOpenDialog(JOptionPane.getRootFrame());
291                        if (showOpenDialog == JFileChooser.APPROVE_OPTION) {
292                                result = new File(chooser.getCurrentDirectory(), chooser.getSelectedFile().getName()).getAbsolutePath();
293                                setDefaultUserConfiguration(INPUT_FILE_NAME, result);
294                        } else if (showOpenDialog == JFileChooser.CANCEL_OPTION) {
295                                result = null;
296                                setDefaultUserConfiguration(INPUT_FILE_NAME, result);
297                        } else {
298                                taskProcessor.stop();
299                                result = null;
300                        }
301
302                }
303
304                CheckPointBox.setCheckPointFlag(InputDialogType.FILE, name, (boolean) ObjectUtils
305                                .defaultIfNull(CheckPointBox.getCheckPointFlag(InputDialogType.FILE, name), false));
306
307                return result;
308        }
309
310        @Override
311        public boolean confirmation(String name, String message, Processor unit, boolean notifyMe) throws Exception {
312
313                name = StringUtils.defaultIfEmpty(name, "Confirmation");
314                if (notifyMe) {
315                        frame.getSoundManager().play();
316                }
317
318                JOptionPane pane = new JOptionPane(message, JOptionPane.WARNING_MESSAGE, JOptionPane.YES_NO_OPTION);
319                JDialog dialog = pane.createDialog(frame, name);
320                dialog.setModal(false);
321                dialog.setResizable(true);
322
323                dialog.setVisible(true);
324                if (!UIUtils.applyPreferedView(dialog, name)) {
325                        dialog.pack();
326                }
327
328                Object value = null;
329                do {
330                        value = pane.getValue();
331                        Thread.sleep(100);
332                } while (value == "uninitializedValue");
333
334                if (notifyMe) {
335                        SoundManager.stop();
336                }
337
338                UIUtils.saveDialogPreferedView(dialog, name);
339                dialog.dispose();
340
341                if (value == null) {
342                        value = -1;
343                }
344
345                int confirm = (int) value;
346                if (confirm < 0) {
347                        unit.stop();
348                }
349                return confirm == JOptionPane.YES_OPTION;
350        }
351
352        @Override
353        public MessageHandler message(final Processor taskProcessor, String title, String message, boolean notifyMe) {
354                String dialogTitle = StringUtils.defaultIfEmpty(title, "Message");
355
356                JOptionPane pane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE);
357
358                JDialog dialog = pane.createDialog(frame, dialogTitle);
359                dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
360
361                MessageHandler handle = new MessageHandler() {
362                        @Override
363                        public void close() {
364                                dialog.dispose();
365                                super.close();
366                        }
367                };
368
369                dialog.addWindowListener(new WindowAdapter() {
370                        @Override
371                        public void windowClosed(WindowEvent var1) {
372                                if (!handle.isProcessDone()) {
373                                        taskProcessor.stop();
374                                }
375                                UIUtils.saveDialogPreferedView(dialog, dialogTitle);
376                                SoundManager.stop();
377                                frame.pushOnTop();
378                        }
379                });
380                dialog.setModal(false);
381                dialog.setResizable(true);
382
383                if (!UIUtils.applyPreferedView(dialog, dialogTitle)) {
384                        dialog.pack();
385                }
386
387                frame.pushOnTop();
388
389                if (notifyMe) {
390                        frame.getSoundManager().play();
391                }
392
393                dialog.setVisible(true);
394
395                return handle;
396        }
397
398        public void inputDataTable(Processor unit, Node aTableNode, boolean notifyMe) throws IOException {
399                Node[] theVariablesNodes = aTableNode.getNodes("var");
400
401                String fileName = aTableNode.getAttribute("file");
402                if (unit != null)
403                        fileName = unit.replaceProperties(aTableNode.getAttribute("file"));
404
405                if (fileName != null) {
406                        File file = unit.getFile(fileName);
407                        if (file.exists()) {
408                                BufferedReader theFileReader = new BufferedReader(new FileReader(file));
409                                String line = null;
410                                while ((line = theFileReader.readLine()) != null) {
411                                        line = line.trim();
412                                        if (!line.isEmpty() && line.charAt(0) != '#') {
413                                                int thePbrk = line.indexOf('=');
414
415                                                String theName = line.substring(0, thePbrk);
416                                                String theValue = line.substring(thePbrk + 1);
417
418                                                Node theNode = new Node("var");
419                                                theNode.setAttribute("name", theName);
420                                                theNode.setAttribute("value", theValue);
421
422                                                for (Node node : theVariablesNodes) {
423                                                        if (node.getAttribute("name").equalsIgnoreCase(theName)) {
424                                                                node.setAttribute("value", theValue);
425                                                        }
426                                                }
427                                        }
428                                }
429                                theFileReader.close();
430                        }
431                }
432
433                String title = aTableNode.getAttribute("name");
434                AbstractTableModel dataModel = new InputTableModel(unit, title, theVariablesNodes);
435
436                JTable table = new JTable(dataModel);
437                table.setRowHeight(20);
438                JScrollPane scrollpane = new JScrollPane(table);
439                CheckPointBox vip = new CheckPointBox(title, null, InputDialogType.MAP);
440
441                if ((!Processor.isSilentMode(unit) && !isConsoleDefaultInput(title, null)) || vip.isSelected()) {
442                        JPanel jPanel = new JPanel();
443                        jPanel.add(new JLabel(), BorderLayout.NORTH);
444                        jPanel.setLayout(new BorderLayout());
445                        jPanel.add(scrollpane, BorderLayout.CENTER);
446
447                        jPanel.add(vip, BorderLayout.SOUTH);
448
449                        if (notifyMe) {
450                                frame.getSoundManager().play();
451                        }
452
453                        int showConfirmDialog = OptionPane.showConfirmDialog(frame, jPanel, title);
454
455                        if (notifyMe) {
456                                SoundManager.stop();
457                        }
458
459                        if (showConfirmDialog == -1 || showConfirmDialog == 2) {
460                                unit.stop();
461                        }
462                }
463
464                FileWriter theFileReader = null;
465                if (fileName != null) {
466                        File file = unit.getFile(fileName);
467                        file.getParentFile().mkdirs();
468                        theFileReader = new FileWriter(file);
469                }
470
471                try {
472                        for (int row = 0; row < dataModel.getRowCount(); row++) {
473
474                                String name = StringUtils.upperCase((String) dataModel.getValueAt(row, 0));
475                                Object valueAt = dataModel.getValueAt(row, -1);
476                                if (valueAt != null) {
477                                        if (theFileReader != null) {
478                                                theFileReader.write(name + "=" + valueAt + "\n");
479                                        }
480                                        String value = null;
481                                        if (valueAt instanceof String) {
482                                                value = (String) valueAt;
483                                        } else if (valueAt instanceof String[] && ((String[]) valueAt).length > 0) {
484                                                value = ((String[]) valueAt)[0];
485                                        }
486                                        value = unit.replaceProperties(value);
487                                        AEWorkspace.getInstance().setDefaultUserConfiguration(".inputValue." + title + "." + name, value);
488                                        unit.setVariableValue(name, value);
489                                }
490
491                        }
492                } finally {
493                        if (theFileReader != null) {
494                                theFileReader.close();
495                        }
496                }
497        }
498
499        @Override
500        public String choiceValue(String name, String description, Object[] aPossibleValues, ILogger log, boolean notifyMe,
501                        Processor processor) {
502                return frame.choiceValue(name, description, aPossibleValues, notifyMe);
503        }
504
505        @Override
506        protected String choicePriorityRecipeFolder(String text, String[] possibleValues) {
507                return (String) JOptionPane.showInputDialog(frame, text, "Conflict of the names",
508                                JOptionPane.INFORMATION_MESSAGE, null, possibleValues, possibleValues[0]);
509        }
510
511        @Override
512        protected Node getConfiguration() throws IOException {
513
514                File configFile = getConfigurationFile();
515
516                if (configFile == null) {
517                        throw new ConfigurationException(AEWorkspace.ENVIRONMENT_FILE_TITLE + " (" + ConfigConstants.AE_CONFIG_XML
518                                        + ") must be defined in " + getHomeWorkingDir() + " or " + getStartDir() + ".");
519                }
520
521                setBaseDir(configFile.getParentFile());
522                Node object = null;
523
524                if (configFile.exists()) {
525                        object = new EasyParser().getObject(configFile);
526                } else {
527                        try {
528                                URL resource = new URL(configFile.toString());
529                                try (InputStream openStream = resource.openStream()) {
530                                        String recipeXml = IOUtils.toString(openStream);
531                                        object = new EasyParser().getObject(recipeXml);
532                                }
533                        } catch (Exception e) {
534                                object = null;
535                        }
536                }
537
538                return object;
539        }
540
541        @Override
542        public void setTestPath(String name, String path) {
543                super.setTestPath(name, path);
544                frame.getRecipesPanel().refreshTaskPathTable();
545        }
546
547        @Override
548        public void removeTestPath(String name) {
549                super.removeTestPath(name);
550                frame.getRecipesPanel().refreshTaskPathTable();
551        }
552
553        @Override
554        protected File findAlternativeConfiguration() {
555                File path = SystemUtils.getUserDir();
556                List<String> confFiles = findAEconfigs(path);
557
558                File confFile = null;
559                if (!confFiles.isEmpty()) {
560                        String project = frame.inputSelectChoice("Projects", null, confFiles.toArray(new String[confFiles.size()]),
561                                        confFiles.get(0), false);
562                        confFile = new File(project);
563                }
564
565                if (confFile == null) {
566                        confFile = selectConfiguration();
567                }
568
569                return confFile;
570        }
571
572        protected File selectConfiguration() {
573                File userDir = SystemUtils.getUserDir();
574                String config = AEWorkspace.getInstance()
575                                .getDefaultUserConfiguration(userDir.getPath() + CONFIG_SUFIX_PROP_NAME, null);
576
577                JFileChooser chooser;
578                if (config == null) {
579                        chooser = new JFileChooser();
580                        chooser.setCurrentDirectory(userDir);
581                } else {
582                        File file = new File(config);
583                        chooser = new JFileChooser(file.getParent());
584                        chooser.setSelectedFile(file);
585                }
586
587                chooser.setDialogTitle("Configuration File");
588                chooser.addChoosableFileFilter(new FileFilter() {
589                        @Override
590                        public String getDescription() {
591                                return AEWorkspace.CONFIGURATION_TITLE;
592                        }
593
594                        @Override
595                        public boolean accept(File f) {
596                                return FilenameUtils.isExtension(f.getName(), "xml");
597                        }
598                });
599
600                int returnVal = chooser.showOpenDialog(JOptionPane.getRootFrame());
601                if (returnVal == JFileChooser.APPROVE_OPTION) {
602                        File selectedFile = chooser.getSelectedFile();
603                        AEWorkspace.getInstance().setDefaultUserConfiguration(userDir.getPath() + CONFIG_SUFIX_PROP_NAME,
604                                        selectedFile.getAbsolutePath());
605                        return selectedFile;
606                }
607
608                return null;
609        }
610
611        public void resetConfiguration() {
612                super.resetConfiguration();
613                frame.resetConfiguration();
614        }
615
616        @Override
617        public void initUserPreferencesEncryption(String password) {
618                Node configNode = getConfigNode();
619                boolean userPreferencesEncryption = Boolean.parseBoolean(configNode.getAttribute("userPreferencesEncryption"));
620
621                if (userPreferencesEncryption) {
622                        do {
623                                if (password == null) {
624
625                                        JPanel panel = new JPanel(new BorderLayout(4, 4));
626                                        JLabel label = new JLabel(
627                                                        "<html>" + AEWorkspace.MESSAGE_PASSWORD_REQUIRED.replace("\n", "<br/>") + "</html>");
628                                        JPasswordField pass = new JPasswordField(20);
629                                        pass.putClientProperty("JPasswordField.cutCopyAllowed", true);
630
631                                        panel.add(label, BorderLayout.NORTH);
632                                        panel.add(pass, BorderLayout.CENTER);
633
634                                        Frame rootFrame = JOptionPane.getRootFrame();
635
636                                        int option = JOptionPane.showOptionDialog(rootFrame, panel, "User Preferences Encryption",
637                                                        JOptionPane.NO_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[] { "OK" }, "OK");
638
639                                        if (option == JOptionPane.CLOSED_OPTION) {
640                                                System.exit(1);
641                                        }
642
643                                        password = new String(pass.getPassword());
644                                        try {
645                                                super.initUserPreferencesEncryption(password);
646
647                                        } catch (Exception e) {
648
649                                                int showConfirmDialog = JOptionPane.showConfirmDialog(frame,
650                                                                "Incorrect key!\nReset the user preferences data?", "Error", JOptionPane.ERROR_MESSAGE,
651                                                                JOptionPane.YES_NO_OPTION);
652
653                                                if (showConfirmDialog == JOptionPane.YES_OPTION) {
654                                                        getUserPreferences().clear();
655                                                        try {
656                                                                File preferencesFile = getPreferencesFile();
657                                                                FileOutputStream fileInputStream = new FileOutputStream(preferencesFile);
658
659                                                                getUserPreferences().store(fileInputStream, null);
660                                                                fileInputStream.close();
661
662                                                        } catch (IOException e1) {
663                                                                e1.printStackTrace();
664                                                        }
665                                                }
666                                                if (showConfirmDialog == JOptionPane.CLOSED_OPTION) {
667                                                        System.exit(1);
668                                                }
669
670                                                password = null;
671                                        }
672                                }
673                        } while (password == null);
674                }
675        }
676}