001package com.ganteater.ae.processor; 002 003import java.io.BufferedReader; 004import java.io.File; 005import java.io.FileNotFoundException; 006import java.io.FileReader; 007import java.io.IOException; 008import java.io.StringReader; 009import java.lang.reflect.Constructor; 010import java.lang.reflect.InvocationTargetException; 011import java.lang.reflect.Method; 012import java.net.MalformedURLException; 013import java.net.URL; 014import java.net.URLClassLoader; 015import java.security.GeneralSecurityException; 016import java.security.SecureRandom; 017import java.security.cert.X509Certificate; 018import java.util.ArrayList; 019import java.util.Enumeration; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Map.Entry; 024import java.util.Properties; 025import java.util.Set; 026import java.util.Stack; 027import java.util.StringTokenizer; 028import java.util.Vector; 029import java.util.concurrent.ThreadPoolExecutor; 030import java.util.jar.Attributes; 031import java.util.jar.JarFile; 032import java.util.jar.Manifest; 033 034import javax.net.ssl.HttpsURLConnection; 035import javax.net.ssl.SSLContext; 036import javax.net.ssl.TrustManager; 037import javax.net.ssl.X509TrustManager; 038 039import org.apache.commons.collections.MapUtils; 040import org.apache.commons.lang.ObjectUtils; 041import org.apache.commons.lang.StringUtils; 042 043import com.ganteater.ae.AELogRecord; 044import com.ganteater.ae.AEManager; 045import com.ganteater.ae.CommandException; 046import com.ganteater.ae.ConfigConstants; 047import com.ganteater.ae.ILogger; 048import com.ganteater.ae.JarClassLoader; 049import com.ganteater.ae.RecipeListener; 050import com.ganteater.ae.TaskCancelingException; 051import com.ganteater.ae.TemplateProcessor; 052import com.ganteater.ae.util.AssertionFailedError; 053import com.ganteater.ae.util.xml.easyparser.EasyParser; 054import com.ganteater.ae.util.xml.easyparser.Node; 055import com.ganteater.ae.util.xml.easyparser.Node.TreeVector; 056 057@SuppressWarnings("deprecation") 058public abstract class Processor extends TemplateProcessor { 059 060 private static final String COMMAND_PREFIX = "runCommand"; 061 protected static final String DEFAULT_LOG_LEVEL_NAME = "DEFAULT_LOG_LEVEL"; 062 063 protected ILogger log; 064 065 protected String testName; 066 protected String testFile; 067 public Map<String, Object> startVariables; 068 private File startBaseDir; 069 private Processor parent = null; 070 protected Processor externProcessor = null; 071 072 protected RecipeListener recipeListener; 073 protected Vector<TaskProcessorThread> childThreads = new Vector<TaskProcessorThread>(); 074 protected Stack<Node> stackTask = new Stack<>(); 075 protected List<ThreadPoolExecutor> threadPoolList = new ArrayList<ThreadPoolExecutor>(); 076 protected Map<Class<?>, Object> operationObjects = new HashMap<Class<?>, Object>(); 077 078 private boolean mainProcessor = true; 079 protected boolean iteratorMode = false; 080 protected boolean mainLoopCommand = false; 081 private boolean pauseOn; 082 protected boolean randomSelect; 083 084 protected int breakFlag; 085 086 protected List<Process> processes = new ArrayList<>(); 087 protected boolean isRootContext; 088 private boolean silentMode = isSilentMode(null); 089 090 private Object monitor = new Object(); 091 092 static { 093 javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() { 094 public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { 095 return true; 096 } 097 }); 098 099 final TrustManager[] trustAllCertificates = new TrustManager[] { new X509TrustManager() { 100 @Override 101 public X509Certificate[] getAcceptedIssuers() { 102 return null; // Not relevant. 103 } 104 105 @Override 106 public void checkClientTrusted(X509Certificate[] certs, String authType) { 107 // Do nothing. Just allow them all. 108 } 109 110 @Override 111 public void checkServerTrusted(X509Certificate[] certs, String authType) { 112 // Do nothing. Just allow them all. 113 } 114 } }; 115 116 try { 117 SSLContext sc = SSLContext.getInstance("SSL"); 118 sc.init(null, trustAllCertificates, new SecureRandom()); 119 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 120 } catch (GeneralSecurityException e) { 121 throw new ExceptionInInitializerError(e); 122 } 123 } 124 125 protected Processor() { 126 } 127 128 public Processor(final Processor parent) throws CommandException { 129 init(parent); 130 } 131 132 public Processor(AEManager manager, ILogger log, File baseDir) { 133 this(new HashMap<String, Object>(manager.getSystemVariables()), manager.getConfigNode(), baseDir); 134 this.log = log; 135 } 136 137 public Processor(final Node configNode, final Map<String, Object> startVariables, final RecipeListener listener, 138 final File startDir, final ILogger aLog, final Processor parent) throws CommandException { 139 this(parent); 140 init(configNode, startVariables, listener, startDir, aLog); 141 } 142 143 public Processor(Map<String, Object> hashMap, Node node, File baseDir) { 144 super(hashMap, node, baseDir); 145 } 146 147 public void init(final Processor parent) throws CommandException { 148 this.parent = parent; 149 this.variables = new HashMap<String, Object>(parent.getListener().getManager().getSystemVariables()); 150 this.configNode = parent.getConfigNode(); 151 this.log = parent.getLog(); 152 setBaseDir(parent.getBaseDir()); 153 init(); 154 } 155 156 protected void init() throws CommandException { 157 } 158 159 public void init(final Node action, final Map<String, Object> aStartVariables, 160 final RecipeListener aMaxTestListener, final File aStartDir, final ILogger aLog) { 161 this.log = aLog; 162 163 this.configNode = action; 164 this.startVariables = aStartVariables; 165 if (aStartDir != null) { 166 this.startBaseDir = aStartDir; 167 setBaseDir(aStartDir); 168 } 169 170 if (this.startVariables != null) { 171 this.variables.putAll(this.startVariables); 172 } 173 174 setTestListener(aMaxTestListener); 175 } 176 177 public void init(final Processor aParent, Node action) throws CommandException { 178 this.mainProcessor = false; 179 this.log = aParent.log; 180 this.configNode = aParent.configNode; 181 this.startVariables = aParent.startVariables; 182 this.startBaseDir = aParent.startBaseDir; 183 setBaseDir(aParent.getBaseDir()); 184 this.variables = aParent.variables; 185 setTestListener(aParent.recipeListener); 186 this.parent = aParent; 187 } 188 189 protected Map<String, Object> processTesting(final String aTestFileName, final Map<String, Object> aVariables, 190 final File aBaseDir) throws Throwable { 191 this.variables = aVariables; 192 final File theBaseDir = getBaseDir(); 193 setBaseDir(aBaseDir); 194 processTesting(aTestFileName); 195 setBaseDir(theBaseDir); 196 return this.variables; 197 } 198 199 protected void processTesting(final String aTestFileName) throws CommandException { 200 if (aTestFileName == null) { 201 return; 202 } 203 204 Node theNode; 205 try { 206 theNode = new EasyParser().load(aTestFileName); 207 theNode.getVector(true); 208 209 } catch (Exception e) { 210 throw new CommandException("Recipe is not found: " + aTestFileName, this); 211 212 } 213 214 this.recipeListener.startTask(getTestName(theNode)); 215 processTesting(theNode, this.variables, new File(aTestFileName).getParentFile()); 216 } 217 218 public void processTesting(final Node theNode, final Map<String, Object> aVariables, final File aBaseDir) 219 throws CommandException { 220 221 this.variables = new HashMap<String, Object>(); 222 if (aVariables != null) { 223 this.variables.putAll(aVariables); 224 } 225 setBaseDir(aBaseDir); 226 227 if (this.startBaseDir == null) { 228 this.startBaseDir = getBaseDir(); 229 } 230 final String theDepends = theNode.getAttribute("depends"); 231 if (theDepends != null) { 232 final StringTokenizer theStringTokenizer = new StringTokenizer(theDepends, ";"); 233 while (theStringTokenizer.hasMoreTokens()) { 234 processTesting(theStringTokenizer.nextToken()); 235 setBaseDir(this.startBaseDir); 236 } 237 } 238 String taskName = theNode.getAttribute("name"); 239 if (taskName != null) { 240 debug("Recipe: \"" + taskName + "\""); 241 } 242 243 taskNode(theNode); 244 245 if (taskName != null) { 246 debug("Recipe: \"" + taskName + "\" done"); 247 } 248 } 249 250 public void taskNode(final Node aNode) throws CommandException { 251 taskNode(aNode, true); 252 } 253 254 public void taskNode(final Node aNode, boolean root) throws CommandException { 255 256 if (isStopped()) { 257 return; 258 } 259 260 if (getBaseDir() != null) { 261 setVariableValue("BASEDIR", getBaseDir().getPath()); 262 } 263 264 CommandException theTroubles = null; 265 266 final Vector<Node> theFinallyVector = new Vector<Node>(); 267 268 String description = getTaskDescription(aNode); 269 270 int i = 0; 271 int theNumberOperation = -1; 272 String recipeName = aNode.getAttribute("name"); 273 274 if (root) { 275 pushToStack(aNode, recipeName); 276 } 277 278 Node command = null; 279 try { 280 if (aNode != null) 281 while (++theNumberOperation < aNode.size() && isStopped() == false) { 282 283 command = (Node) aNode.get(theNumberOperation); 284 pushToStack(command, recipeName); 285 286 final String theRunMode = command.getAttribute("runMode"); 287 if (theRunMode != null && theRunMode.equals(this.recipeListener.getRunMode()) == false) { 288 continue; 289 } 290 291 String theDescription = command.getAttribute("description"); 292 293 theDescription = replaceProperties(theDescription); 294 if (theDescription != null) { 295 theDescription = replaceProperties(theDescription); 296 } 297 298 if (this.iteratorMode == false) { 299 progress(aNode.size(), i++, description, false); 300 } 301 302 if (SpecialCommands.LOGGER.equals(command.getTag())) { 303 continue; 304 } 305 306 final String exceptionVarName = replaceProperties(command.getAttribute("exception")); 307 try { 308 final String tagName = command.getTag(); 309 310 if (SpecialCommands.ELSE.equals(tagName)) { 311 continue; 312 } 313 314 if (SpecialCommands.BREAK.equals(tagName)) { 315 breakFlag++; 316 break; 317 } 318 319 if (SpecialCommands.STOP.equals(tagName)) { 320 String ifNull = command.getAttribute("ifNull"); 321 if (ifNull != null) { 322 String replaceProperties = replaceProperties(ifNull); 323 if (getVariableValue(replaceProperties) == null) { 324 stop(); 325 break; 326 } 327 } else { 328 stop(); 329 break; 330 } 331 } 332 333 if (SpecialCommands.FINALLY.equals(tagName)) { 334 theFinallyVector.add(command); 335 continue; 336 } 337 338 if (isStopped()) { 339 return; 340 } 341 startCommandInformation(command); 342 343 executeCommand(command); 344 345 if (exceptionVarName != null) { 346 setVariableValue(exceptionVarName, null); 347 } 348 349 } catch (final InvocationTargetException e) { 350 Throwable cause = e.getCause(); 351 352 if (!isStoppedTest()) { 353 if (exceptionVarName != null) { 354 this.recipeListener.exceptionIgnored(e); 355 setVariableValue(exceptionVarName, e.getCause().getMessage()); 356 357 } else { 358 if (!(cause instanceof TaskCancelingException) 359 && !(cause instanceof CommandException)) { 360 try { 361 this.recipeListener.errorInformation(this, cause, command); 362 theTroubles = null; 363 break; 364 365 } catch (final Exception e1) { 366 cause = e1; 367 } 368 } 369 370 if (cause instanceof TaskCancelingException) { 371 recipeListener.stopTest(); 372 } else if (cause instanceof CommandException) { 373 theTroubles = (CommandException) cause; 374 } else { 375 theTroubles = new CommandException(cause, this, command); 376 } 377 break; 378 } 379 } 380 } catch (final Throwable e) { 381 if (!isStoppedTest()) { 382 theTroubles = new CommandException(e, this, command); 383 } 384 385 } finally { 386 this.stackTask.pop(); 387 doPause(); 388 389 if (this.iteratorMode == false) { 390 progress(aNode.size(), i, description, theTroubles != null); 391 } 392 } 393 } 394 } finally { 395 boolean stoppedTest = isStopped(); 396 setStopped(false); 397 for (Node node : theFinallyVector) { 398 try { 399 taskNode(node, false); 400 } catch (final Throwable aThrowable) { 401 this.log.error("Exception in finally block.\n" 402 + new CommandException(aThrowable, this, command).getTaskTrace(), aThrowable); 403 } 404 } 405 setStopped(stoppedTest); 406 if (root) { 407 this.stackTask.pop(); 408 } 409 } 410 411 progress(100, 100, "", false); 412 413 if (theTroubles != null) { 414 if (isMainProcessor() && this.stackTask.size() == 0) { 415 416 final String theExceptionMode = replaceProperties(aNode.getAttribute("exception")); 417 if ("ignored".equals(theExceptionMode) || "ignore".equals(theExceptionMode)) { 418 this.recipeListener.exceptionIgnored(theTroubles); 419 return; 420 421 } else { 422 if (theTroubles.getCause() instanceof AssertionFailedError) { 423 this.recipeListener.checkFailure(theTroubles, this); 424 theTroubles = null; 425 } else { 426 this.recipeListener.criticalError(theTroubles, this); 427 } 428 } 429 } 430 431 if (theTroubles != null) { 432 throw theTroubles; 433 } 434 } 435 436 } 437 438 private void pushToStack(Node command, String recipeName) { 439 Node clone = (Node) command.clone(); 440 clone.clear(); 441 if (recipeName != null) { 442 clone.setAttribute("recipe", recipeName); 443 } 444 this.stackTask.push(clone); 445 } 446 447 private void executeCommand(Node action) throws IllegalAccessException, InvocationTargetException { 448 Node command; 449 Object paramsMap = attrValue(action, "attr-map"); 450 if (paramsMap instanceof Map) { 451 command = (Node) action.clone(); 452 command.removeAttribute("attr-map"); 453 @SuppressWarnings({ "unchecked", "rawtypes" }) 454 Set<Entry<String, String>> entrySet = ((Map) paramsMap).entrySet(); 455 for (Entry<String, String> entry : entrySet) { 456 String key = entry.getKey(); 457 String value = entry.getValue(); 458 if (command.getAttribute(key) == null) { 459 command.setAttribute(key, value); 460 } 461 } 462 } else { 463 command = action; 464 } 465 466 final String tagName = command.getTag(); 467 468 try { 469 final Method theMethod = getClass().getMethod(COMMAND_PREFIX + tagName.replace('$', '_'), 470 new Class[] { Node.class }); 471 472 theMethod.invoke(this, new Object[] { command }); 473 } catch (NoSuchMethodException e) { 474 } 475 } 476 477 public boolean isMainProcessor() { 478 return this.mainProcessor; 479 } 480 481 public String getTestName() { 482 return this.testName; 483 } 484 485 public void setTestName(String testName) { 486 this.testName = testName; 487 } 488 489 public void regChildProcess(final TaskProcessorThread aMaxTestRunnable) { 490 this.recipeListener.startChildProcess(aMaxTestRunnable); 491 this.childThreads.add(aMaxTestRunnable); 492 } 493 494 public void unregChildProcess(final TaskProcessorThread aMaxTestRunnable) { 495 this.recipeListener.stopChildProcess(aMaxTestRunnable); 496 this.childThreads.remove(aMaxTestRunnable); 497 } 498 499 public Node getConfigNode() { 500 return this.configNode; 501 } 502 503 public Map<String, Object> getStartVariables() { 504 return this.startVariables; 505 } 506 507 public RecipeListener getListener() { 508 return this.recipeListener; 509 } 510 511 public Map<String, Object> getVariables() { 512 return this.variables; 513 } 514 515 public int getChildThreads() { 516 return this.childThreads.size(); 517 } 518 519 public ILogger getLog() { 520 return log; 521 } 522 523 public void runNodes(final Node[] aTheNodes) throws CommandException { 524 525 for (int i = 0; i < aTheNodes.length; i++) { 526 if (isStopped()) { 527 break; 528 } 529 final Node theNode = aTheNodes[i]; 530 taskNode(theNode, false); 531 } 532 } 533 534 public void setTestListener(final RecipeListener testListener) { 535 this.recipeListener = testListener; 536 } 537 538 public void startCommandInformation(final Node command) { 539 final String theID = command.getAttribute(Node.TAG_ID); 540 541 boolean isRootRecipe = isRootRecipe(); 542 543 if (this.recipeListener != null && theID != null && isRootRecipe) { 544 this.recipeListener.startCommand(Integer.parseInt(theID)); 545 } 546 } 547 548 protected boolean isRootRecipe() { 549 int recipeNodeCount = 0; 550 for (Object node : this.stackTask.toArray()) { 551 if ("Recipe".equals(((Node)node).getTag())) { 552 recipeNodeCount++; 553 } 554 } 555 boolean isRootRecipe = recipeNodeCount == 1 || isRootContext; 556 return isRootRecipe; 557 } 558 559 protected String getTestName(final Node aNode) { 560 String theAttribut = aNode.getAttribute("name"); 561 if (theAttribut == null || theAttribut.trim().length() == 0) { 562 theAttribut = aNode.getAttribute("description"); 563 } 564 return replaceProperties(theAttribut); 565 } 566 567 private String getTaskDescription(final Node aNode) { 568 if (aNode == null) { 569 return null; 570 } 571 String theTaskDescription = aNode.getAttribute("name"); 572 if (theTaskDescription == null || theTaskDescription.trim().length() == 0) { 573 theTaskDescription = aNode.getAttribute("description"); 574 } 575 final String theTag = aNode.getTag(); 576 if (theTag.equals("Recipe")) { 577 startTask(theTaskDescription, aNode.getAttribute("description")); 578 } else if (theTag.equals(SpecialCommands.STARTUP)) { 579 if (theTaskDescription == null) { 580 theTaskDescription = SpecialCommands.STARTUP; 581 } 582 startTask(theTaskDescription, SpecialCommands.STARTUP); 583 } else { 584 theTaskDescription = aNode.getAttribute("description"); 585 } 586 return theTaskDescription; 587 } 588 589 private void startTask(String name, String description) { 590 this.testName = name; 591 this.recipeListener.startTask(name); 592 } 593 594 protected String getTrimmedLines(String theValue1) throws IOException { 595 final BufferedReader theStringReader = new BufferedReader(new StringReader(theValue1)); 596 String theLine = ""; 597 final StringBuffer theBuffer = new StringBuffer(); 598 while ((theLine = theStringReader.readLine()) != null) { 599 final String theTrimmedLine = theLine.trim(); 600 if (theTrimmedLine.length() > 0) { 601 theBuffer.append(theTrimmedLine); 602 theBuffer.append('\n'); 603 } 604 } 605 theValue1 = theBuffer.toString(); 606 return theValue1; 607 } 608 609 protected String[] randomSort(final String[] aArray) { 610 final Vector<String> theVector = new Vector<String>(); 611 for (int i = 0; i < aArray.length; i++) { 612 theVector.add(aArray[i]); 613 } 614 final String[] theResult = new String[theVector.size()]; 615 616 for (int l = 0; l < aArray.length; l++) { 617 final int theNumber = (int) (Math.random() * (theVector.size())); 618 theResult[l] = theVector.elementAt(theNumber); 619 theVector.removeElementAt(theNumber); 620 } 621 622 return theResult; 623 } 624 625 static public String prepareXml(String theCurrentValue) { 626 final int head = theCurrentValue.indexOf("<?"); 627 if (head >= 0) { 628 final int end = theCurrentValue.indexOf("?>"); 629 theCurrentValue = theCurrentValue.substring(end + 2).trim(); 630 } 631 return theCurrentValue; 632 } 633 634 protected Properties replaceAttributes(Node aCurrentAction) { 635 Map<String, String> attributes = aCurrentAction.getAttributes(); 636 Properties properties = MapUtils.toProperties(attributes); 637 Set<Entry<Object, Object>> entrySet = properties.entrySet(); 638 Properties props = new Properties(); 639 for (Entry<Object, Object> entry : entrySet) { 640 String key = (String) entry.getKey(); 641 String value = (String) entry.getValue(); 642 643 String replaceProperties = replaceProperties(value); 644 props.setProperty(key, replaceProperties); 645 } 646 return props; 647 } 648 649 protected void outputLog(String varName, final String theLevelAttribut, final Object theTextOut, String type) { 650 651 AELogRecord logRecord = new AELogRecord(theTextOut, type, varName); 652 653 if ("info".equals(theLevelAttribut)) { 654 this.log.info(logRecord); 655 } 656 if ("error".equals(theLevelAttribut)) { 657 this.log.error(logRecord); 658 } 659 if ("debug".equals(theLevelAttribut)) { 660 debug(logRecord); 661 } 662 if ("warn".equals(theLevelAttribut)) { 663 this.log.warn(logRecord); 664 } 665 } 666 667 protected boolean isActiveInitFor(final Node action, String value) { 668 return StringUtils.contains(attr(action, "init"), value); 669 } 670 671 protected String getFields(final Properties theOutArrayList) { 672 final StringBuffer theResult = new StringBuffer(); 673 for (final Enumeration<?> e = theOutArrayList.propertyNames(); e.hasMoreElements();) { 674 final String theName = (String) e.nextElement(); 675 final String theValue = theOutArrayList.getProperty(theName); 676 theResult.append(theName); 677 theResult.append("="); 678 theResult.append(theValue); 679 theResult.append(";"); 680 } 681 return theResult.toString(); 682 } 683 684 protected void applyResult(final Node commandNode, final String name, final Object value) { 685 setVariableValue(name, value); 686 687 String level = replaceProperties(commandNode.getAttribute("level")); 688 String type = replaceProperties(commandNode.getAttribute("type")); 689 if (level != null) { 690 outputLog(name, level, value, type); 691 } 692 } 693 694 public void setStartDir(final File aStartBaseDir) { 695 this.startBaseDir = aStartBaseDir; 696 } 697 698 protected void progress(final long theSize, final long aValue, String aDescription, final boolean aErrorState) { 699 try { 700 if (aDescription == null || aDescription.length() == 0) { 701 aDescription = new String(" "); 702 } 703 704 boolean loopActivated = isLoopActivated(); 705 706 if (!loopActivated) { 707 this.recipeListener.setProgress(aDescription, theSize, aValue, aErrorState); 708 } 709 } catch (final Throwable e) { 710 } 711 } 712 713 protected boolean isLoopActivated() { 714 boolean result = false; 715 Processor parent = getParent(); 716 if (parent != null) { 717 result = parent.isLoopActivated(); 718 } 719 if (!result) { 720 result = mainLoopCommand; 721 } 722 return result; 723 } 724 725 @Override 726 public File getFile(String path) { 727 path = replaceProperties(path); 728 return this.recipeListener.getManager().getFile(path); 729 } 730 731 public void make(final String aTestFile) throws CommandException { 732 this.testFile = aTestFile; 733 try { 734 if (this.recipeListener != null && isStopped() == false) { 735 this.recipeListener.startTask(this.testFile); 736 processTesting(this.testFile); 737 this.recipeListener.endTask(false); 738 } else { 739 throw new RuntimeException(); 740 } 741 742 } finally { 743 744 if (this.testName != null) { 745 debug("Recipe '" + this.testName + "' is stopped."); 746 } 747 } 748 } 749 750 public void stop() { 751 super.stop(); 752 753 if (getChildThreads() > 0) { 754 debug("Child's threads: " + getChildThreads()); 755 } 756 757 if (this.externProcessor != null && this.externProcessor != this && !externProcessor.isStoppedTest()) { 758 this.externProcessor.stop(); 759 } 760 761 if (this.configNode == null) { 762 return; 763 } 764 765 synchronized (monitor) { 766 monitor.notify(); 767 } 768 769 for (Process process : processes) { 770 debug("Request to destroy a child process:" + process.destroyForcibly()); 771 } 772 processes.clear(); 773 774 stopChilds(); 775 776 for (ThreadPoolExecutor pool : threadPoolList) { 777 pool.shutdownNow(); 778 } 779 780 while (!isStoppedTest()) { 781 try { 782 synchronized (monitor) { 783 monitor.wait(100); 784 } 785 } catch (InterruptedException e) { 786 Thread.currentThread().interrupt(); 787 } 788 } 789 790 RecipeListener listener = getListener(); 791 if (listener != null) { 792 listener.endTask(false); 793 } 794 795 if (parent != null && !parent.isStoppedTest()) { 796 parent.stop(); 797 } 798 } 799 800 private void stopChilds() { 801 List<TaskProcessorThread> fChildThreads2 = new ArrayList<>(childThreads); 802 for (TaskProcessorThread child : fChildThreads2) { 803 child.stopTest(); 804 805 while (!child.getProcessor().isStoppedTest()) { 806 try { 807 synchronized (monitor) { 808 monitor.wait(100); 809 } 810 } catch (InterruptedException e) { 811 Thread.currentThread().interrupt(); 812 } 813 } 814 } 815 } 816 817 static class SystemCommandStart extends Thread { 818 private final String fCommandAttribut; 819 820 ILogger fLog; 821 822 public SystemCommandStart(final String aCommandAttribut, final ILogger aLog) { 823 this.fLog = aLog; 824 this.fCommandAttribut = aCommandAttribut; 825 } 826 827 @Override 828 public void run() { 829 try { 830 Runtime.getRuntime().exec(this.fCommandAttribut); 831 } catch (final IOException e) { 832 this.fLog.error("System command starting is failed.", e); 833 } 834 } 835 836 } 837 838 protected String replaceXmlReference(String aValue) throws Exception { 839 aValue = replaceFile(aValue); 840 final String theStartKey = "&#"; 841 final String theEndKey = ";"; 842 int theBeginPos = 0; 843 int theEndPos = 0; 844 if (aValue == null) { 845 return aValue; 846 } 847 final StringBuffer theStringBuffer = new StringBuffer(); 848 while (true) { 849 theBeginPos = aValue.indexOf(theStartKey, theEndPos); 850 if (theBeginPos < 0) { 851 break; 852 } 853 theStringBuffer.append(aValue.substring(theEndPos, theBeginPos)); 854 theEndPos = aValue.indexOf(theEndKey, theBeginPos); 855 if (theEndPos < 0) { 856 throw new Exception("Variable getting incorrect syntax, absent symbol '" + theEndKey + "'."); 857 } 858 String theNameProperty = aValue.substring(theBeginPos + theStartKey.length(), theEndPos); 859 final int defaultPos = theNameProperty.indexOf(','); 860 if (defaultPos >= 0) { 861 theNameProperty = theNameProperty.substring(0, defaultPos); 862 } 863 final String theValue = new String(new char[] { (char) Integer.parseInt(theNameProperty) }); 864 theStringBuffer.append(theValue); 865 theEndPos += theEndKey.length(); 866 } 867 theStringBuffer.append(aValue.substring(theEndPos)); 868 return theStringBuffer.toString(); 869 } 870 871 public Processor makeProcessor(final Node aCurrentAction) 872 throws IOException, ClassNotFoundException, MalformedURLException, FileNotFoundException, 873 NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, CommandException { 874 String className = replaceProperties(aCurrentAction.getAttribute("class")); 875 876 if (StringUtils.indexOf(className, '.') < 0) { 877 className = "com.ganteater.ae.processor." + className; 878 } 879 880 final String pluginJar = replaceProperties(aCurrentAction.getAttribute("plugin")); 881 882 Class<?> theClass = null; 883 if (pluginJar != null) { 884 final File file = getFile(pluginJar); 885 886 if (file.isFile()) { 887 final JarClassLoader jarLoader = new JarClassLoader(file); 888 if (className == null) { 889 final JarFile jarFile = new JarFile(file); 890 try { 891 final Manifest manifest = jarFile.getManifest(); 892 final Attributes mainAttributes = manifest.getMainAttributes(); 893 className = mainAttributes.getValue("AE-Class"); 894 } finally { 895 jarFile.close(); 896 } 897 } 898 theClass = jarLoader.loadClass(className, true); 899 } else if (file.isDirectory()) { 900 try (URLClassLoader classLoader = new URLClassLoader(new URL[] { file.toURL() })) { 901 theClass = classLoader.loadClass(className); 902 } 903 } else { 904 throw new FileNotFoundException(pluginJar); 905 } 906 907 } else { 908 theClass = getClass().getClassLoader().loadClass(className); 909 } 910 911 final Constructor<?> constructor = theClass.getConstructor(); 912 final Processor newInstance = (Processor) constructor.newInstance(); 913 if (isRootRecipe()) { 914 newInstance.setRootContext(true); 915 newInstance.setTestListener(recipeListener); 916 } 917 newInstance.init(this); 918 return newInstance; 919 } 920 921 public void loadProperties(final String aParameterRule, final String aDelim, 922 final Map<String, Object> aMapProperties, final boolean aNameUpperCase) throws Exception { 923 final StringTokenizer theStringTokenizer = new StringTokenizer(aParameterRule, aDelim); 924 while (theStringTokenizer.hasMoreTokens()) { 925 final String theLine = theStringTokenizer.nextToken(); 926 if (theLine == null || theLine.length() == 0 || (theLine.length() > 0 && theLine.trim().charAt(0) == '#')) { 927 continue; 928 } 929 final int thePbrk = theLine.indexOf('='); 930 String theName = replaceProperties(theLine.substring(0, thePbrk)); 931 final String theValue = replaceProperties(theLine.substring(thePbrk + 1)); 932 if (aNameUpperCase) { 933 theName = theName.toUpperCase(); 934 } 935 aMapProperties.put(theName, theValue); 936 } 937 } 938 939 public void loadProperties(final File aFile, final Map<String, Object> theProperties, final boolean aNameUpperCase) 940 throws Exception { 941 final BufferedReader theFileReader = new BufferedReader(new FileReader(aFile)); 942 try { 943 String theLine = null; 944 while ((theLine = theFileReader.readLine()) != null) { 945 if (theLine == null || theLine.length() == 0 946 || (theLine.length() > 0 && theLine.trim().charAt(0) == '#')) { 947 continue; 948 } 949 final int thePbrk = theLine.indexOf('='); 950 if (thePbrk < 0) { 951 try { 952 String theExtLine = replaceProperties(theLine); 953 theExtLine = theExtLine.replace('\r', '\n'); 954 loadProperties(theExtLine, "\n", theProperties, aNameUpperCase); 955 } catch (final StringIndexOutOfBoundsException e) { 956 throw new Exception("Incorrect data in properties file. File: " + aFile.getAbsolutePath() 957 + "\nLine: " + theLine); 958 } 959 continue; 960 } 961 String theName = replaceProperties(theLine.substring(0, thePbrk)); 962 final String theValue = replaceProperties(theLine.substring(thePbrk + 1)); 963 if (aNameUpperCase) { 964 theName = theName.toUpperCase(); 965 } 966 theProperties.put(theName, theValue); 967 } 968 } finally { 969 theFileReader.close(); 970 } 971 } 972 973 public static String[] listToArray(final ArrayList<?> theResult) { 974 final String[] theResultArray = new String[theResult.size()]; 975 for (int i = 0; i < theResultArray.length; i++) { 976 theResultArray[i] = (String) theResult.get(i); 977 } 978 return theResultArray; 979 } 980 981 protected void setRootContext(boolean isRootContext) { 982 this.isRootContext = isRootContext; 983 } 984 985 public Processor getParent() { 986 return this.parent; 987 } 988 989 public void complete(boolean success) { 990 stopChilds(); 991 } 992 993 public Stack<Node> getLocalTaskTrace() { 994 return this.stackTask; 995 } 996 997 public Vector<Object> getCallTaskTrace() { 998 final TreeVector result = new TreeVector(getTestName()); 999 final Vector<Node> trace = getLocalTaskTrace(); 1000 result.addAll(trace); 1001 return result; 1002 } 1003 1004 public ILogger getLogger() { 1005 return this.log; 1006 } 1007 1008 @Override 1009 protected String replaceCall(final String aValue) { 1010 final String theStartKey = "$call{"; 1011 final String theEndKey = "}"; 1012 int theBeginPos = 0; 1013 int theEndPos = 0; 1014 if (aValue == null) { 1015 return aValue; 1016 } 1017 1018 final StringBuffer theStringBuffer = new StringBuffer(); 1019 while (true) { 1020 theBeginPos = aValue.indexOf(theStartKey, theEndPos); 1021 if (theBeginPos < 0) { 1022 break; 1023 } 1024 theStringBuffer.append(aValue.substring(theEndPos, theBeginPos)); 1025 theEndPos = aValue.indexOf(theEndKey, theBeginPos); 1026 if (theEndPos < 0) { 1027 throw new RuntimeException("Tag created is incorrect syntax, absent symbol '" + theEndKey + "'."); 1028 } 1029 1030 final String theLine = aValue.substring(theBeginPos + theStartKey.length(), theEndPos); 1031 final int thePbrk = theLine.indexOf(','); 1032 String theTagName = theLine; 1033 String theNameVar = theLine; 1034 if (thePbrk > 0) { 1035 theTagName = theLine.substring(0, thePbrk); 1036 theNameVar = theLine.substring(thePbrk + 1); 1037 } else { 1038 theTagName = theLine; 1039 theNameVar = "RETURN"; 1040 } 1041 1042 Object theObjValue = null; 1043 if (StringUtils.startsWith(theTagName, "fn:")) { 1044 1045 if (StringUtils.equals(theTagName, "fn:currentTimeMillis")) { 1046 theObjValue = Long.toString(System.currentTimeMillis()); 1047 } 1048 1049 } else { 1050 1051 final String theFileAttribut = getListener().getManager().getTestPath(theTagName); 1052 1053 try { 1054 final Processor theTestUnit = new BaseProcessor(this); 1055 theTestUnit.init(this.configNode, this.variables, this.recipeListener, this.startBaseDir, 1056 this.log); 1057 final Map<String, Object> theVariables = theTestUnit.processTesting(theFileAttribut, 1058 this.variables, getBaseDir()); 1059 String name = StringUtils.upperCase(theNameVar); 1060 theObjValue = theVariables.get(name); 1061 1062 } catch (final Throwable e) { 1063 throw new RuntimeException(e); 1064 } 1065 } 1066 1067 String theValue = null; 1068 if (theObjValue instanceof String) { 1069 theValue = (String) theObjValue; 1070 } else if (theObjValue instanceof String[] && ((String[]) theObjValue).length > 0) { 1071 theValue = ((String[]) theObjValue)[0]; 1072 } else { 1073 theValue = ObjectUtils.toString(theObjValue); 1074 } 1075 theStringBuffer.append(theValue); 1076 theEndPos += theEndKey.length(); 1077 } 1078 1079 theStringBuffer.append(aValue.substring(theEndPos)); 1080 return theStringBuffer.toString(); 1081 } 1082 1083 public void pause() { 1084 this.pauseOn = true; 1085 if (parent != null) { 1086 parent.pauseOn = this.pauseOn; 1087 } 1088 if (externProcessor != null) { 1089 externProcessor.pauseOn = this.pauseOn; 1090 } 1091 for (final Enumeration<TaskProcessorThread> theEnum = this.childThreads.elements(); theEnum 1092 .hasMoreElements();) { 1093 final TaskProcessorThread theRunnTest = theEnum.nextElement(); 1094 theRunnTest.getProcessor().pause(); 1095 } 1096 getListener().pause(); 1097 } 1098 1099 public void resume() { 1100 this.pauseOn = false; 1101 if (externProcessor != null) { 1102 externProcessor.pauseOn = this.pauseOn; 1103 } 1104 if (parent != null) { 1105 parent.pauseOn = this.pauseOn; 1106 } 1107 for (final Enumeration<TaskProcessorThread> theEnum = this.childThreads.elements(); theEnum 1108 .hasMoreElements();) { 1109 final TaskProcessorThread theRunnTest = theEnum.nextElement(); 1110 theRunnTest.getProcessor().resume(); 1111 } 1112 getListener().resume(); 1113 } 1114 1115 private void doPause() { 1116 while (this.pauseOn) { 1117 try { 1118 synchronized (monitor) { 1119 monitor.wait(100); 1120 } 1121 } catch (final InterruptedException e) { 1122 Thread.currentThread().interrupt(); 1123 } 1124 } 1125 } 1126 1127 protected void debug(Object message) { 1128 log.debug(message); 1129 } 1130 1131 protected void debug(Object message, Exception e) { 1132 log.debug(message, e); 1133 } 1134 1135 public void setLogger(final ILogger logger) { 1136 this.log = logger; 1137 } 1138 1139 public boolean isStoppedTest() { 1140 return isStopped(); 1141 } 1142 1143 public String attr(Node action, String name, String defaultValue) { 1144 String value = attr(action, name); 1145 return StringUtils.defaultIfEmpty(value, defaultValue); 1146 } 1147 1148 public String attr(Node action, String name) { 1149 name = replaceProperties(name); 1150 String attribute = action.getAttribute(name); 1151 return replaceProperties(attribute); 1152 } 1153 1154 public Object attrValue(Node action, String name) { 1155 name = replaceProperties(name); 1156 String value = attr(action, name); 1157 return getVariableValue(value); 1158 } 1159 1160 public static void setSilentMode(Processor unit, boolean silentMode) { 1161 if (unit != null) { 1162 unit.silentMode = silentMode; 1163 } 1164 } 1165 1166 public static boolean isSilentMode(Processor unit) { 1167 boolean result; 1168 if (unit != null) { 1169 result = unit.silentMode; 1170 } else { 1171 result = Boolean.parseBoolean(System.getProperty(ConfigConstants.TAKE_IT_EASY_MODE, "false")); 1172 } 1173 1174 return result; 1175 } 1176 1177 protected void wait(final String value) { 1178 synchronized (monitor) { 1179 try { 1180 monitor.wait(Integer.parseInt(value)); 1181 } catch (InterruptedException e) { 1182 getLog().debug(e.getMessage()); 1183 stop(); 1184 } 1185 } 1186 } 1187 1188}