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