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.security.GeneralSecurityException; 014import java.security.SecureRandom; 015import java.security.cert.X509Certificate; 016import java.util.ArrayList; 017import java.util.Calendar; 018import java.util.Date; 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; 030 031import javax.net.ssl.HttpsURLConnection; 032import javax.net.ssl.SSLContext; 033import javax.net.ssl.TrustManager; 034import javax.net.ssl.X509TrustManager; 035 036import org.apache.commons.collections.MapUtils; 037import org.apache.commons.lang.ObjectUtils; 038import org.apache.commons.lang.StringUtils; 039import org.apache.commons.lang.math.NumberUtils; 040 041import com.ganteater.ae.AELogRecord; 042import com.ganteater.ae.AEManager; 043import com.ganteater.ae.CommandException; 044import com.ganteater.ae.ConfigConstants; 045import com.ganteater.ae.ILogger; 046import com.ganteater.ae.RecipeListener; 047import com.ganteater.ae.RecipeRunner; 048import com.ganteater.ae.TaskCancelingException; 049import com.ganteater.ae.TemplateProcessor; 050import com.ganteater.ae.util.AssertionFailedError; 051import com.ganteater.ae.util.xml.easyparser.EasyParser; 052import com.ganteater.ae.util.xml.easyparser.Node; 053import com.ganteater.ae.util.xml.easyparser.Node.TreeVector; 054 055@SuppressWarnings("deprecation") 056public abstract class Processor extends TemplateProcessor { 057 058 public static final String STG_PROCESSOR_PACKAGE_NAME = "com.ganteater.ae.processor."; 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> variables, final RecipeListener aMaxTestListener, 160 final File aStartDir, final ILogger aLog) { 161 this.log = aLog; 162 163 this.configNode = action; 164 this.startVariables = variables; 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 parentProcessor, Node action) throws CommandException { 178 this.mainProcessor = false; 179 this.log = parentProcessor.log; 180 this.configNode = parentProcessor.configNode; 181 this.startVariables = parentProcessor.startVariables; 182 this.startBaseDir = parentProcessor.startBaseDir; 183 setBaseDir(parentProcessor.getBaseDir()); 184 this.variables = parentProcessor.variables; 185 setTestListener(parentProcessor.recipeListener); 186 this.parent = parentProcessor; 187 } 188 189 protected Map<String, Object> processTesting(final String testFileName, final Map<String, Object> variables, 190 final File baseDir) throws Throwable { 191 this.variables = variables; 192 final File theBaseDir = getBaseDir(); 193 setBaseDir(baseDir); 194 processTesting(testFileName); 195 setBaseDir(theBaseDir); 196 return this.variables; 197 } 198 199 protected void processTesting(final String testFileName) throws CommandException { 200 if (testFileName == null) { 201 return; 202 } 203 204 Node theNode; 205 try { 206 theNode = new EasyParser().load(testFileName); 207 theNode.getVector(true); 208 209 } catch (Exception e) { 210 throw new CommandException("Recipe is not found: " + testFileName, this); 211 212 } 213 214 this.recipeListener.startTask(getTestName(theNode)); 215 processTesting(theNode, this.variables, new File(testFileName).getParentFile()); 216 } 217 218 public void processTesting(final Node node, final Map<String, Object> variables, final File baseDir) 219 throws CommandException { 220 221 this.variables = new HashMap<String, Object>(); 222 if (variables != null) { 223 this.variables.putAll(variables); 224 } 225 setBaseDir(baseDir); 226 227 if (this.startBaseDir == null) { 228 this.startBaseDir = getBaseDir(); 229 } 230 final String theDepends = node.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 = node.getAttribute("name"); 239 if (taskName != null) { 240 debug("Recipe: \"" + taskName + "\""); 241 } 242 243 taskNode(node); 244 245 if (taskName != null) { 246 debug("Recipe: \"" + taskName + "\" done"); 247 } 248 } 249 250 public void taskNode(final Node node) throws CommandException { 251 taskNode(node, true); 252 } 253 254 public void taskNode(final Node node, 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> finallyVector = new Vector<Node>(); 267 268 String description = getTaskDescription(node); 269 270 int i = 0; 271 int theNumberOperation = -1; 272 String recipeName = node.getAttribute("name"); 273 274 if (root) { 275 pushToStack(node, recipeName); 276 } 277 278 Node command = null; 279 try { 280 if (node != null) 281 while (++theNumberOperation < node.size() && isStopped() == false) { 282 283 command = (Node) node.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(node.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 finallyVector.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(node.size(), i, description, theTroubles != null); 391 } 392 } 393 } 394 } finally { 395 boolean stoppedTest = isStopped(); 396 setStopped(false); 397 for (Node curNode : finallyVector) { 398 try { 399 taskNode(curNode, 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 if (theTroubles == null) { 412 progress(100, 100, "", false); 413 } else { 414 progress(node.size(), i, description, true); 415 } 416 417 if (theTroubles != null) { 418 if (isMainProcessor() && this.stackTask.size() == 0) { 419 420 final String theExceptionMode = replaceProperties(node.getAttribute("exception")); 421 if ("ignored".equals(theExceptionMode) || "ignore".equals(theExceptionMode)) { 422 this.recipeListener.exceptionIgnored(theTroubles); 423 return; 424 425 } else { 426 if (theTroubles.getCause() instanceof AssertionFailedError) { 427 this.recipeListener.checkFailure(theTroubles, this); 428 theTroubles = null; 429 } else { 430 this.recipeListener.criticalError(theTroubles, this); 431 } 432 } 433 } 434 435 if (theTroubles != null) { 436 throw theTroubles; 437 } 438 } 439 440 } 441 442 private void pushToStack(Node command, String recipeName) { 443 Node clone = (Node) command.clone(); 444 clone.clear(); 445 if (recipeName != null) { 446 clone.setAttribute("recipe", recipeName); 447 } 448 this.stackTask.push(clone); 449 } 450 451 private void executeCommand(Node action) throws IllegalAccessException, InvocationTargetException { 452 Node command; 453 Object paramsMap = attrValue(action, "attr-map"); 454 if (paramsMap instanceof Map) { 455 command = (Node) action.clone(); 456 command.removeAttribute("attr-map"); 457 @SuppressWarnings({ "unchecked", "rawtypes" }) 458 Set<Entry<String, String>> entrySet = ((Map) paramsMap).entrySet(); 459 for (Entry<String, String> entry : entrySet) { 460 String key = entry.getKey(); 461 String value = entry.getValue(); 462 if (command.getAttribute(key) == null) { 463 command.setAttribute(key, value); 464 } 465 } 466 } else { 467 command = action; 468 } 469 470 final String tagName = command.getTag(); 471 472 try { 473 final Method theMethod = getClass().getMethod(COMMAND_PREFIX + tagName.replace('$', '_'), 474 new Class[] { Node.class }); 475 476 theMethod.invoke(this, new Object[] { command }); 477 } catch (NoSuchMethodException e) { 478 } 479 } 480 481 public boolean isMainProcessor() { 482 return this.mainProcessor; 483 } 484 485 public String getTestName() { 486 return this.testName; 487 } 488 489 public void setTestName(String testName) { 490 this.testName = testName; 491 } 492 493 public void regChildProcess(final TaskProcessorThread aMaxTestRunnable) { 494 this.recipeListener.startChildProcess(aMaxTestRunnable); 495 this.childThreads.add(aMaxTestRunnable); 496 } 497 498 public void unregChildProcess(final TaskProcessorThread aMaxTestRunnable) { 499 this.recipeListener.stopChildProcess(aMaxTestRunnable); 500 this.childThreads.remove(aMaxTestRunnable); 501 } 502 503 public Node getConfigNode() { 504 return this.configNode; 505 } 506 507 public Map<String, Object> getStartVariables() { 508 return this.startVariables; 509 } 510 511 public RecipeListener getListener() { 512 return this.recipeListener; 513 } 514 515 public Map<String, Object> getVariables() { 516 return this.variables; 517 } 518 519 public int getChildThreads() { 520 return this.childThreads.size(); 521 } 522 523 public ILogger getLog() { 524 return log; 525 } 526 527 public void runNodes(final Node[] aTheNodes) throws CommandException { 528 529 for (int i = 0; i < aTheNodes.length; i++) { 530 if (isStopped()) { 531 break; 532 } 533 final Node theNode = aTheNodes[i]; 534 taskNode(theNode, false); 535 } 536 } 537 538 public void setTestListener(final RecipeListener testListener) { 539 this.recipeListener = testListener; 540 } 541 542 public void startCommandInformation(final Node command) { 543 final String theID = command.getAttribute(Node.TAG_ID); 544 545 boolean isRootRecipe = isRootRecipe(); 546 547 if (this.recipeListener != null && theID != null && isRootRecipe) { 548 this.recipeListener.startCommand(Integer.parseInt(theID)); 549 } 550 } 551 552 protected boolean isRootRecipe() { 553 int recipeNodeCount = 0; 554 for (Object node : this.stackTask.toArray()) { 555 if ("Recipe".equals(((Node) node).getTag())) { 556 recipeNodeCount++; 557 } 558 } 559 boolean isRootRecipe = recipeNodeCount == 1 || isRootContext; 560 return isRootRecipe; 561 } 562 563 protected String getTestName(final Node aNode) { 564 String theAttribut = aNode.getAttribute("name"); 565 if (theAttribut == null || theAttribut.trim().length() == 0) { 566 theAttribut = aNode.getAttribute("description"); 567 } 568 return replaceProperties(theAttribut); 569 } 570 571 private String getTaskDescription(final Node aNode) { 572 if (aNode == null) { 573 return null; 574 } 575 String theTaskDescription = aNode.getAttribute("name"); 576 if (theTaskDescription == null || theTaskDescription.trim().length() == 0) { 577 theTaskDescription = aNode.getAttribute("description"); 578 } 579 final String theTag = aNode.getTag(); 580 if (theTag.equals("Recipe")) { 581 startTask(theTaskDescription, aNode.getAttribute("description")); 582 } else if (theTag.equals(SpecialCommands.STARTUP)) { 583 if (theTaskDescription == null) { 584 theTaskDescription = SpecialCommands.STARTUP; 585 } 586 startTask(theTaskDescription, SpecialCommands.STARTUP); 587 } else { 588 theTaskDescription = aNode.getAttribute("description"); 589 } 590 return theTaskDescription; 591 } 592 593 private void startTask(String name, String description) { 594 this.testName = name; 595 this.recipeListener.startTask(name); 596 } 597 598 protected String getTrimmedLines(String theValue1) throws IOException { 599 final BufferedReader theStringReader = new BufferedReader(new StringReader(theValue1)); 600 String theLine = ""; 601 final StringBuffer theBuffer = new StringBuffer(); 602 while ((theLine = theStringReader.readLine()) != null) { 603 final String theTrimmedLine = theLine.trim(); 604 if (theTrimmedLine.length() > 0) { 605 theBuffer.append(theTrimmedLine); 606 theBuffer.append('\n'); 607 } 608 } 609 theValue1 = theBuffer.toString(); 610 return theValue1; 611 } 612 613 protected String[] randomSort(final String[] aArray) { 614 final Vector<String> theVector = new Vector<String>(); 615 for (int i = 0; i < aArray.length; i++) { 616 theVector.add(aArray[i]); 617 } 618 final String[] theResult = new String[theVector.size()]; 619 620 for (int l = 0; l < aArray.length; l++) { 621 final int theNumber = (int) (Math.random() * (theVector.size())); 622 theResult[l] = theVector.elementAt(theNumber); 623 theVector.removeElementAt(theNumber); 624 } 625 626 return theResult; 627 } 628 629 static public String prepareXml(String theCurrentValue) { 630 final int head = theCurrentValue.indexOf("<?"); 631 if (head >= 0) { 632 final int end = theCurrentValue.indexOf("?>"); 633 theCurrentValue = theCurrentValue.substring(end + 2).trim(); 634 } 635 return theCurrentValue; 636 } 637 638 protected Properties replaceAttributes(Node aCurrentAction) { 639 Map<String, String> attributes = aCurrentAction.getAttributes(); 640 Properties properties = MapUtils.toProperties(attributes); 641 Set<Entry<Object, Object>> entrySet = properties.entrySet(); 642 Properties props = new Properties(); 643 for (Entry<Object, Object> entry : entrySet) { 644 String key = (String) entry.getKey(); 645 String value = (String) entry.getValue(); 646 647 String replaceProperties = replaceProperties(value); 648 props.setProperty(key, replaceProperties); 649 } 650 return props; 651 } 652 653 protected void outputLog(String varName, final String theLevelAttribut, final Object theTextOut, String type) { 654 655 AELogRecord logRecord = new AELogRecord(theTextOut, type, varName); 656 657 if ("info".equals(theLevelAttribut)) { 658 this.log.info(logRecord); 659 } 660 if ("error".equals(theLevelAttribut)) { 661 this.log.error(logRecord); 662 } 663 if ("debug".equals(theLevelAttribut)) { 664 debug(logRecord); 665 } 666 if ("warn".equals(theLevelAttribut)) { 667 this.log.warn(logRecord); 668 } 669 } 670 671 protected boolean isActiveInitFor(final Node action, String value) { 672 return StringUtils.contains(attr(action, "init"), value); 673 } 674 675 protected String getFields(final Properties theOutArrayList) { 676 final StringBuffer theResult = new StringBuffer(); 677 for (final Enumeration<?> e = theOutArrayList.propertyNames(); e.hasMoreElements();) { 678 final String theName = (String) e.nextElement(); 679 final String theValue = theOutArrayList.getProperty(theName); 680 theResult.append(theName); 681 theResult.append("="); 682 theResult.append(theValue); 683 theResult.append(";"); 684 } 685 return theResult.toString(); 686 } 687 688 protected void applyResult(final Node commandNode, final String name, final Object value) { 689 setVariableValue(name, value); 690 691 String level = replaceProperties(commandNode.getAttribute("level")); 692 String type = replaceProperties(commandNode.getAttribute("type")); 693 if (level != null) { 694 outputLog(name, level, value, type); 695 } 696 } 697 698 public void setStartDir(final File aStartBaseDir) { 699 this.startBaseDir = aStartBaseDir; 700 } 701 702 protected void progress(final long theSize, final long aValue, String aDescription, final boolean aErrorState) { 703 try { 704 if (aDescription == null || aDescription.length() == 0) { 705 aDescription = new String(" "); 706 } 707 708 boolean loopActivated = isLoopActivated(); 709 710 if (!loopActivated) { 711 this.recipeListener.setProgress(aDescription, theSize, aValue, aErrorState); 712 } 713 } catch (final Throwable e) { 714 } 715 } 716 717 protected boolean isLoopActivated() { 718 boolean result = false; 719 Processor parent = getParent(); 720 if (parent != null) { 721 result = parent.isLoopActivated(); 722 } 723 if (!result) { 724 result = mainLoopCommand; 725 } 726 return result; 727 } 728 729 @Override 730 public File getFile(String filePath) { 731 filePath = replaceProperties(filePath); 732 733 File file = null; 734 if (!StringUtils.startsWithAny(filePath, new String[] { "https:", "http:" })) { 735 if (filePath != null) { 736 if (filePath.startsWith("classpath:") || filePath.startsWith("jar:") || filePath.startsWith("file:") 737 || '/' == filePath.charAt(0) || '\\' == filePath.charAt(0) || filePath.indexOf(":\\") > 0 738 || '/' == filePath.charAt(0)) { 739 file = new File(filePath); 740 } else { 741 file = new File(getBaseDir(), filePath); 742 } 743 } 744 } 745 746 return file; 747 } 748 749 public void make(final String aTestFile) throws CommandException { 750 this.testFile = aTestFile; 751 try { 752 if (this.recipeListener != null && isStopped() == false) { 753 this.recipeListener.startTask(this.testFile); 754 processTesting(this.testFile); 755 this.recipeListener.endTask(false); 756 } else { 757 throw new RuntimeException(); 758 } 759 760 } finally { 761 762 if (this.testName != null) { 763 debug("Recipe '" + this.testName + "' is stopped."); 764 } 765 } 766 } 767 768 public void stop() { 769 super.stop(); 770 771 if (getChildThreads() > 0) { 772 debug("Child's threads: " + getChildThreads()); 773 } 774 775 if (this.externProcessor != null && this.externProcessor != this && !externProcessor.isStoppedTest()) { 776 this.externProcessor.stop(); 777 } 778 779 if (this.configNode == null) { 780 return; 781 } 782 783 synchronized (monitor) { 784 monitor.notify(); 785 } 786 787 for (Process process : processes) { 788 debug("Request to destroy a child process:" + process.destroyForcibly()); 789 } 790 processes.clear(); 791 792 stopChilds(); 793 794 for (ThreadPoolExecutor pool : threadPoolList) { 795 pool.shutdownNow(); 796 } 797 798 while (!isStoppedTest()) { 799 try { 800 synchronized (monitor) { 801 monitor.wait(100); 802 } 803 } catch (InterruptedException e) { 804 Thread.currentThread().interrupt(); 805 } 806 } 807 808 RecipeListener listener = getListener(); 809 if (listener != null) { 810 listener.endTask(false); 811 } 812 813 if (parent != null && !parent.isStoppedTest()) { 814 parent.stop(); 815 } 816 } 817 818 private void stopChilds() { 819 List<TaskProcessorThread> fChildThreads2 = new ArrayList<>(childThreads); 820 for (TaskProcessorThread child : fChildThreads2) { 821 child.stopTest(); 822 823 while (!child.getProcessor().isStoppedTest()) { 824 try { 825 synchronized (monitor) { 826 monitor.wait(100); 827 } 828 } catch (InterruptedException e) { 829 Thread.currentThread().interrupt(); 830 } 831 } 832 } 833 } 834 835 static class SystemCommandStart extends Thread { 836 private final String fCommandAttribut; 837 838 ILogger fLog; 839 840 public SystemCommandStart(final String aCommandAttribut, final ILogger aLog) { 841 this.fLog = aLog; 842 this.fCommandAttribut = aCommandAttribut; 843 } 844 845 @Override 846 public void run() { 847 try { 848 Runtime.getRuntime().exec(this.fCommandAttribut); 849 } catch (final IOException e) { 850 this.fLog.error("System command starting is failed.", e); 851 } 852 } 853 854 } 855 856 protected String replaceXmlReference(String aValue) throws Exception { 857 aValue = replaceFile(aValue); 858 final String theStartKey = "&#"; 859 final String theEndKey = ";"; 860 int theBeginPos = 0; 861 int theEndPos = 0; 862 if (aValue == null) { 863 return aValue; 864 } 865 final StringBuffer theStringBuffer = new StringBuffer(); 866 while (true) { 867 theBeginPos = aValue.indexOf(theStartKey, theEndPos); 868 if (theBeginPos < 0) { 869 break; 870 } 871 theStringBuffer.append(aValue.substring(theEndPos, theBeginPos)); 872 theEndPos = aValue.indexOf(theEndKey, theBeginPos); 873 if (theEndPos < 0) { 874 throw new Exception("Variable getting incorrect syntax, absent symbol '" + theEndKey + "'."); 875 } 876 String theNameProperty = aValue.substring(theBeginPos + theStartKey.length(), theEndPos); 877 final int defaultPos = theNameProperty.indexOf(','); 878 if (defaultPos >= 0) { 879 theNameProperty = theNameProperty.substring(0, defaultPos); 880 } 881 final String theValue = new String(new char[] { (char) Integer.parseInt(theNameProperty) }); 882 theStringBuffer.append(theValue); 883 theEndPos += theEndKey.length(); 884 } 885 theStringBuffer.append(aValue.substring(theEndPos)); 886 return theStringBuffer.toString(); 887 } 888 889 public Processor makeProcessor(final Node aCurrentAction) throws IOException, ClassNotFoundException, 890 MalformedURLException, FileNotFoundException, NoSuchMethodException, InstantiationException, 891 IllegalAccessException, InvocationTargetException, CommandException { 892 String className = replaceProperties(aCurrentAction.getAttribute("class")); 893 894 className = getFullClassName(className); 895 896 Class<?> theClass = getClass().getClassLoader().loadClass(className); 897 898 final Constructor<?> constructor = theClass.getConstructor(); 899 final Processor newInstance = (Processor) constructor.newInstance(); 900 if (isRootRecipe()) { 901 newInstance.setRootContext(true); 902 newInstance.setTestListener(recipeListener); 903 } 904 newInstance.init(this); 905 return newInstance; 906 } 907 908 public static String getFullClassName(String className) { 909 if (StringUtils.indexOf(className, '.') < 0) { 910 className = STG_PROCESSOR_PACKAGE_NAME + className; 911 } 912 return className; 913 } 914 915 public void loadProperties(final String aParameterRule, final String aDelim, 916 final Map<String, Object> aMapProperties, final boolean aNameUpperCase) { 917 final StringTokenizer theStringTokenizer = new StringTokenizer(aParameterRule, aDelim); 918 while (theStringTokenizer.hasMoreTokens()) { 919 final String theLine = theStringTokenizer.nextToken(); 920 if (theLine == null || theLine.length() == 0 || (theLine.length() > 0 && theLine.trim().charAt(0) == '#')) { 921 continue; 922 } 923 final int thePbrk = theLine.indexOf('='); 924 String theName = replaceProperties(theLine.substring(0, thePbrk)); 925 final String theValue = replaceProperties(theLine.substring(thePbrk + 1)); 926 if (aNameUpperCase) { 927 theName = theName.toUpperCase(); 928 } 929 aMapProperties.put(theName, theValue); 930 } 931 } 932 933 public void loadProperties(final File aFile, final Map<String, Object> theProperties, final boolean aNameUpperCase) 934 throws IOException { 935 final BufferedReader theFileReader = new BufferedReader(new FileReader(aFile)); 936 try { 937 String theLine = null; 938 while ((theLine = theFileReader.readLine()) != null) { 939 if (theLine == null || theLine.length() == 0 940 || (theLine.length() > 0 && theLine.trim().charAt(0) == '#')) { 941 continue; 942 } 943 final int thePbrk = theLine.indexOf('='); 944 if (thePbrk < 0) { 945 try { 946 String theExtLine = replaceProperties(theLine); 947 theExtLine = theExtLine.replace('\r', '\n'); 948 loadProperties(theExtLine, "\n", theProperties, aNameUpperCase); 949 } catch (final StringIndexOutOfBoundsException e) { 950 throw new IOException("Incorrect data in properties file. File: " + aFile.getAbsolutePath() 951 + "\nLine: " + theLine); 952 } 953 continue; 954 } 955 String theName = replaceProperties(theLine.substring(0, thePbrk)); 956 final String theValue = replaceProperties(theLine.substring(thePbrk + 1)); 957 if (aNameUpperCase) { 958 theName = theName.toUpperCase(); 959 } 960 theProperties.put(theName, theValue); 961 } 962 } finally { 963 theFileReader.close(); 964 } 965 } 966 967 public static String[] listToArray(final ArrayList<?> theResult) { 968 final String[] theResultArray = new String[theResult.size()]; 969 for (int i = 0; i < theResultArray.length; i++) { 970 theResultArray[i] = (String) theResult.get(i); 971 } 972 return theResultArray; 973 } 974 975 protected void setRootContext(boolean isRootContext) { 976 this.isRootContext = isRootContext; 977 } 978 979 public Processor getParent() { 980 return this.parent; 981 } 982 983 public void complete(boolean success) { 984 stopChilds(); 985 } 986 987 public Stack<Node> getLocalTaskTrace() { 988 return this.stackTask; 989 } 990 991 public Vector<Object> getCallTaskTrace() { 992 final TreeVector result = new TreeVector(getTestName()); 993 final Vector<Node> trace = getLocalTaskTrace(); 994 result.addAll(trace); 995 return result; 996 } 997 998 public ILogger getLogger() { 999 return this.log; 1000 } 1001 1002 @Override 1003 protected String replaceCall(final String aValue) { 1004 final String theStartKey = "$call{"; 1005 final String theEndKey = "}"; 1006 int theBeginPos = 0; 1007 int theEndPos = 0; 1008 if (aValue == null) { 1009 return aValue; 1010 } 1011 1012 final StringBuffer theStringBuffer = new StringBuffer(); 1013 while (true) { 1014 theBeginPos = aValue.indexOf(theStartKey, theEndPos); 1015 if (theBeginPos < 0) { 1016 break; 1017 } 1018 theStringBuffer.append(aValue.substring(theEndPos, theBeginPos)); 1019 theEndPos = aValue.indexOf(theEndKey, theBeginPos); 1020 if (theEndPos < 0) { 1021 throw new RuntimeException("Tag created is incorrect syntax, absent symbol '" + theEndKey + "'."); 1022 } 1023 1024 final String theLine = aValue.substring(theBeginPos + theStartKey.length(), theEndPos); 1025 final int thePbrk = theLine.indexOf(','); 1026 String theTagName = theLine; 1027 String theNameVar = theLine; 1028 if (thePbrk > 0) { 1029 theTagName = theLine.substring(0, thePbrk); 1030 theNameVar = theLine.substring(thePbrk + 1); 1031 } else { 1032 theTagName = theLine; 1033 theNameVar = "RETURN"; 1034 } 1035 1036 Object theObjValue = null; 1037 if (StringUtils.startsWith(theTagName, "fn:")) { 1038 1039 if (StringUtils.equals(theTagName, "fn:currentTimeMillis")) { 1040 theObjValue = Long.toString(System.currentTimeMillis()); 1041 } 1042 1043 } else { 1044 1045 final String theFileAttribut = getListener().getManager().getTestPath(theTagName); 1046 1047 try { 1048 final Processor theTestUnit = new BaseProcessor(this); 1049 theTestUnit.init(this.configNode, this.variables, this.recipeListener, this.startBaseDir, this.log); 1050 final Map<String, Object> theVariables = theTestUnit.processTesting(theFileAttribut, this.variables, 1051 getBaseDir()); 1052 String name = StringUtils.upperCase(theNameVar); 1053 theObjValue = theVariables.get(name); 1054 1055 } catch (final Throwable e) { 1056 throw new RuntimeException(e); 1057 } 1058 } 1059 1060 String theValue = null; 1061 if (theObjValue instanceof String) { 1062 theValue = (String) theObjValue; 1063 } else if (theObjValue instanceof String[] && ((String[]) theObjValue).length > 0) { 1064 theValue = ((String[]) theObjValue)[0]; 1065 } else { 1066 theValue = ObjectUtils.toString(theObjValue); 1067 } 1068 theStringBuffer.append(theValue); 1069 theEndPos += theEndKey.length(); 1070 } 1071 1072 theStringBuffer.append(aValue.substring(theEndPos)); 1073 return theStringBuffer.toString(); 1074 } 1075 1076 public void pause() { 1077 this.pauseOn = true; 1078 if (parent != null) { 1079 parent.pauseOn = this.pauseOn; 1080 } 1081 if (externProcessor != null) { 1082 externProcessor.pauseOn = this.pauseOn; 1083 } 1084 for (final Enumeration<TaskProcessorThread> theEnum = this.childThreads.elements(); theEnum 1085 .hasMoreElements();) { 1086 final TaskProcessorThread theRunnTest = theEnum.nextElement(); 1087 theRunnTest.getProcessor().pause(); 1088 } 1089 getListener().pause(); 1090 } 1091 1092 public void resume() { 1093 this.pauseOn = false; 1094 if (externProcessor != null) { 1095 externProcessor.pauseOn = this.pauseOn; 1096 } 1097 if (parent != null) { 1098 parent.pauseOn = this.pauseOn; 1099 } 1100 for (final Enumeration<TaskProcessorThread> theEnum = this.childThreads.elements(); theEnum 1101 .hasMoreElements();) { 1102 final TaskProcessorThread theRunnTest = theEnum.nextElement(); 1103 theRunnTest.getProcessor().resume(); 1104 } 1105 getListener().resume(); 1106 } 1107 1108 private void doPause() { 1109 while (this.pauseOn) { 1110 try { 1111 synchronized (monitor) { 1112 monitor.wait(100); 1113 } 1114 } catch (final InterruptedException e) { 1115 Thread.currentThread().interrupt(); 1116 } 1117 } 1118 } 1119 1120 protected void debug(Object message) { 1121 log.debug(message); 1122 } 1123 1124 protected void debug(Object message, Exception e) { 1125 log.debug(message, e); 1126 } 1127 1128 public void setLogger(final ILogger logger) { 1129 this.log = logger; 1130 } 1131 1132 public boolean isStoppedTest() { 1133 return isStopped(); 1134 } 1135 1136 public String attr(Node action, String name, String defaultValue) { 1137 String value = attr(action, name); 1138 return StringUtils.defaultIfEmpty(value, defaultValue); 1139 } 1140 1141 public String attr(Node action, String name) { 1142 name = replaceProperties(name); 1143 String attribute = action.getAttribute(name); 1144 return replaceProperties(attribute); 1145 } 1146 1147 public Object attrValue(Node action, String name) { 1148 name = replaceProperties(name); 1149 String value = attr(action, name); 1150 return getVariableValue(value); 1151 } 1152 1153 public static void setSilentMode(Processor unit, boolean silentMode) { 1154 if (unit != null) { 1155 unit.silentMode = silentMode; 1156 } 1157 } 1158 1159 public static boolean isSilentMode(Processor unit) { 1160 boolean result; 1161 if (unit != null) { 1162 result = unit.silentMode; 1163 } else { 1164 result = Boolean.parseBoolean(System.getProperty(ConfigConstants.TAKE_IT_EASY_MODE, "false")); 1165 } 1166 1167 return result; 1168 } 1169 1170 protected void quietWait(final long value) { 1171 synchronized (monitor) { 1172 try { 1173 monitor.wait(value); 1174 } catch (InterruptedException e) { 1175 getLog().debug(e.getMessage()); 1176 stop(); 1177 } 1178 } 1179 } 1180 1181 public long attrTime(final Node action, String attrNane, String defaultValue) { 1182 String fullValue = StringUtils.defaultIfBlank(attr(action, attrNane), defaultValue); 1183 String valueStr; 1184 char typeMarker = ' '; 1185 1186 if (NumberUtils.isNumber(fullValue)) { 1187 valueStr = fullValue; 1188 } else { 1189 valueStr = StringUtils.substring(fullValue, 0, fullValue.length() - 1); 1190 typeMarker = fullValue.charAt(fullValue.length() - 1); 1191 } 1192 1193 double value = Double.parseDouble(valueStr); 1194 1195 Date cdate = new Date(); 1196 Calendar c = Calendar.getInstance(); 1197 c.setTime(cdate); 1198 1199 long resultInMs; 1200 switch (typeMarker) { 1201 case 'Y': 1202 c.add(Calendar.YEAR, (int) value); 1203 resultInMs = c.getTime().getTime() - cdate.getTime(); 1204 break; 1205 case 'M': 1206 c.add(Calendar.MONTH, (int) value); 1207 resultInMs = c.getTime().getTime() - cdate.getTime(); 1208 break; 1209 case 'w': 1210 value = (long) (value *= 7); 1211 case 'd': 1212 value = (long) (value *= 24); 1213 case 'h': 1214 value = (long) (value *= 60); 1215 case 'm': 1216 value = (long) (value *= 60); 1217 case 's': 1218 value = (long) (value *= 1000); 1219 default: 1220 resultInMs = (long) value; 1221 } 1222 1223 return resultInMs; 1224 } 1225 1226}