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}