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}