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