001package com.ganteater.ae.processor; 002 003import java.awt.Toolkit; 004import java.awt.datatransfer.Clipboard; 005import java.awt.datatransfer.StringSelection; 006import java.io.BufferedReader; 007import java.io.ByteArrayOutputStream; 008import java.io.File; 009import java.io.FileInputStream; 010import java.io.FileNotFoundException; 011import java.io.FileOutputStream; 012import java.io.FileReader; 013import java.io.IOException; 014import java.io.InputStream; 015import java.io.InputStreamReader; 016import java.io.OutputStream; 017import java.io.StringReader; 018import java.io.StringWriter; 019import java.io.UnsupportedEncodingException; 020import java.net.Inet4Address; 021import java.net.InetAddress; 022import java.net.NetworkInterface; 023import java.net.Socket; 024import java.net.SocketException; 025import java.net.SocketTimeoutException; 026import java.net.URL; 027import java.net.URLConnection; 028import java.net.UnknownHostException; 029import java.security.NoSuchAlgorithmException; 030import java.security.SecureRandom; 031import java.text.DateFormat; 032import java.text.SimpleDateFormat; 033import java.util.ArrayList; 034import java.util.Arrays; 035import java.util.Base64; 036import java.util.Calendar; 037import java.util.Collection; 038import java.util.Date; 039import java.util.Enumeration; 040import java.util.HashMap; 041import java.util.HashSet; 042import java.util.Iterator; 043import java.util.LinkedHashMap; 044import java.util.LinkedHashSet; 045import java.util.List; 046import java.util.Map; 047import java.util.Map.Entry; 048import java.util.Properties; 049import java.util.Random; 050import java.util.Set; 051import java.util.StringTokenizer; 052import java.util.TimeZone; 053import java.util.UUID; 054import java.util.concurrent.Executors; 055import java.util.concurrent.ThreadPoolExecutor; 056import java.util.concurrent.TimeUnit; 057import java.util.regex.Matcher; 058import java.util.regex.Pattern; 059import java.util.stream.Collectors; 060import java.util.stream.IntStream; 061 062import javax.swing.JOptionPane; 063import javax.xml.transform.Source; 064import javax.xml.transform.Transformer; 065import javax.xml.transform.TransformerFactory; 066import javax.xml.transform.stream.StreamResult; 067import javax.xml.transform.stream.StreamSource; 068 069import org.apache.commons.collections.CollectionUtils; 070import org.apache.commons.collections.MapUtils; 071import org.apache.commons.io.FileUtils; 072import org.apache.commons.io.IOUtils; 073import org.apache.commons.io.filefilter.IOFileFilter; 074import org.apache.commons.io.filefilter.RegexFileFilter; 075import org.apache.commons.io.filefilter.TrueFileFilter; 076import org.apache.commons.jexl3.JexlBuilder; 077import org.apache.commons.jexl3.JexlContext; 078import org.apache.commons.jexl3.JexlEngine; 079import org.apache.commons.jexl3.JexlExpression; 080import org.apache.commons.jexl3.MapContext; 081import org.apache.commons.lang.ArrayUtils; 082import org.apache.commons.lang.BooleanUtils; 083import org.apache.commons.lang.ObjectUtils; 084import org.apache.commons.lang.StringEscapeUtils; 085import org.apache.commons.lang.StringUtils; 086import org.apache.commons.lang.math.NumberUtils; 087import org.apache.commons.lang3.SystemUtils; 088import org.apache.http.auth.AuthScope; 089import org.apache.http.auth.UsernamePasswordCredentials; 090import org.apache.http.client.CredentialsProvider; 091import org.apache.http.client.config.RequestConfig; 092import org.apache.http.client.methods.CloseableHttpResponse; 093import org.apache.http.client.methods.HttpGet; 094import org.apache.http.client.methods.HttpPost; 095import org.apache.http.client.methods.HttpRequestBase; 096import org.apache.http.client.protocol.HttpClientContext; 097import org.apache.http.client.utils.URLEncodedUtils; 098import org.apache.http.entity.ByteArrayEntity; 099import org.apache.http.impl.client.BasicCredentialsProvider; 100import org.apache.http.impl.client.CloseableHttpClient; 101import org.apache.http.impl.client.HttpClients; 102import org.apache.sling.commons.json.JSONArray; 103import org.apache.sling.commons.json.JSONException; 104import org.apache.sling.commons.json.JSONObject; 105 106import com.ganteater.ae.AEManager; 107import com.ganteater.ae.AEWorkspace; 108import com.ganteater.ae.ChoiceTaskRunner; 109import com.ganteater.ae.CommandException; 110import com.ganteater.ae.ILogger; 111import com.ganteater.ae.MultiTaskRunDialog; 112import com.ganteater.ae.RecipeListener; 113import com.ganteater.ae.TaskCancelingException; 114import com.ganteater.ae.processor.annotation.CommandDescription; 115import com.ganteater.ae.processor.annotation.CommandExamples; 116import com.ganteater.ae.util.AEUtils; 117import com.ganteater.ae.util.NameValuePairImplementation; 118import com.ganteater.ae.util.TestCase; 119import com.ganteater.ae.util.xml.easyparser.EasyParser; 120import com.ganteater.ae.util.xml.easyparser.EasyUtils; 121import com.ganteater.ae.util.xml.easyparser.Node; 122import com.opencsv.CSVReader; 123 124import okhttp3.MediaType; 125import okhttp3.OkHttpClient; 126import okhttp3.Request.Builder; 127import okhttp3.Response; 128 129public class BaseProcessor extends Processor { 130 131 private Random random; 132 133 public BaseProcessor() { 134 } 135 136 public BaseProcessor(Processor parent) throws CommandException { 137 init(parent); 138 } 139 140 public BaseProcessor(AEManager manager, ILogger log, File baseDir) { 141 super(manager, log, baseDir); 142 } 143 144 public BaseProcessor(Map<String, Object> hashMap, Node node, File baseDir) { 145 super(hashMap, node, baseDir); 146 } 147 148 public BaseProcessor(Node configNode, Map<String, Object> startVariables, RecipeListener listener, File startDir, 149 ILogger aLog, Processor parent) throws CommandException { 150 super(configNode, startVariables, listener, startDir, aLog, parent); 151 } 152 153 @CommandExamples({ "<Regexp name='type:property' source='type:property' regex='type:string' group='type:integer'/>", 154 "<Regexp name='type:property' source='type:property' regex='type:string' />" }) 155 public void runCommandRegexp(final Node action) throws Throwable { 156 final String theName = attr(action, "name"); 157 String regex = replaceProperties(action.getAttribute("regex")); 158 int group = Integer.parseInt(attr(action, "group", "0")); 159 Object sourceObj = attrValue(action, "source"); 160 if (sourceObj == null) { 161 throw new IllegalArgumentException("The 'source' value must not be null."); 162 } 163 164 if (sourceObj instanceof String) { 165 sourceObj = new String[] { (String) sourceObj }; 166 } 167 168 Pattern pattern = Pattern.compile(regex); 169 List<String> result = new ArrayList<>(); 170 if (sourceObj instanceof String[]) { 171 String[] sources = (String[]) sourceObj; 172 173 for (String source : sources) { 174 Matcher matcher = pattern.matcher(source); 175 if (matcher.find()) { 176 String theText = matcher.group(group); 177 result.add(theText); 178 } 179 } 180 } 181 setVariableValue(theName, result); 182 } 183 184 @CommandExamples({ "<Replace name='type:property' oldChar='type:integer' newChar='type:integer'/>", 185 "<Replace name='type:property' regex='type:regex' replacement='type:string'/>", 186 "<Replace name='type:property' unescape='enum:java|csv|html|javascript|xml' />", 187 "<Replace name='type:property' escape='enum:java|csv|html|javascript|xml|sql' />" }) 188 public void runCommandReplace(final Node command) throws Throwable { 189 String name = replaceProperties(command.getAttribute("name")); 190 191 Object variableValue = getVariableValue(name); 192 String value = null; 193 if (variableValue instanceof String) { 194 value = (String) variableValue; 195 } else if (variableValue instanceof byte[]) { 196 value = new String((byte[]) variableValue); 197 } else { 198 value = ObjectUtils.toString(variableValue); 199 } 200 value = replaceProperties(value); 201 202 final String theOldChar = replaceProperties(command.getAttribute("oldChar")); 203 final String theNewChar = replaceProperties(command.getAttribute("newChar")); 204 if (theOldChar != null) { 205 value = value.replace(theOldChar, theNewChar); 206 } 207 208 final String regex = replaceProperties(command.getAttribute("regex")); 209 final String replacement = replaceProperties(command.getAttribute("replacement")); 210 if (regex != null && value != null) { 211 value = value.replaceAll(regex, replacement); 212 } 213 214 String unescape = attr(command, "unescape"); 215 if (unescape != null) { 216 unescape = unescape.toLowerCase(); 217 switch (unescape) { 218 case "csv": { 219 value = StringEscapeUtils.unescapeCsv(value); 220 break; 221 } 222 case "html": { 223 value = StringEscapeUtils.unescapeHtml(value); 224 break; 225 } 226 case "java": { 227 value = StringEscapeUtils.unescapeJava(value); 228 break; 229 } 230 case "javascript": { 231 value = StringEscapeUtils.unescapeJavaScript(value); 232 break; 233 } 234 case "xml": { 235 value = StringEscapeUtils.unescapeXml(value); 236 break; 237 } 238 } 239 } 240 241 String escape = attr(command, "escape"); 242 if (escape != null) { 243 escape = escape.toLowerCase(); 244 switch (escape) { 245 case "csv": { 246 value = StringEscapeUtils.escapeCsv(value); 247 break; 248 } 249 case "html": { 250 value = StringEscapeUtils.escapeHtml(value); 251 break; 252 } 253 case "java": { 254 value = StringEscapeUtils.escapeJava(value); 255 break; 256 } 257 case "javascript": { 258 value = StringEscapeUtils.escapeJavaScript(value); 259 break; 260 } 261 case "sql": { 262 value = StringEscapeUtils.escapeSql(value); 263 break; 264 } 265 case "xml": { 266 value = StringEscapeUtils.escapeXml(value); 267 break; 268 } 269 } 270 } 271 272 setVariableValue(name, value); 273 } 274 275 @CommandExamples({ "<Clipboard name='type:property'/>" }) 276 public void runCommandClipboard(final Node action) { 277 String value = String.valueOf(attrValue(action, "name")); 278 StringSelection stringSelection = new StringSelection(value); 279 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 280 clipboard.setContents(stringSelection, null); 281 } 282 283 @CommandExamples({ 284 "<CheckValue actual='type:string' expected='type:string' mode='enum:normal|trimLines' condition='enum:unequal|equal' onErrorMsg='type:string'/>", 285 "<CheckValue value='type:string' regex='type:regex' onErrorMsg='type:string'/>" }) 286 public void runCommandCheckValue(final Node aCurrentAction) throws Throwable { 287 288 final String theErrorMsg = replaceProperties(aCurrentAction.getAttribute("onErrorMsg")); 289 290 final String theRegex = replaceProperties(aCurrentAction.getAttribute("regex")); 291 292 if (theRegex == null) { 293 final boolean theTrimLines = "trimLines".equals(replaceProperties(aCurrentAction.getAttribute("mode"))); 294 try { 295 String actual = replaceProperties(aCurrentAction.getAttribute("actual")); 296 String expected = replaceProperties(aCurrentAction.getAttribute("expected")); 297 if (theTrimLines) { 298 actual = getTrimmedLines(actual); 299 expected = getTrimmedLines(expected); 300 } 301 302 final boolean unequal = "unequal".equals(replaceProperties(aCurrentAction.getAttribute("condition"))); 303 if (unequal) { 304 boolean equals = StringUtils.equals(expected, actual); 305 TestCase.assertFalse(theErrorMsg, equals); 306 } else { 307 TestCase.assertEquals(theErrorMsg, expected, actual); 308 } 309 } catch (final Throwable e) { 310 taskNode(aCurrentAction, false); 311 throw e; 312 } 313 } else { 314 final String theValue = replaceProperties(aCurrentAction.getAttribute("value")); 315 final Pattern p = Pattern.compile(theRegex); 316 final Matcher m = p.matcher(theValue); 317 if (m.find() == false) { 318 taskNode(aCurrentAction, false); 319 TestCase.fail("Regex validation failed. Regex:" + theRegex + ", value:" + theValue); 320 } 321 } 322 323 } 324 325 @CommandExamples({ "<CheckNotNull name='type:property' onErrorMsg='type:string'/>" }) 326 public void runCommandCheckNotNull(final Node aCurrentAction) throws Throwable { 327 final String theName = replaceProperties(aCurrentAction.getAttribute("name")); 328 final String theErrorMsg = replaceProperties(aCurrentAction.getAttribute("onErrorMsg")); 329 Object theValue = getVariableValue(theName); 330 if (theValue != null && theValue instanceof String[] && ((String[]) theValue).length == 0) { 331 theValue = null; 332 } 333 try { 334 TestCase.assertNotNull(theErrorMsg, theValue); 335 } catch (final Throwable e) { 336 taskNode(aCurrentAction, false); 337 throw e; 338 } 339 } 340 341 @CommandExamples({ "<Choice name='type:property'>" + "<Task name='type:string'>...</Task></Choice>", 342 "<Choice name='type:property' mode='enum:default|table'>" + "<Task name='type:string'>...</Task></Choice>", 343 "<Choice name='type:property' mode='enum:default|table' type='setup'>" 344 + "<Task name='type:string'/></Choice>", 345 "<Choice name='type:property' mode='enum:default|table' type='call-task'>" 346 + "<Task name='type:recipe'/></Choice>", 347 "<Choice name='type:property'><Task name='type:string'>...</Task><Started>...</Started></Choice>", 348 "<Choice name='type:property' runAllTaskName='type:string' mode='enum:default|table' type='enum:default|call-task'>" 349 + "<Task name='type:string'>...</Task><Started>...</Started></Choice>" }) 350 public void runCommandChoice(final Node aCurrentAction) throws Throwable { 351 352 final String nameOfChoice = replaceProperties(aCurrentAction.getAttribute("name")); 353 Object preset = getVariableValue(nameOfChoice); 354 355 String description = replaceProperties(aCurrentAction.getAttribute("description")); 356 357 final String theRunAllTaskName = replaceProperties(aCurrentAction.getAttribute("runAllTaskName")); 358 String type = replaceProperties(aCurrentAction.getAttribute("type")); 359 final boolean callType = "call-task".equals(type); 360 361 final Map<String, Node> tablesNodes = new LinkedHashMap<>(); 362 363 final String theMode = replaceProperties(aCurrentAction.getAttribute("mode")); 364 365 final Node[] taskNodes = aCurrentAction.getNodes("Task"); 366 for (int i = 0; i < taskNodes.length; i++) { 367 final String name = replaceProperties(taskNodes[i].getAttribute("name")); 368 369 if ("table".equals(theMode) && name != null && name.equals(theRunAllTaskName)) { 370 continue; 371 } 372 373 if (!callType || getListener().getManager().getTestPath(name) != null) { 374 tablesNodes.put(name, taskNodes[i]); 375 } 376 } 377 378 final String[] names = tablesNodes.keySet().toArray(new String[tablesNodes.size()]); 379 380 debug("Task list: " + nameOfChoice); 381 382 final List<String> activeNodes = new ArrayList<>(); 383 384 if ("table".equals(theMode) || "hidden".equals(theMode)) { 385 386 final String exceptionIgnore = replaceProperties(aCurrentAction.getAttribute("exception")); 387 boolean startsWith = false; 388 if (exceptionIgnore != null) { 389 startsWith = exceptionIgnore.startsWith("ignore"); 390 } 391 392 ChoiceTaskRunner choiceRunner = new ChoiceTaskRunner(nameOfChoice, preset == null); 393 boolean visible = !"hidden".equals(theMode); 394 final MultiTaskRunDialog inputSelectChoice = this.recipeListener.getManager().tasksChoice(choiceRunner, 395 names, startsWith, preset, this, visible); 396 397 try { 398 final Iterator<String> selectedTasks = inputSelectChoice.getSelectedTasks(); 399 400 List<String> selectedTaskNames = new ArrayList<>(); 401 while (selectedTasks.hasNext()) { 402 String selectedTask = selectedTasks.next(); 403 activeNodes.add(selectedTask); 404 405 selectedTaskNames.add(selectedTask); 406 inputSelectChoice.begin(selectedTask); 407 408 try { 409 Node action = tablesNodes.get(selectedTask); 410 startCommandInformation(action); 411 412 if (callType) { 413 runCommandTask(action); 414 } else { 415 taskNode(action, false); 416 } 417 inputSelectChoice.end(selectedTask, true); 418 419 } catch (final Throwable e) { 420 inputSelectChoice.end(selectedTask, false); 421 if (inputSelectChoice.isExceptionIgnore() == false) { 422 throw e; 423 } 424 } 425 } 426 427 if ("setup".equals(type)) { 428 setVariableValue(nameOfChoice, selectedTaskNames.toArray(new String[selectedTaskNames.size()])); 429 } 430 } finally { 431 inputSelectChoice.done(); 432 if (inputSelectChoice.isStarted()) { 433 Node[] nodes = aCurrentAction.getNodes("Started"); 434 for (Node node : nodes) { 435 taskNode(node); 436 } 437 } 438 } 439 440 } else { 441 if (this.recipeListener.getManager() != null) { 442 boolean notifyMe = this.recipeListener.isNotifyMe(); 443 description = StringUtils.defaultString(description, nameOfChoice); 444 final String inputSelectChoice = this.recipeListener.getManager().inputChoice(nameOfChoice, description, 445 names, ObjectUtils.toString(preset, null), this, notifyMe); 446 if (inputSelectChoice != null) { 447 activeNodes.add(inputSelectChoice); 448 } 449 } 450 451 debug("Select task: " + (activeNodes != null ? activeNodes : "<not chosen>")); 452 453 if (!activeNodes.isEmpty()) { 454 if (activeNodes.get(0).equals(theRunAllTaskName) == false) { 455 456 if (callType) { 457 runCommandTask(tablesNodes.get(activeNodes.get(0))); 458 } else { 459 taskNode(tablesNodes.get(activeNodes.get(0))); 460 } 461 462 } else { 463 for (int i = 0; i < names.length; i++) { 464 final String theActiveNode = names[i]; 465 if (theActiveNode.equals(theRunAllTaskName) == false) { 466 if (callType) { 467 runCommandTask(tablesNodes.get(theActiveNode)); 468 } else { 469 taskNode(tablesNodes.get(theActiveNode)); 470 } 471 } 472 } 473 } 474 } 475 } 476 477 setVariableValue(nameOfChoice, activeNodes); 478 } 479 480 @CommandExamples({ "<Runnable name='type:property' threadLog='type:boolean'>...code...</Runnable>" }) 481 public void runCommandRunnable(final Node aCurrentAction) throws CommandException { 482 final String theName = replaceProperties(aCurrentAction.getAttribute("name")); 483 String theNameThreads = getTestName(aCurrentAction); 484 if (theNameThreads == null) { 485 theNameThreads = "Thread"; 486 } 487 488 boolean threadLog = Boolean.valueOf(StringUtils.defaultIfBlank(attr(aCurrentAction, "threadLog"), "false")); 489 ILogger theLog = this.log; 490 if (threadLog) { 491 theLog = this.recipeListener.createLog(theNameThreads, false); 492 } 493 494 Node task = new Node("Task"); 495 task.setAttribute("description", aCurrentAction.getAttribute("name")); 496 task.addAll(aCurrentAction); 497 final TaskProcessorThread runnable = new TaskProcessorThread(this, task, getBaseDir(), theLog); 498 setVariableValue(theName, runnable); 499 } 500 501 @CommandExamples({ "<Sort name='type:property' type='enum:natural|random' />" }) 502 public void runCommandSort(final Node aCurrentAction) { 503 final String theName = replaceProperties(aCurrentAction.getAttribute("name")); 504 String theType = replaceProperties(aCurrentAction.getAttribute("type")); 505 if (theType == null) { 506 theType = "natural"; 507 } 508 509 final Object theObject = getVariableValue(theName); 510 if (theObject instanceof String[]) { 511 String[] theArray = (String[]) theObject; 512 if ("natural".equals(theType)) { 513 Arrays.sort(theArray); 514 } else if ("random".equals(theType)) { 515 theArray = randomSort(theArray); 516 } else { 517 throw new IllegalArgumentException("Sort type should be following value: natural, random."); 518 } 519 setVariableValue(theName, theArray); 520 } 521 } 522 523 @CommandExamples({ "<CheckInArray value='type:string' array='type:property' onErrorMsg='type:string'/>" }) 524 public void runCommandCheckInArray(final Node aCurrentAction) throws Throwable { 525 final String theValue = replaceProperties(aCurrentAction.getAttribute("value")); 526 final String theArrayName = replaceProperties(aCurrentAction.getAttribute("array")); 527 final String theErrorMsg = replaceProperties(aCurrentAction.getAttribute("onErrorMsg")); 528 final Object theObject = getVariableValue(theArrayName); 529 if (theObject != null && theObject instanceof String[]) { 530 final String[] theValues = (String[]) theObject; 531 Arrays.sort(theValues); 532 try { 533 TestCase.assertTrue(theErrorMsg, Arrays.binarySearch(theValues, theValue) >= 0); 534 } catch (final Throwable e) { 535 taskNode(aCurrentAction, false); 536 throw e; 537 } 538 } 539 } 540 541 @CommandExamples({ "<Tokenizer name='type:property' delim='type:string'/>" }) 542 public void runCommandTokenizer(final Node aCurrentVar) { 543 final String theAttribut = aCurrentVar.getAttribute("name"); 544 String theDelimAttribut = aCurrentVar.getAttribute("delim"); 545 if (theDelimAttribut == null) { 546 theDelimAttribut = ";"; 547 } 548 final Object theObjectValue = getVariableValue(theAttribut); 549 if (theObjectValue == null) { 550 return; 551 } 552 String theLine = null; 553 if (theObjectValue instanceof String) { 554 theLine = (String) getVariableValue(theAttribut); 555 } else if (theObjectValue instanceof String[] && ((String[]) getVariableValue(theAttribut)).length == 1) { 556 theLine = ((String[]) getVariableValue(theAttribut))[0]; 557 } 558 final ArrayList<String> theArrayList = new ArrayList<String>(); 559 if (theLine != null) { 560 final StringTokenizer theStringTokenizer = new StringTokenizer(theLine, theDelimAttribut); 561 while (theStringTokenizer.hasMoreTokens()) { 562 theArrayList.add(theStringTokenizer.nextToken()); 563 } 564 final String[] theArray = new String[theArrayList.size()]; 565 for (int i = 0; i < theArrayList.size(); i++) { 566 if (isStopped()) { 567 break; 568 } 569 theArray[i] = theArrayList.get(i); 570 } 571 setVariableValue(theAttribut, theArray); 572 } else { 573 debug("Tokenized empty string is ignored."); 574 } 575 } 576 577 @CommandExamples({ "<Date name='type:string' format='type:string' />", 578 "<Date name='type:string' format='type:string' source='type:property' sformat='type:string' />", 579 "<Date name='type:string' format='type:string' shift='type:time' />" }) 580 public void runCommandDate(final Node aCurrentAction) throws Throwable { 581 final String name = replaceProperties(aCurrentAction.getAttribute("name")); 582 String value = replaceProperties(aCurrentAction.getAttribute("value")); 583 if (value == null) { 584 String source = aCurrentAction.getAttribute("source"); 585 if (source != null) { 586 value = (String) getVariableValue(replaceProperties(source)); 587 } 588 } 589 590 if (value == null) { 591 Object variableValue = getVariableValue(name); 592 if (variableValue != null) { 593 value = ObjectUtils.toString(variableValue); 594 } 595 } 596 597 String format = replaceProperties(aCurrentAction.getAttribute("format")); 598 String sformat = StringUtils.defaultString(replaceProperties(aCurrentAction.getAttribute("sformat")), format); 599 600 SimpleDateFormat dateFor = null; 601 if (sformat != null && !"ms".equals(sformat)) { 602 dateFor = new SimpleDateFormat(sformat); 603 dateFor.setTimeZone(TimeZone.getTimeZone("UTC")); 604 } 605 String stringDate = null; 606 if (value == null) { 607 if (dateFor != null) { 608 stringDate = dateFor.format(new Date()); 609 } else { 610 stringDate = Long.toString(new Date().getTime()); 611 } 612 value = stringDate; 613 } 614 615 final String shift = replaceProperties(StringUtils.trim(aCurrentAction.getAttribute("shift"))); 616 617 Date date; 618 if (dateFor != null) { 619 date = dateFor.parse(value); 620 } else { 621 date = new Date(Long.parseLong(value)); 622 } 623 624 if (shift != null) { 625 Calendar c = Calendar.getInstance(); 626 c.setTime(date); 627 String substring = StringUtils.substring(shift, 0, shift.length() - 1); 628 int shiftValue = Integer.parseInt(substring); 629 switch (shift.charAt(shift.length() - 1)) { 630 case 's': 631 c.add(Calendar.SECOND, shiftValue); 632 break; 633 case 'm': 634 c.add(Calendar.MINUTE, shiftValue); 635 break; 636 case 'h': 637 c.add(Calendar.HOUR, shiftValue); 638 break; 639 case 'd': 640 c.add(Calendar.DAY_OF_MONTH, shiftValue); 641 break; 642 case 'w': 643 c.add(Calendar.WEEK_OF_MONTH, shiftValue); 644 break; 645 case 'M': 646 c.add(Calendar.MONTH, shiftValue); 647 break; 648 case 'Y': 649 c.add(Calendar.YEAR, shiftValue); 650 break; 651 } 652 653 date = c.getTime(); 654 } 655 656 if (format != null && !"ms".equals(format)) { 657 dateFor = new SimpleDateFormat(format); 658 dateFor.setTimeZone(TimeZone.getTimeZone("UTC")); 659 stringDate = dateFor.format(date); 660 } else { 661 stringDate = Long.toString(date.getTime()); 662 } 663 664 setVariableValue(name, stringDate); 665 } 666 667 @CommandExamples({ "<Wait delay='type:time'/>", "<Wait/>" }) 668 public void runCommandWait(final Node aCurrentAction) { 669 final long theValue = parseTime(aCurrentAction, "delay", "0"); 670 if (theValue > 0) { 671 quietWait(theValue); 672 } else { 673 pause(); 674 } 675 } 676 677 @CommandDescription("The View command defines a view component to precentation output date provided by Out command.") 678 @CommandExamples({ 679 "<View name='type:string' reuse='type:boolean' type='type:view' />" }) 680 public void runCommandView(final Node aCurrentAction) throws Throwable { 681 this.recipeListener.runCommandView(replaceAttributes(aCurrentAction)); 682 } 683 684 @CommandExamples({ "<Formater name='type:property' type='enum:xml|http-get-request'/>" }) 685 public void runCommandFormater(final Node aCurrentAction) throws Throwable { 686 final String theNameAttribut = replaceProperties(aCurrentAction.getAttribute("name")); 687 final String theTypeAttribut = replaceProperties(aCurrentAction.getAttribute("type")); 688 Object theValue = getVariableValue(theNameAttribut); 689 if (theValue instanceof String) { 690 if ("json".equals(theTypeAttribut)) { 691 theValue = AEUtils.format(ObjectUtils.toString(theValue)); 692 } else { 693 theValue = new String[] { (String) theValue }; 694 } 695 696 setVariableValue(theNameAttribut, theValue); 697 } 698 if (theValue instanceof String[]) { 699 final String[] theValueArray = (String[]) theValue; 700 for (int i = 0; i < theValueArray.length; i++) { 701 if (isStopped()) { 702 break; 703 } 704 if ("xml".equals(theTypeAttribut)) { 705 final EasyParser theParser = new EasyParser(); 706 String theCurrentValue = theValueArray[i]; 707 theCurrentValue = prepareXml(theCurrentValue); 708 final Node object = theParser.getObject(theCurrentValue); 709 theValueArray[i] = object.getXMLText(); 710 } 711 } 712 if (theValueArray.length > 2) { 713 setVariableValue(theNameAttribut, theValueArray); 714 } else if (theValueArray.length == 1) { 715 setVariableValue(theNameAttribut, theValueArray[0]); 716 } else { 717 setVariableValue(theNameAttribut, null); 718 } 719 } 720 } 721 722 @CommandExamples({ "<Trim name='type:property'/>" }) 723 public void runCommandTrim(final Node aCurrentAction) throws Throwable { 724 String name = replaceProperties(aCurrentAction.getAttribute("name")); 725 Object value = getVariableValue(name); 726 if (value instanceof String) { 727 value = StringUtils.trimToNull(ObjectUtils.toString(value)); 728 } else if (value instanceof String[]) { 729 String[] array = (String[]) value; 730 if (array.length == 0) { 731 value = null; 732 } else { 733 List<String> list = new ArrayList<>(); 734 for (String object : array) { 735 String val = ObjectUtils.toString(object); 736 if (StringUtils.isNotBlank(val)) { 737 list.add(object); 738 } 739 } 740 value = list.toArray(new String[list.size()]); 741 } 742 } else if (value instanceof List) { 743 @SuppressWarnings("unchecked") 744 List<String> array = (List<String>) value; 745 if (array.size() == 0) { 746 value = null; 747 } else { 748 List<String> list = new ArrayList<>(); 749 for (String object : array) { 750 String val = ObjectUtils.toString(object); 751 if (StringUtils.isNotBlank(val)) { 752 list.add(object); 753 } 754 } 755 value = list.toArray(new String[list.size()]); 756 } 757 } 758 applyResult(aCurrentAction, name, value); 759 } 760 761 @CommandExamples({ "<Xslt name='type:property' xml='type:property' xsl='type:property'/>" }) 762 public void runCommandXslt(final Node aCurrentAction) throws Throwable { 763 final String theNameAttribut = attr(aCurrentAction, "name"); 764 final String theXmlAttribut = ObjectUtils.toString(attrValue(aCurrentAction, "xml")); 765 final String theXslAttribut = ObjectUtils.toString(attrValue(aCurrentAction, "xsl")); 766 final StringWriter theStringWriter = new StringWriter(); 767 768 if (theXmlAttribut == null || theXmlAttribut.trim().length() == 0 || "null".equals(theXmlAttribut)) { 769 debug("Xml document is empty, transform disable."); 770 return; 771 } 772 773 if (theXslAttribut == null || theXslAttribut.trim().length() == 0 || "null".equals(theXslAttribut)) { 774 debug("Xsl document is empty, transform disable."); 775 return; 776 } 777 778 try { 779 final Source xslSource = new StreamSource(new StringReader(theXslAttribut)); 780 final Transformer transformer = TransformerFactory.newInstance().newTransformer(xslSource); 781 final Source xmlSource = new StreamSource(new StringReader(theXmlAttribut)); 782 783 transformer.transform(xmlSource, new StreamResult(theStringWriter)); 784 785 } catch (final Throwable e) { 786 debug("XML Data to transformation:\n" + theXmlAttribut); 787 debug("XSL:\n" + theXslAttribut); 788 this.log.error("Xsl transformation is failed.", e); 789 throw e; 790 } 791 792 setVariableValue(theNameAttribut, theStringWriter.toString()); 793 } 794 795 @CommandExamples({ "Output a property by name: <Out name='type:property' />", 796 "Outputs the text content: <Out view='type:string'> ... </Out>", 797 "Output with a type: <Out name='type:property' type='enum:txt|html|xml|json|~json|url|path|uri|csv'/>", 798 "Outputs the value of the specified view id: <Out view='type:string'>...</Out>", 799 "Outputs a property value with a specified log level: <Out name='type:property' level='enum:info|debug|warn|error'/>", 800 "Outputs a property value with a message at a specified log level: <Out name='type:property' level='enum:info|debug|warn|error'> ... </Out>", 801 "Outputs a property value at specified log level: <Out level='enum:info|debug|warn|error'>... $var{...} ... </Out>", 802 "Writes output to a file with options to append content and specify encoding: <Out file='type:path' append='enum:true|false' encoding='UTF-8'/>" }) 803 public void runCommandOut(final Node command) throws UnsupportedEncodingException, IOException { 804 final String name = replaceProperties(command.getAttribute("name")); 805 final String description = replaceProperties(command.getAttribute("description")); 806 String theOutFileNameAttribut = replaceProperties(command.getAttribute("file")); 807 808 String logLevel = command.getAttribute("level"); 809 logLevel = replaceProperties(logLevel); 810 811 if (logLevel == null) { 812 logLevel = StringUtils.defaultIfBlank(getVariableString(DEFAULT_LOG_LEVEL_NAME), "info"); 813 } 814 815 String type = replaceProperties(command.getAttribute("type")); 816 817 FileOutputStream theFileOutputStream = null; 818 try { 819 if (theOutFileNameAttribut != null) { 820 String theAppendAttribut = replaceProperties(command.getAttribute("append")); 821 if (theAppendAttribut == null) { 822 theAppendAttribut = "true"; 823 } 824 theOutFileNameAttribut = replaceProperties(theOutFileNameAttribut); 825 final File file = getFile(theOutFileNameAttribut); 826 file.getParentFile().mkdirs(); 827 theFileOutputStream = new FileOutputStream(file, "true".equals(theAppendAttribut)); 828 } 829 String theEncoding = replaceProperties(command.getAttribute("encoding")); 830 if (theEncoding == null) { 831 theEncoding = "UTF-8"; 832 } 833 834 String theTextOut = null; 835 String varName = name; 836 final Node[] nodes = command.getTextNodes(); 837 838 if (nodes.length > 0) { 839 Node node = nodes[0]; 840 theTextOut = replaceProperties(node.getText()); 841 } else if (command.size() > 0) { 842 String innerXMLText = command.getInnerXMLText(); 843 Node node = new EasyParser().getObject(innerXMLText); 844 EasyUtils.removeTagId(node); 845 theTextOut = replaceProperties(node.toString()); 846 } 847 848 if (theTextOut != null) { 849 if (name != null) { 850 varName = theTextOut + ": " + varName; 851 } 852 if (theFileOutputStream != null) { 853 theFileOutputStream.write(theTextOut.getBytes(theEncoding)); 854 } 855 856 Properties attributes = replaceAttributes(command); 857 this.recipeListener.outToView(this, attributes, theTextOut); 858 } 859 860 if (name != null) { 861 Object theValue = getVariableValue(name); 862 863 if (theValue instanceof byte[]) { 864 if (theFileOutputStream != null) { 865 final byte[] value = (byte[]) theValue; 866 theFileOutputStream.write(value); 867 theFileOutputStream.close(); 868 return; 869 } else { 870 outputLog(StringUtils.defaultIfEmpty(description, varName), logLevel, theValue, type); 871 return; 872 } 873 } 874 875 if (theValue == null) { 876 outputLog(StringUtils.defaultIfEmpty(description, varName), logLevel, null, type); 877 878 } else if (theValue instanceof String) { 879 if (theFileOutputStream == null) { 880 outputLog(StringUtils.defaultIfEmpty(description, varName), logLevel, theValue.toString(), 881 type); 882 } else { 883 theFileOutputStream.write(theValue.toString().getBytes(theEncoding)); 884 } 885 886 this.recipeListener.outToView(this, replaceAttributes(command), theValue); 887 888 } else if (theValue instanceof String[]) { 889 final StringBuffer theBuffer = new StringBuffer(); 890 891 final String[] theValueArray = (String[]) theValue; 892 for (int i = 0; i < theValueArray.length; i++) { 893 if (isStopped()) { 894 break; 895 } 896 897 if (theBuffer.length() > 0) { 898 theBuffer.append("\n"); 899 } 900 theBuffer.append(theValueArray[i]); 901 902 Properties params = replaceAttributes(command); 903 String msg = theValueArray[i]; 904 this.recipeListener.outToView(this, params, msg); 905 } 906 if (theFileOutputStream == null) { 907 outputLog(StringUtils.defaultIfEmpty(description, varName), logLevel, theBuffer.toString(), 908 type); 909 } else { 910 theFileOutputStream.write(theBuffer.toString().getBytes(theEncoding)); 911 } 912 } else { 913 outputLog(StringUtils.defaultIfEmpty(description, varName), logLevel, theValue, type); 914 this.recipeListener.outToView(this, replaceAttributes(command), theValue); 915 } 916 } else { 917 outputLog(StringUtils.defaultIfEmpty(description, varName), logLevel, theTextOut, type); 918 } 919 } finally { 920 if (theFileOutputStream != null) { 921 theFileOutputStream.flush(); 922 theFileOutputStream.close(); 923 } 924 } 925 } 926 927 @CommandDescription("The <About> information tag (not executable) is used to display details about the recipe. This tag contains a <description> element, " 928 + "which provides the recipe's description.\r\n" 929 + "The description can be written in plain text or markdown format and is displayed as additional information on the menu page. " 930 + "For optimal readability in the recipe editor. Text strings must be formatted and less than 120 characters long.") 931 @CommandExamples({ "<About><description>...</description></About>", 932 "<About><attach><file name='type:url|path' /></attach></About>", 933 "<About><author name='type:string' email='type:string' messager='type:string' phone='type:string'/>" 934 + "<attach><file name='type:url|path' width='type:number' height='type:number'/></attach></About>" }) 935 public void runCommandAbout(final Node aCurrentAction) throws Throwable { 936 } 937 938 @CommandExamples({ "<Exist name='type:property' text='type:string' value='type:string'/>", 939 "<Exist name='type:property' array='type:property' value='type:string'/>" }) 940 public void runCommandExist(final Node aCurrentAction) throws Throwable { 941 final String theName = replaceProperties(aCurrentAction.getAttribute("name")); 942 final String theText = replaceProperties(aCurrentAction.getAttribute("text")); 943 final String theArrayName = replaceProperties(aCurrentAction.getAttribute("array")); 944 final String theValue = replaceProperties(aCurrentAction.getAttribute("value")); 945 946 if (theArrayName != null) { 947 final Object variableValue = getVariableValue(theArrayName); 948 if (variableValue instanceof String[]) { 949 final String[] variableValueArray = (String[]) variableValue; 950 for (int i = 0; i < variableValueArray.length; i++) { 951 if (theValue.equals(variableValueArray[i])) { 952 setVariableValue(theName, "true"); 953 return; 954 } 955 } 956 } 957 958 if (variableValue instanceof String) { 959 final String value = (String) variableValue; 960 if (theValue.equals(value)) { 961 setVariableValue(theName, "true"); 962 return; 963 } 964 } 965 setVariableValue(theName, "false"); 966 } else { 967 if (theText == null || theValue == null || theName == null) { 968 return; 969 } 970 final int indexOf = theText.indexOf(theValue); 971 setVariableValue(theName, indexOf >= 0 ? "true" : "false"); 972 } 973 } 974 975 @CommandExamples({ "<Load name='type:property' init='console'/>", 976 "<Load name='type:property' init='console'/>...</Load>", "<Load name='type:property' file='type:path'/>", 977 "<Load name='type:property' file='type:path' timeout='type:time' mode='enum:default|noreplace|escapeJS|bytes'/>", 978 "<Load name='type:property' url='type:url' timeout='type:time' mode='enum:default|noreplace|escapeJS|bytes'/>" }) 979 public void runCommandLoad(final Node action) throws Throwable { 980 final boolean noreplace = "noreplace".equals(action.getAttribute("mode")); 981 final boolean isArray = "array".equals(action.getAttribute("mode")); 982 final boolean defaultMode = "default".equals(action.getAttribute("mode")); 983 final boolean escapeJSValue = "escapeJS".equals(action.getAttribute("mode")); 984 final boolean bytes = "bytes".equals(action.getAttribute("mode")); 985 final boolean base64 = "base64".equals(action.getAttribute("mode")); 986 987 String theEncoding = replaceProperties(action.getAttribute("encoding")); 988 if (theEncoding == null) { 989 theEncoding = "UTF-8"; 990 } 991 992 final String name = replaceProperties(action.getAttribute("name")); 993 int timeout = (int) parseTime(action, "timeout", "0"); 994 995 final String theUrl = replaceProperties(action.getAttribute("url")); 996 if (theUrl != null) { 997 URL url = new URL(theUrl); 998 long startTime = System.currentTimeMillis(); 999 while (timeout == 0 || System.currentTimeMillis() < startTime + timeout) { 1000 if (isStopped()) { 1001 break; 1002 } 1003 try { 1004 URLConnection openConnection = url.openConnection(); 1005 openConnection.setReadTimeout(timeout); 1006 byte[] byteArray = IOUtils.toByteArray(openConnection.getInputStream()); 1007 if (escapeJSValue) { 1008 String data = StringEscapeUtils.escapeJavaScript(new String(byteArray)); 1009 setVariableValue(name, data); 1010 } else { 1011 setVariableValue(name, new String(byteArray, theEncoding)); 1012 } 1013 return; 1014 1015 } catch (IOException e) { 1016 if (timeout == 0) { 1017 throw e; 1018 } 1019 quietWait(200); 1020 } 1021 } 1022 } 1023 1024 String filePath = (String) attr(action, "file"); 1025 final boolean theDialog = isActiveInitFor(action, "console"); 1026 1027 if (theDialog) { 1028 File theFile = null; 1029 if (filePath != null) { 1030 theFile = getFile(filePath); 1031 } 1032 filePath = this.recipeListener.getManager().inputFile(name, null, theFile, log, this); 1033 } 1034 1035 if (filePath != null) { 1036 if (base64 || bytes) { 1037 File file = getFile(filePath); 1038 debug("Loading file: " + file); 1039 if (file.exists()) { 1040 try (FileInputStream input = new FileInputStream(file)) { 1041 Object byteArray = IOUtils.toByteArray(input); 1042 if (base64) { 1043 byteArray = Base64.getEncoder().encodeToString((byte[]) byteArray); 1044 } 1045 setVariableValue(name, byteArray); 1046 } 1047 } else { 1048 throw new FileNotFoundException(file.getAbsolutePath()); 1049 } 1050 return; 1051 } 1052 1053 int iterations = timeout / 1000; 1054 if (iterations == 0) { 1055 iterations = 1; 1056 } 1057 for (int i = 0; i < iterations; i++) { 1058 if (isStopped()) { 1059 break; 1060 } 1061 try { 1062 1063 if (!action.isEmpty()) { 1064 File file = getFile(filePath); 1065 try (BufferedReader reader = new BufferedReader(new FileReader(file))) { 1066 String line; 1067 while ((line = reader.readLine()) != null) { 1068 if (this.breakFlag > 0) { 1069 break; 1070 } 1071 setVariableValue(name, line); 1072 taskNode(action, false); 1073 } 1074 } finally { 1075 if (this.breakFlag > 0) { 1076 breakFlag--; 1077 } 1078 } 1079 1080 } else { 1081 1082 String text = AEUtils.loadResource(filePath, getBaseDir(), theEncoding); 1083 if (!noreplace) { 1084 text = replaceProperties(text, defaultMode); 1085 } 1086 1087 if (escapeJSValue) { 1088 String data = StringEscapeUtils.escapeJavaScript(text); 1089 setVariableValue(name, data); 1090 } else { 1091 Object val = text; 1092 if (isArray) { 1093 val = StringUtils.split(text, "\n\r"); 1094 } 1095 1096 setVariableValue(name, val); 1097 } 1098 } 1099 1100 break; 1101 1102 } catch (final FileNotFoundException e) { 1103 if (timeout == 0) { 1104 throw e; 1105 } 1106 quietWait(1000); 1107 } catch (final Exception e) { 1108 throw e; 1109 } 1110 } 1111 } else { 1112 if (isActiveInitFor(action, "mandatory")) { 1113 stop(); 1114 } 1115 } 1116 1117 } 1118 1119 @CommandExamples({ "<Remove name='type:property'/>", "<Remove file='type:path'/>", 1120 "<Remove name='type:property' history='type:boolean'/>" }) 1121 public void runCommandRemove(final Node aCurrentAction) throws Throwable { 1122 String theFileName = aCurrentAction.getAttribute("file"); 1123 if (theFileName != null) { 1124 theFileName = replaceProperties(theFileName); 1125 final File theFile = getFile(theFileName); 1126 if (theFile.isDirectory()) { 1127 FileUtils.deleteDirectory(theFile); 1128 } else { 1129 if (theFile.delete() == false) { 1130 new Exception("File '" + theFile.getAbsolutePath() + "' is not deleted."); 1131 } 1132 } 1133 } 1134 String theVarName = aCurrentAction.getAttribute("name"); 1135 if (theVarName != null) { 1136 theVarName = replaceProperties(theVarName); 1137 setVariableValue(theVarName, null); 1138 if (Boolean.parseBoolean((attr(aCurrentAction, "history")))) { 1139 AEWorkspace.getInstance().setDefaultUserConfiguration(".inputValue." + theVarName, null); 1140 } 1141 } 1142 } 1143 1144 @CommandDescription("Load the web page by `url`. The response is stored in the variable defined by the `name` attribute.") 1145 @CommandExamples({ 1146 "<Get name='type:property' url='type:string' /> ", 1147 "<Get name='type:property' url='type:string' timeout='type:time'/> ", 1148 "<Get name='type:property' url='type:string' auth='type:string' mediaType='type:string' retries='1' timeout='type:time'/> " }) 1149 public void runCommandGet(final Node aCurrentAction) throws Throwable { 1150 1151 String mediaTypeStr = attr(aCurrentAction, "mediaType"); 1152 mediaTypeStr = StringUtils.defaultIfEmpty(mediaTypeStr, "application/json"); 1153 1154 String url = attr(aCurrentAction, "url"); 1155 String auth = attr(aCurrentAction, "auth"); 1156 int retries = Integer.parseInt(attr(aCurrentAction, "retries", "1")); 1157 1158 Builder builder = new okhttp3.Request.Builder().url(url).get(); 1159 1160 if (mediaTypeStr != null) { 1161 builder.addHeader("Content-Type", mediaTypeStr); 1162 } 1163 if (auth != null) { 1164 builder.addHeader("Authorization", auth); 1165 } 1166 1167 okhttp3.Request request = builder.build(); 1168 1169 for (int i = 0; i < retries; i++) { 1170 if (isStopped()) { 1171 break; 1172 } 1173 1174 try { 1175 okhttp3.OkHttpClient.Builder newBuilder = new OkHttpClient().newBuilder(); 1176 long timeout = parseTime(aCurrentAction, "timeout", "0"); 1177 if (timeout > 0) { 1178 newBuilder.connectTimeout(timeout, TimeUnit.MILLISECONDS); 1179 newBuilder.readTimeout(timeout, TimeUnit.MILLISECONDS); 1180 newBuilder.writeTimeout(timeout, TimeUnit.MILLISECONDS); 1181 } 1182 OkHttpClient client = newBuilder.build(); 1183 1184 try (Response response = client.newCall(request).execute()) { 1185 String value = new String(response.body().bytes(), "UTF-8"); 1186 String name = attr(aCurrentAction, "name"); 1187 if (name != null) { 1188 setVariableValue(name, value); 1189 } 1190 } 1191 1192 break; 1193 } catch (SocketTimeoutException e) { 1194 if (i == 2) { 1195 throw e; 1196 } 1197 } 1198 } 1199 } 1200 1201 @CommandDescription("Post the body defined by the `body` attribute to `url`. " 1202 + "The response is stored in the variable defined by the `name` attribute. " 1203 + "If the body is not simple, you should create a special variable and pass its value via $var{}.") 1204 @CommandExamples({ 1205 "<Post name='type:property' url='type:string' body='type:string'/> ", 1206 "<Post name='type:property' url='type:string' body='type:string' timeout='type:time'/> ", 1207 "<Post name='type:property' url='type:string' auth='type:string' body='type:string' mediaType='type:string' timeout='type:time'/> " 1208 }) 1209 public void runCommandPost(final Node aCurrentAction) throws Throwable { 1210 String mediaTypeStr = attr(aCurrentAction, "mediaType"); 1211 mediaTypeStr = StringUtils.defaultIfEmpty(mediaTypeStr, "application/json"); 1212 1213 String url = attr(aCurrentAction, "url"); 1214 String auth = attr(aCurrentAction, "auth"); 1215 String bodyStr = StringUtils.defaultIfEmpty(replaceProperties(aCurrentAction.getAttribute("body")), ""); 1216 1217 MediaType mediaType = MediaType.parse(mediaTypeStr); 1218 okhttp3.RequestBody body = okhttp3.RequestBody.create(mediaType, bodyStr); 1219 1220 Builder addHeader = new okhttp3.Request.Builder().url(url).method("POST", body).addHeader("Content-Type", 1221 mediaTypeStr); 1222 if (auth != null) { 1223 addHeader = addHeader.addHeader("Authorization", auth); 1224 } 1225 okhttp3.Request request = addHeader.addHeader("Accept", "*/*").build(); 1226 okhttp3.OkHttpClient.Builder newBuilder = new OkHttpClient().newBuilder(); 1227 1228 long timeout = parseTime(aCurrentAction, "timeout", "0"); 1229 if (timeout > 0) { 1230 newBuilder.connectTimeout(timeout, TimeUnit.MILLISECONDS); 1231 newBuilder.readTimeout(timeout, TimeUnit.MILLISECONDS); 1232 newBuilder.writeTimeout(timeout, TimeUnit.MILLISECONDS); 1233 } 1234 OkHttpClient client = newBuilder.build(); 1235 try (Response response = client.newCall(request).execute()) { 1236 String value = new String(response.body().bytes(), "UTF-8"); 1237 1238// if(response.code() == 404) { 1239// 1240// } 1241 1242 String name = attr(aCurrentAction, "name"); 1243 if (name != null) { 1244 setVariableValue(name, value); 1245 } 1246 } 1247 } 1248 1249 @CommandExamples({ 1250 "<Request method='value:get|post|[socket]' request='type:property[Map{header;body}]' response='type:property[Map{status;body}]' host='http://...' timeout='type:time'/>", 1251 "<Request method='get' response='type:property[Map{status;body}]' host='type:url' userName='type:string' password='type:string'><param name='type:string' value='type:string'/></Request>" }) 1252 public void runCommandRequest(final Node aCurrentAction) throws Throwable { 1253 Object request = attrValue(aCurrentAction, "request"); 1254 final String responseName = attr(aCurrentAction, "response"); 1255 final String method = StringUtils.defaultIfEmpty(attr(aCurrentAction, "method"), "socket"); 1256 String theUrl = attr(aCurrentAction, "host"); 1257 1258 String userName = attr(aCurrentAction, "userName"); 1259 String password = attr(aCurrentAction, "password"); 1260 HttpClientContext localContext = null; 1261 if (userName != null && password != null) { 1262 CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); 1263 credentialsProvider.setCredentials(AuthScope.ANY, 1264 new UsernamePasswordCredentials(userName + ":" + password)); 1265 localContext = HttpClientContext.create(); 1266 localContext.setCredentialsProvider(credentialsProvider); 1267 } 1268 1269 HttpRequestBase httpRequest = null; 1270 1271 final Node[] paramNodes = aCurrentAction.getNodes("param"); 1272 if (paramNodes != null && paramNodes.length > 0) { 1273 List<NameValuePairImplementation> parameters = new ArrayList<>(); 1274 for (Node node : paramNodes) { 1275 String name = attr(node, "name"); 1276 String value = attr(node, "value"); 1277 1278 NameValuePairImplementation nameValuePair = new NameValuePairImplementation(name, value); 1279 parameters.add(nameValuePair); 1280 } 1281 1282 String query = URLEncodedUtils.format(parameters, "UTF-8"); 1283 theUrl = theUrl + "?" + query; 1284 } 1285 1286 if (theUrl.toLowerCase().startsWith("http")) { 1287 if ("get".equalsIgnoreCase(method)) { 1288 httpRequest = new HttpGet(theUrl); 1289 1290 } else if ("post".equalsIgnoreCase(method)) { 1291 HttpPost httpPost = new HttpPost(theUrl); 1292 if (request != null) { 1293 @SuppressWarnings("unchecked") 1294 final Map<String, Object> requestMap = (Map<String, Object>) request; 1295 Object bodyObject = requestMap.get("body"); 1296 byte[] body = null; 1297 if (bodyObject instanceof byte[]) { 1298 body = (byte[]) bodyObject; 1299 } else if (bodyObject instanceof String) { 1300 body = ((String) bodyObject).getBytes(); 1301 } 1302 httpPost.setEntity(new ByteArrayEntity(body)); 1303 } 1304 httpRequest = httpPost; 1305 1306 } 1307 int timeout = (int) parseTime(aCurrentAction, "timeout", "5000"); 1308 1309 RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout) 1310 .setConnectionRequestTimeout(timeout).setSocketTimeout(timeout).build(); 1311 httpRequest.setConfig(config); 1312 if (request != null) { 1313 @SuppressWarnings("unchecked") 1314 Map<String, String> header = (Map<String, String>) ((Map<String, Object>) request).get("header"); 1315 if (header != null) { 1316 Set<Entry<String, String>> entrySet = header.entrySet(); 1317 for (Entry<String, String> entry : entrySet) { 1318 httpRequest.setHeader(entry.getKey(), entry.getValue()); 1319 } 1320 } 1321 } 1322 1323 CloseableHttpResponse response; 1324 CloseableHttpClient httpclient = HttpClients.createDefault(); 1325 1326 long duration = System.currentTimeMillis(); 1327 if (localContext == null) { 1328 response = httpclient.execute(httpRequest); 1329 } else { 1330 response = httpclient.execute(httpRequest, localContext); 1331 } 1332 ByteArrayOutputStream body = new ByteArrayOutputStream(); 1333 response.getEntity().writeTo(body); 1334 1335 HashMap<String, Object> aValue = new HashMap<String, Object>(); 1336 aValue.put("body", body.toByteArray()); 1337 aValue.put("status", response.getStatusLine().getStatusCode()); 1338 aValue.put("header", response.getAllHeaders()); 1339 aValue.put("duration", Long.toString(System.currentTimeMillis() - duration)); 1340 setVariableValue(responseName, aValue); 1341 1342 } else { 1343 1344 Socket socket = null; 1345 try { 1346 String host = StringUtils.substringBefore(theUrl, ":"); 1347 int port = Integer.parseInt(StringUtils.defaultIfBlank(StringUtils.substringAfter(theUrl, ":"), "80")); 1348 socket = new Socket(host, port); 1349 OutputStream outputStream = socket.getOutputStream(); 1350 if (request instanceof byte[]) { 1351 IOUtils.write((byte[]) request, outputStream); 1352 } else if (request instanceof String) { 1353 IOUtils.write(((String) request).getBytes(), outputStream); 1354 } 1355 InputStream inputStream = socket.getInputStream(); 1356 byte[] response = IOUtils.toByteArray(inputStream); 1357 setVariableValue(responseName, response); 1358 } finally { 1359 if (socket != null) { 1360 socket.close(); 1361 } 1362 } 1363 1364 } 1365 1366 } 1367 1368 @CommandExamples({ "<Table name='The table of variables'><var name='type:property' value='type:string'/></Table>", 1369 "<Table name='The table of variables' file='type:path'><var name='type:property' value='type:string'/></Table>" }) 1370 public void runCommandTable(final Node aCurrentVar) throws Throwable { 1371 AEManager manager = this.recipeListener.getManager(); 1372 boolean notifyMe = this.recipeListener.isNotifyMe(); 1373 1374 manager.inputDataTable(this, aCurrentVar, notifyMe); 1375 } 1376 1377 @SuppressWarnings({ "unchecked" }) 1378 @CommandExamples({ "<Loop name='type:property' source='type:property' numbers='type:integer'> ... </Loop>", 1379 "<Loop numbers='type:integer'> ... </Loop>", 1380 "<Loop name='type:property' query='select * from ...' maxCount='type:integer'> ... </Loop>" }) 1381 public void runCommandLoop(final Node aCurrentVar) throws Throwable { 1382 String theDescript = replaceProperties(aCurrentVar.getAttribute("description")); 1383 final String theNameAttribut = attr(aCurrentVar, "name"); 1384 boolean mainLoopCommand = false; 1385 1386 final String theNumbers = StringUtils.trimToNull(replaceProperties(aCurrentVar.getAttribute("numbers"))); 1387 if (theDescript == null) { 1388 theDescript = "Loop"; 1389 } 1390 String sourceAttribute = aCurrentVar.getAttribute("source"); 1391 final String theAttribut = replaceProperties(sourceAttribute); 1392 Object loopArrayVar = null; 1393 if (theAttribut != null) { 1394 loopArrayVar = getVariableValue(theAttribut); 1395 } 1396 List<Object> theLoopArray = new ArrayList<>(); 1397 if (loopArrayVar != null) { 1398 if (loopArrayVar instanceof String) { 1399 theLoopArray.add((String) loopArrayVar); 1400 } else if (loopArrayVar instanceof String[]) { 1401 List<String> asList = Arrays.asList((String[]) loopArrayVar); 1402 theLoopArray.addAll(asList); 1403 } else if (loopArrayVar instanceof List) { 1404 theLoopArray = (List<Object>) loopArrayVar; 1405 } else if (loopArrayVar instanceof Map) { 1406 Map map = (Map) loopArrayVar; 1407 theLoopArray.addAll(map.keySet()); 1408 } else if (loopArrayVar instanceof JSONArray) { 1409 JSONArray array = (JSONArray) loopArrayVar; 1410 theLoopArray = array.toList(); 1411 } else { 1412 return; 1413 } 1414 } 1415 int theCount = 0; 1416 boolean infinityLoop = false; 1417 if (StringUtils.isNotBlank(theNumbers)) { 1418 theCount = (int) Double.parseDouble(theNumbers); 1419 } else { 1420 if (!theLoopArray.isEmpty()) { 1421 theCount = theLoopArray.size(); 1422 } else { 1423 infinityLoop = sourceAttribute == null; 1424 } 1425 } 1426 if (isLoopActivated() == false) { 1427 this.mainLoopCommand = true; 1428 mainLoopCommand = true; 1429 } 1430 1431 if (infinityLoop) { 1432 this.mainLoopCommand = false; 1433 } 1434 try { 1435 for (int i = 0; (i < theCount || infinityLoop) && isStopped() == false; i++) { 1436 if (isStopped()) { 1437 break; 1438 } 1439 if (this.breakFlag > 0) { 1440 break; 1441 } 1442 if ((mainLoopCommand && !infinityLoop) || theCount > 5) { 1443 this.recipeListener.setProgress(theDescript, theCount, i, false); 1444 } 1445 startCommandInformation(aCurrentVar); 1446 if (theLoopArray != null && theLoopArray.size() > 0) { 1447 if (i < theLoopArray.size()) { 1448 setVariableValue(theNameAttribut, theLoopArray.get(i)); 1449 } 1450 } else { 1451 setVariableValue(theNameAttribut, ObjectUtils.toString(i)); 1452 } 1453 taskNode(aCurrentVar, false); 1454 } 1455 } finally { 1456 if (this.breakFlag > 0) { 1457 breakFlag--; 1458 } 1459 if (mainLoopCommand) { 1460 this.mainLoopCommand = false; 1461 } 1462 } 1463 } 1464 1465 @CommandExamples({ "<Append name='type:property' value='type:string' type='enum:all|unique'/>", 1466 "<Append name='type:property'>...</Append>" }) 1467 public synchronized void runCommandAppend(final Node aCurrentVar) throws Throwable { 1468 final String name = aCurrentVar.getAttribute("name"); 1469 Object value = attr(aCurrentVar, "value"); 1470 if (value == null) { 1471 value = replaceProperties(aCurrentVar.getInnerText()); 1472 } 1473 1474 String source = aCurrentVar.getAttribute("source"); 1475 if (source != null) { 1476 value = getVariableValue(replaceProperties(source)); 1477 } 1478 1479 final Object theOldValue = getVariableValue(name, false); 1480 if (theOldValue == null) { 1481 return; 1482 } 1483 if (theOldValue instanceof String) { 1484 final String theValue1 = (String) theOldValue; 1485 value = theValue1 + value; 1486 setVariableValue(name, value); 1487 1488 } else if (theOldValue instanceof Object[]) { 1489 final boolean theUniqueTypeAttribut = "unique".equals(aCurrentVar.getAttribute("type")); 1490 1491 final String[] theValue1 = (String[]) theOldValue; 1492 String[] theValue2 = null; 1493 1494 if (theUniqueTypeAttribut) { 1495 Set<String> targetSet = new LinkedHashSet<>(Arrays.asList(theValue1)); 1496 if (value instanceof String) { 1497 targetSet.add((String) value); 1498 } else if (value instanceof String[]) { 1499 for (String val : (String[]) value) { 1500 targetSet.add(val); 1501 } 1502 } 1503 1504 String[] array = new String[targetSet.size()]; 1505 Iterator<String> iterator = targetSet.iterator(); 1506 int i = 0; 1507 while (iterator.hasNext()) { 1508 String object = (String) iterator.next(); 1509 array[i++] = object; 1510 } 1511 1512 theValue2 = array; 1513 1514 } else { 1515 List<String> targetList = new ArrayList<>(Arrays.asList(theValue1)); 1516 if (value instanceof String[]) { 1517 for (String val : (String[]) value) { 1518 targetList.add(val); 1519 } 1520 } else { 1521 targetList.add((String) value); 1522 } 1523 1524 String[] array = new String[targetList.size()]; 1525 int i = 0; 1526 for (Object val : targetList) { 1527 if (val instanceof String) { 1528 array[i++] = (String) val; 1529 } else { 1530 array[i++] = ObjectUtils.toString(val); 1531 } 1532 } 1533 1534 theValue2 = array; 1535 } 1536 1537 applyResult(aCurrentVar, name, theValue2); 1538 } 1539 } 1540 1541 @CommandExamples({ "<Rnd name='type:property' symbols='type:integer' type='enum:number|default'/>", 1542 "<Rnd name='type:property' type='uuid'/>", 1543 "<Rnd name='type:property' symbols='type:integer' startCode='type:integer' endCode='type:integer'/>", 1544 "<Rnd name='type:property' source='type:property'/>" }) 1545 public void runCommandRnd(final Node aCurrentVar) throws Throwable { 1546 final String theNameAttribut = replaceProperties(aCurrentVar.getAttribute("name")); 1547 String result = null; 1548 String type = replaceProperties(aCurrentVar.getAttribute("type")); 1549 1550 if ("uuid".equalsIgnoreCase(type)) { 1551 result = UUID.randomUUID().toString(); 1552 1553 } else { 1554 final String source = replaceProperties(aCurrentVar.getAttribute("source")); 1555 if (this.random == null) { 1556 this.random = SecureRandom.getInstance("SHA1PRNG"); 1557 } 1558 if (source != null) { 1559 Object value = getVariableValue(source); 1560 if (value instanceof String[]) { 1561 String[] strings = (String[]) value; 1562 int index = this.random.nextInt(strings.length); 1563 value = strings[index]; 1564 } 1565 setVariableValue(theNameAttribut, value); 1566 return; 1567 } 1568 1569 final String theSymbolsAttribut = replaceProperties(aCurrentVar.getAttribute("symbols")); 1570 1571 final long theBegNum = Long.parseLong(theSymbolsAttribut); 1572 int startCode = 0x41; 1573 final String startCodeStr = replaceProperties(aCurrentVar.getAttribute("startCode")); 1574 if (startCodeStr != null) { 1575 if (startCodeStr.indexOf('x') > 0) { 1576 startCode = Integer.parseInt(startCodeStr.substring(2), 16); 1577 } else { 1578 startCode = Integer.parseInt(startCodeStr); 1579 } 1580 type = "-number"; 1581 } 1582 1583 int endCode = 0x05A; 1584 final String endCodeStr = replaceProperties(aCurrentVar.getAttribute("endCode")); 1585 if (endCodeStr != null) { 1586 if (endCodeStr.indexOf('x') > 0) { 1587 endCode = Integer.parseInt(endCodeStr.substring(2), 16); 1588 } else { 1589 endCode = Integer.parseInt(endCodeStr); 1590 } 1591 type = "-number"; 1592 } 1593 1594 if ("number".equals(type) == false) { 1595 final StringBuffer theBuffer = new StringBuffer(); 1596 for (int i = 0; i < theBegNum; i++) { 1597 theBuffer.append((char) (this.random.nextInt(endCode - startCode) + startCode)); 1598 } 1599 result = theBuffer.toString(); 1600 } else { 1601 final StringBuffer theBuffer = new StringBuffer(); 1602 for (int i = 0; i < theBegNum; i++) { 1603 theBuffer.append(this.random.nextInt(9)); 1604 } 1605 result = theBuffer.toString(); 1606 } 1607 } 1608 1609 setVariableValue(theNameAttribut, result); 1610 } 1611 1612 @CommandExamples({ "<Inc name='type:property' increase='type:number'/>" }) 1613 public void runCommandInc(final Node aCurrentVar) throws Throwable { 1614 String theValueAttribut = aCurrentVar.getAttribute("increase"); 1615 theValueAttribut = replaceProperties(theValueAttribut); 1616 long theIncLong = 1; 1617 if (theValueAttribut != null) { 1618 theIncLong = Long.parseLong(theValueAttribut); 1619 } 1620 final String theAttribut = aCurrentVar.getAttribute("name"); 1621 Object theOldValue = getVariableValue(theAttribut); 1622 1623 if (!(theOldValue instanceof Object[])) { 1624 theOldValue = ObjectUtils.toString(theOldValue, null); 1625 } 1626 1627 if (theOldValue instanceof String) { 1628 final long theLongValue = Long.parseLong((String) theOldValue) + theIncLong; 1629 setVariableValue(theAttribut, Long.toString(theLongValue)); 1630 } 1631 if (theOldValue instanceof String[] && ((String[]) theOldValue).length > 0) { 1632 final long theLongValue = Long.parseLong(((String[]) theOldValue)[0]) + theIncLong; 1633 setVariableValue(theAttribut, Long.toString(theLongValue)); 1634 } else { 1635 new ClassCastException("Tag <Inc> enabled only one number argument."); 1636 } 1637 } 1638 1639 @CommandExamples({ 1640 "<If name='type:property' startsWith='type:string' endsWith='type:string' contains='type:string' equals='type:string' notEqual='type:string'> ... </If>", 1641 "<If value='type:property' startsWith='type:string' endsWith='type:string' contains='type:string' equals='type:string' notEqual='type:string'> ... <Else> ... </Else></If>", 1642 "<If expression='type:string'> ... </If>", "<If isNull='type:property'> ... </If>", 1643 "<If isNotNull='type:property'> ... </If>" }) 1644 public void runCommandIf(final Node action) throws Throwable { 1645 runIf(action); 1646 } 1647 1648 private boolean runIf(final Node action) throws CommandException, Throwable, ClassNotFoundException { 1649 String theExpressionAttribut = action.getAttribute("expression"); 1650 String isNull = action.getAttribute("isNull"); 1651 String isNotNull = action.getAttribute("isNotNull"); 1652 String nameAttr = attr(action, "name"); 1653 1654 String valueAttr = action.getAttribute("value"); 1655 1656 String theValue1Attribut = action.getAttribute("value1"); 1657 String theValue2Attribut = action.getAttribute("value2"); 1658 String theConditionAttribut = action.getAttribute("condition"); 1659 1660 boolean result = false; 1661 if (nameAttr != null || valueAttr != null) { 1662 Object variableValue = getVariableValue(nameAttr); 1663 String value; 1664 1665 if (variableValue == null) { 1666 value = replaceProperties(valueAttr); 1667 } else { 1668 if (variableValue instanceof String[]) { 1669 value = StringUtils.join((String[]) variableValue, "\n"); 1670 } else { 1671 value = ObjectUtils.toString(variableValue); 1672 } 1673 } 1674 1675 String startsWith = attr(action, "startsWith"); 1676 String endsWith = attr(action, "endsWith"); 1677 String contains = attr(action, "contains"); 1678 String equals = attr(action, "equals"); 1679 String regex = attr(action, "regex"); 1680 String notEqual = attr(action, "notEqual"); 1681 1682 boolean ignoreCase = Boolean.valueOf(attr(action, "ignoreCase", "false")); 1683 1684 boolean condition1 = startsWith == null || (ignoreCase ? StringUtils.startsWithIgnoreCase(value, startsWith) 1685 : StringUtils.startsWith(value, startsWith)); 1686 boolean condition2 = endsWith == null || (ignoreCase ? StringUtils.endsWithIgnoreCase(value, endsWith) 1687 : StringUtils.endsWith(value, endsWith)); 1688 boolean condition3 = contains == null || (ignoreCase ? StringUtils.containsIgnoreCase(value, contains) 1689 : StringUtils.contains(value, contains)); 1690 boolean condition4 = equals == null 1691 || (ignoreCase ? StringUtils.equalsIgnoreCase(value, equals) : StringUtils.equals(value, equals)); 1692 1693 boolean condition5 = true; 1694 if (regex != null) { 1695 final Pattern p = Pattern.compile(regex); 1696 final Matcher m = p.matcher(value); 1697 condition5 = m.find(); 1698 } 1699 1700 boolean condition6 = notEqual == null || (ignoreCase ? !StringUtils.equalsIgnoreCase(value, notEqual) 1701 : !StringUtils.equals(value, notEqual)); 1702 1703 result = condition1 && condition2 && condition3 && condition4 && condition5 && condition6; 1704 execIf(action, result); 1705 return result; 1706 } else if (isNull != null) { 1707 result = getVariableValue(replaceProperties(isNull)) == null; 1708 execIf(action, result); 1709 return result; 1710 } else if (isNotNull != null) { 1711 Object variableValue = getVariableValue(replaceProperties(isNotNull)); 1712 result = variableValue != null; 1713 execIf(action, result); 1714 return result; 1715 } else if (theExpressionAttribut != null) { 1716 theExpressionAttribut = replaceProperties(theExpressionAttribut); 1717 JexlEngine jexl = new JexlBuilder().create(); 1718 1719 JexlExpression expr_c = jexl.createExpression(theExpressionAttribut); 1720 JexlContext context = new MapContext(); 1721 1722 if (expr_c != null) { 1723 Object val = expr_c.evaluate(context); 1724 result = "true".equals(val.toString()); 1725 } 1726 1727 execIf(action, result); 1728 return result; 1729 } else if (theValue1Attribut != null || theValue2Attribut != null) { 1730 if (theConditionAttribut == null) { 1731 theConditionAttribut = "=="; 1732 } 1733 theValue1Attribut = replaceProperties(theValue1Attribut); 1734 theValue2Attribut = replaceProperties(theValue2Attribut); 1735 1736 if ("==".equals(theConditionAttribut) && theValue1Attribut.equals(theValue2Attribut)) { 1737 taskNode(action, false); 1738 result = true; 1739 } else if (("!=".equals(theConditionAttribut) || "unequal".equals(theConditionAttribut)) 1740 && (theValue1Attribut.equals(theValue2Attribut) == false)) { 1741 taskNode(action, false); 1742 result = true; 1743 } else if ("less".equals(theConditionAttribut) 1744 && (Long.parseLong(theValue1Attribut) < Long.parseLong(theValue2Attribut))) { 1745 taskNode(action, false); 1746 result = true; 1747 } else if ("bigger".equals(theConditionAttribut) 1748 && (Long.parseLong(theValue1Attribut) > Long.parseLong(theValue2Attribut))) { 1749 taskNode(action, false); 1750 result = true; 1751 } else { 1752 for (Node command : action.getNodes("Else")) { 1753 taskNode(command, false); 1754 } 1755 } 1756 } 1757 1758 return result; 1759 } 1760 1761 private void execIf(final Node action, boolean result) throws CommandException, Throwable { 1762 if (result) { 1763 taskNode(action, false); 1764 } else { 1765 for (Node command : action.getNodes("Else")) { 1766 if (command.getAttribute("name") == null && action.getAttribute("name") != null) { 1767 command.setAttribute("name", action.getAttribute("name")); 1768 } 1769 if (command.getAttribute("value") == null && action.getAttribute("value") != null) { 1770 command.setAttribute("value", action.getAttribute("value")); 1771 } 1772 if (command.getAttribute("name") != null || command.getAttribute("value") != null) { 1773 if (runIf(command)) { 1774 break; 1775 } 1776 } else { 1777 taskNode(command); 1778 } 1779 } 1780 } 1781 } 1782 1783 @CommandExamples({ 1784 "<While name='type:property' startsWith='type:string' endsWith='type:string' contains='type:string' equals='type:string' notEqual='type:string'> ... </While>", 1785 "<While value1='type:string' value2='type:string' condition='unequal'> ... <Else value1='type:string' value2='type:string' condition='enum:unequal|equal'> ... </Else></While>", 1786 "<While expression='type:string'> ... </While>", "<While isNull='type:property'> ... </While>", 1787 "<While isNotNull='type:property'> ... </While>" }) 1788 public void runCommandWhile(final Node aCurrentVar) throws Throwable { 1789 try { 1790 for (; runIf(aCurrentVar);) { 1791 if (this.breakFlag > 0) { 1792 break; 1793 } 1794 } 1795 } finally { 1796 if (this.breakFlag > 0) { 1797 breakFlag--; 1798 } 1799 } 1800 } 1801 1802 @CommandExamples({ "<Pragma event='console-input' action='default'/>", 1803 "<Pragma event='random-select' action='on'/>", "<Pragma event='log-window' action='single'/>" }) 1804 public void runCommandPragma(final Node aCurrentVar) throws Throwable { 1805 final String theEventAttribut = aCurrentVar.getAttribute("event"); 1806 final String theActionAttribut = aCurrentVar.getAttribute("action"); 1807 1808 if ("console-input".equals(theEventAttribut)) { 1809 boolean consoleDefaultInput = "default".equals(theActionAttribut); 1810 getListener().getManager().setConsoleDefaultInput(consoleDefaultInput); 1811 } else if ("random-select".equals(theEventAttribut)) { 1812 randomSelect = "on".equals(theActionAttribut); 1813 } else { 1814 this.log.error("Pragma ignored. Event: " + theEventAttribut); 1815 } 1816 } 1817 1818 @SuppressWarnings("unchecked") 1819 @CommandDescription("The `name` attribute is a name of variable which provides Runnable or List<Runnable> value. " 1820 + "To define this value, you should use the Runnable command tag.") 1821 @CommandExamples({ 1822 "<Threads name='type:property' threadLog='type:boolean' numbers='type:integer' multi='enum:true|false' />", 1823 "<Threads numbers='type:integer' multi='enum:true|false' mode='enum:wait|nowait'><Out name='" 1824 + TaskProcessorThread.THREAD_ID + "'/></Threads>", 1825 "<Threads multi='enum:true|false'><Out name='" + TaskProcessorThread.THREAD_ID + "'/></Threads>" }) 1826 public void runCommandThreads(final Node aCurrentAction) throws InterruptedException, CommandException { 1827 1828 boolean threadLog = Boolean 1829 .parseBoolean(StringUtils.defaultIfBlank(attr(aCurrentAction, "threadLog"), "false")); 1830 int numbers = Integer.parseInt(StringUtils.defaultIfBlank(attr(aCurrentAction, "numbers"), "1")); 1831 boolean multi = Boolean.parseBoolean(StringUtils.defaultIfBlank(attr(aCurrentAction, "multi"), "true")); 1832 1833 ThreadPoolExecutor threadPool; 1834 if (multi) { 1835 if (numbers > 0) { 1836 threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(numbers); 1837 } else { 1838 threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool(); 1839 } 1840 } else { 1841 threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(1); 1842 } 1843 1844 String callableListName = attr(aCurrentAction, "name"); 1845 if (callableListName == null) { 1846 final Iterator<?> theIterator = aCurrentAction.iterator(); 1847 1848 if (numbers == 0) { 1849 while (theIterator.hasNext()) { 1850 final Node theNode = (Node) theIterator.next(); 1851 1852 String theNameThreads = getTestName(theNode); 1853 if (theNameThreads == null) { 1854 theNameThreads = "Thread"; 1855 } 1856 1857 ILogger theLog = this.log; 1858 if (threadLog) { 1859 theLog = this.recipeListener.createLog(theNameThreads, false); 1860 } 1861 1862 final TaskProcessorThread runnable = new TaskProcessorThread(this, theNode, getBaseDir(), theLog); 1863 1864 threadPool.execute(runnable); 1865 1866 } 1867 } else { 1868 final Node theNode = (Node) aCurrentAction.clone(); 1869 theNode.setTag("Task"); 1870 theNode.removeAttribute(callableListName); 1871 1872 for (int i = 0; i < numbers; i++) { 1873 String theNameThreads = getTestName(theNode); 1874 String logName = "Thread #" + i; 1875 if (theNameThreads != null) { 1876 logName = theNameThreads + " #" + i; 1877 } 1878 1879 ILogger theLog = this.log; 1880 if (threadLog) { 1881 theLog = this.recipeListener.createLog(logName, false); 1882 } 1883 1884 final TaskProcessorThread runnable = new TaskProcessorThread(this, theNode, getBaseDir(), theLog); 1885 runnable.getVaribleValue(TaskProcessorThread.THREAD_ID, String.valueOf(i)); 1886 1887 threadPool.execute(runnable); 1888 } 1889 } 1890 1891 } else { 1892 Object callableList = getVariableValue(callableListName); 1893 if (callableList instanceof List) { 1894 for (Runnable runnable : (List<Runnable>) callableList) { 1895 threadPool.execute(runnable); 1896 } 1897 } else if (callableList instanceof Runnable) { 1898 for (int i = 0; i < numbers; i++) { 1899 if (callableList instanceof TaskProcessorThread) { 1900 threadPool.execute(((TaskProcessorThread) callableList).clone(i)); 1901 } else { 1902 threadPool.execute((Runnable) callableList); 1903 } 1904 } 1905 } else { 1906 throw new IllegalArgumentException( 1907 "Variable of type must be Runnable or List<Runnable>, actually: " + callableList); 1908 } 1909 } 1910 1911 String description = replaceProperties(aCurrentAction.getAttribute("description")); 1912 1913 long completedTaskCount = 0; 1914 long size = threadPool.getTaskCount(); 1915 1916 threadPoolList.add(threadPool); 1917 do { 1918 completedTaskCount = threadPool.getCompletedTaskCount(); 1919 progress(size, completedTaskCount, description, false); 1920 Thread.sleep(200); 1921 1922 } while (completedTaskCount < size); 1923 threadPoolList.remove(threadPool); 1924 } 1925 1926 @CommandExamples({ "Run recipe by name: <Task name='type:recipe' />", 1927 "Run recipe by name in async mode: <Task name='type:recipe' mode='async' optional='optional'/>", 1928 "Recipe command grouping: <Task> ... </Task>", 1929 "Run recipe by file path: <Task file='type:path' />" }) 1930 public void runCommandTask(final Node action) throws Throwable { 1931 1932 final boolean optional = Boolean.valueOf(attr(action, "optional", "false")); 1933 1934 final String taskName = replaceProperties(action.getAttribute("name")); 1935 String taskFile = replaceProperties(action.getAttribute("file")); 1936 1937 if (taskFile == null) { 1938 if (taskName != null) { 1939 taskFile = getListener().getManager().getTestPath(taskName); 1940 1941 if (taskFile == null) { 1942 if (optional) { 1943 return; 1944 } else { 1945 throw new Exception("Task with name: '" + taskName + "' not found."); 1946 } 1947 } 1948 } 1949 } else { 1950 if (!(new File(taskFile)).exists()) { 1951 if (optional) { 1952 return; 1953 } else { 1954 throw new Exception("Task with name: '" + taskFile + "' not found."); 1955 } 1956 } 1957 } 1958 1959 final File theBaseDir = getBaseDir(); 1960 try { 1961 if (taskName != null) { 1962 String mode = replaceProperties(action.getAttribute("mode")); 1963 if ("async".equals(mode)) { 1964 getListener().getManager().runTask(taskName, true); 1965 1966 } else { 1967 Properties taskParameters = MapUtils.toProperties(action.getAttributes()); 1968 Set<Entry<Object, Object>> entrySet = taskParameters.entrySet(); 1969 1970 String currentLogLevel = (String) this.variables.get(DEFAULT_LOG_LEVEL_NAME); 1971 String level = (String) taskParameters.get("level"); 1972 1973 for (Entry<Object, Object> entry : entrySet) { 1974 String name = (String) entry.getKey(); 1975 if (!"$ID".equals(name) && !"name".equals(name) && !"file".equals(name) 1976 && !"level".equals(name)) { 1977 String value = replaceProperties((String) entry.getValue()); 1978 this.variables.put(toUpperCaseName(name), value); 1979 } 1980 } 1981 1982 this.variables.put(DEFAULT_LOG_LEVEL_NAME, level); 1983 this.variables = processTesting(taskFile, this.variables, getBaseDir()); 1984 this.variables.put(DEFAULT_LOG_LEVEL_NAME, currentLogLevel); 1985 } 1986 } else { 1987 taskNode(action, false); 1988 } 1989 } finally { 1990 setBaseDir(theBaseDir); 1991 } 1992 } 1993 1994 @CommandExamples({ "<IterationRules name='type:property'><Out name='Iteration'/></IterationRules>", 1995 "<IterationRules name='type:property' timeLimit='type:time' start='type:integer'> ... </IterationRules>", 1996 "<Var name='rules'>#\n[multiple]\na=1\nb $enum=1;2\nc $inc=0;10\nd $file=file_name\n[single]\n...\n[concurrently]\n...\n[independent]\n...\n#</Var>" 1997 + "<IterationRules name='rules'><Out name='Iteration'/></IterationRules>", }) 1998 public void runCommandIterationRules(final Node action) throws IOException, CommandException { 1999 final String name = (String) attrValue(action, "name"); 2000 String theStartAttribut = action.getAttribute("start"); 2001 long theLimit = parseTime(action, "timeLimit", "180000"); 2002 2003 if (theStartAttribut == null) { 2004 theStartAttribut = "0"; 2005 } 2006 2007 final int theStart = Integer.parseInt(theStartAttribut); 2008 if (name == null) { 2009 throw new CommandException("In tag <IterationRules> variable rules is not defined.", this); 2010 } 2011 try { 2012 this.iteratorMode = true; 2013 final TestIterator theTestIterator = new TestIterator(this, name); 2014 final int theMax = theTestIterator.count(); 2015 progress(theMax, 0, "Iteration process", false); 2016 debug("Iteration block. Total count: " + theMax); 2017 final long theStertTime = System.currentTimeMillis(); 2018 for (int i = theStart; i < theMax; i++) { 2019 if (isStopped()) { 2020 break; 2021 } 2022 setVariableValue("Iteration", Integer.toString(i + 1)); 2023 theTestIterator.nextIteration(this); 2024 2025 taskNode(action, false); 2026 2027 progress(theMax, i, "Iteration process", false); 2028 if (i == 0) { 2029 long theTotalTime = ((System.currentTimeMillis() - theStertTime) * theMax) / 60000; 2030 debug("Total Iteration time: " + Long.toString(theTotalTime) + " min."); 2031 if (theTotalTime > theLimit) { 2032 int theConfirm = 0; 2033 if (this.recipeListener.getManager() != null) { 2034 if (this.recipeListener.getManager().isConsoleDefaultInput(attr(action, "name"), 2035 attr(action, "description")) == false) { 2036 if (theTotalTime < 60) { 2037 theConfirm = JOptionPane.showConfirmDialog( 2038 JOptionPane.getRootFrame(), "Total Iteration time: " 2039 + Long.toString(theTotalTime) + " min. \nContinue?", 2040 "Warning", JOptionPane.YES_NO_OPTION); 2041 } else { 2042 theTotalTime /= 60; 2043 theConfirm = JOptionPane.showConfirmDialog(JOptionPane.getRootFrame(), 2044 "Total Iteration time: " + Long.toString(theTotalTime) + " h. \nContinue?", 2045 "Warning", JOptionPane.YES_NO_OPTION); 2046 } 2047 } 2048 if (theConfirm != JOptionPane.YES_OPTION) { 2049 break; 2050 } 2051 } 2052 } 2053 } 2054 } 2055 } finally { 2056 this.iteratorMode = false; 2057 } 2058 } 2059 2060 @CommandExamples({ "<Listdir path='type:path' name='type:property'/>", 2061 "<Listdir name='type:property' path='type:path' filter='type:regex'/>", 2062 "<Listdir name='type:property' path='type:path' filter='type:regex' dirFilter='type:regex' />", 2063 "<Listdir path='type:path' name='type:property' tree='type:boolean'/>" }) 2064 public void runCommandListdir(final Node aCurrentVar) throws Throwable { 2065 final String thePathAttribut = replaceProperties(aCurrentVar.getAttribute("path")); 2066 final String theNameAttribut = replaceProperties(aCurrentVar.getAttribute("name")); 2067 final String fileFilterRegex = attr(aCurrentVar, "filter"); 2068 final String dirFilterRegex = attr(aCurrentVar, "dirFilter"); 2069 File theFile = getFile(thePathAttribut); 2070 2071 if (isActiveInitFor(aCurrentVar, "console")) { 2072 String path = this.recipeListener.getManager().inputFile(theNameAttribut, null, theFile, log, this); 2073 if (path != null) { 2074 theFile = new File(path); 2075 } 2076 } 2077 2078 if (theFile != null) { 2079 debug("Listing of directory: " + theFile.getAbsolutePath()); 2080 2081 String[] theValue = null; 2082 if ("true".equals(attr(aCurrentVar, "tree")) || fileFilterRegex != null || dirFilterRegex != null) { 2083 IOFileFilter fileFilter = TrueFileFilter.TRUE; 2084 IOFileFilter dirFilter = TrueFileFilter.TRUE; 2085 2086 if (fileFilterRegex != null) { 2087 fileFilter = new RegexFileFilter(fileFilterRegex); 2088 } 2089 2090 if (dirFilterRegex != null) { 2091 fileFilter = new RegexFileFilter(dirFilterRegex); 2092 } 2093 2094 @SuppressWarnings("unchecked") 2095 Collection<File> files = FileUtils.listFiles(theFile, fileFilter, dirFilter); 2096 if (files != null) { 2097 theValue = new String[files.size()]; 2098 int i = 0; 2099 for (File file : files) { 2100 theValue[i++] = file.getAbsolutePath(); 2101 } 2102 } 2103 } else { 2104 int i = 0; 2105 File[] listFiles = theFile.listFiles(); 2106 if (listFiles != null) { 2107 theValue = new String[listFiles.length]; 2108 for (File file : listFiles) { 2109 theValue[i++] = file.getAbsolutePath(); 2110 } 2111 } 2112 } 2113 2114 if (theValue != null) { 2115 Arrays.sort(theValue); 2116 setVariableValue(theNameAttribut, theValue); 2117 } 2118 } else { 2119 throw new TaskCancelingException(); 2120 } 2121 } 2122 2123 @CommandExamples({ "<NetworkInterfaces name='type:property' />", 2124 "<NetworkInterfaces name='type:property' host='type:string' filterFor='type:string'/>" }) 2125 public void runCommandNetworkInterfaces(final Node aCurrentAction) throws SocketException, UnknownHostException { 2126 final String name = replaceProperties(aCurrentAction.getAttribute("name")); 2127 String host = replaceProperties(aCurrentAction.getAttribute("host")); 2128 2129 if (host == null) { 2130 Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); 2131 Set<String> hostIps = new HashSet<>(); 2132 while (networkInterfaces.hasMoreElements()) { 2133 NetworkInterface nextElement = networkInterfaces.nextElement(); 2134 Enumeration<InetAddress> inetAddresses = nextElement.getInetAddresses(); 2135 while (inetAddresses.hasMoreElements()) { 2136 InetAddress nextElement2 = inetAddresses.nextElement(); 2137 if (nextElement2 instanceof Inet4Address) { 2138 Inet4Address address = (Inet4Address) nextElement2; 2139 String hostAddress = address.getHostAddress(); 2140 hostIps.add(hostAddress); 2141 } 2142 } 2143 } 2144 setVariableValue(name, new ArrayList<>(hostIps)); 2145 } else { 2146 try { 2147 URL url = new URL(host); 2148 host = url.getHost(); 2149 } catch (Exception e) { 2150 2151 } 2152 2153 InetAddress address1 = InetAddress.getByName(host); 2154 setVariableValue(name, address1.getHostAddress()); 2155 } 2156 } 2157 2158 @CommandDescription("Executes a command on the local computer. The command will be executed if the regular expression specified in `os` matches the OS_NAME system property. " 2159 + "The `dir` attribute specifies the current directory for the command being executed. This attribute can use `~` as the directory for the current recipe.") 2160 @CommandExamples({ "<Command os='type:regex'>...</Command>", 2161 "<Command name='type:property' os='type:regex' exitValue='type:property' cmd='type:string' noCommandLog='type:boolean' dir='type:path'/>", 2162 "<Command name='type:property' os='type:regex' exitValue='type:property' cmd='type:string' noCommandLog='type:boolean' dir='type:path'/>...</Command>" }) 2163 public void runCommandCommand(final Node aCurrentNode) throws Throwable { 2164 2165 String command = replaceProperties(aCurrentNode.getAttribute("cmd")); 2166 final String name = replaceProperties(aCurrentNode.getAttribute("name")); 2167 final String dir = replaceProperties(aCurrentNode.getAttribute("dir")); 2168 final String os = replaceProperties(aCurrentNode.getAttribute("os")); 2169 2170 String osName = SystemUtils.OS_NAME; 2171 2172 if (os == null || Pattern.compile(os).matcher(osName).matches()) { 2173 if (command == null) { 2174 final Node[] theNodes = aCurrentNode.getTextNodes(); 2175 if (theNodes.length > 0) { 2176 command = replaceProperties(theNodes[0].getText()); 2177 } 2178 } 2179 2180 runSystemCommand(command, name, aCurrentNode, dir); 2181 } 2182 } 2183 2184 private void runSystemCommand(final String theCommandAttribut, final String theNameAttribut, 2185 final Node aCurrentNode, String dir) throws Throwable { 2186 final String prefix = "start "; 2187 if (theCommandAttribut.startsWith(prefix) == false) { 2188 2189 String regExp = "\"(\\\"|[^\"])*?\"|[^ ]+"; 2190 Pattern pattern = Pattern.compile(regExp, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); 2191 Matcher matcher = pattern.matcher(theCommandAttribut); 2192 List<String> matches = new ArrayList<String>(); 2193 while (matcher.find()) { 2194 matches.add(matcher.group()); 2195 } 2196 String[] parsedCommand = matches.toArray(new String[] {}); 2197 2198 ProcessBuilder builder = new ProcessBuilder(parsedCommand); 2199 2200 if (dir != null) { 2201 File directory; 2202 if (dir.startsWith("~/")) { 2203 dir = dir.substring(1); 2204 String recipeFile = this.recipeListener.getManager().getTestPath(testName); 2205 if (recipeFile != null) { 2206 directory = new File(new File(recipeFile).getParent(), dir); 2207 builder.directory(directory); 2208 } 2209 } else { 2210 directory = new File(dir); 2211 builder.directory(directory); 2212 } 2213 } 2214 2215 builder.redirectErrorStream(true); 2216 Process process = builder.start(); 2217 2218 final String stdin = replaceProperties(aCurrentNode.getAttribute("stdin")); 2219 if (stdin != null) { 2220 process.getOutputStream().write(stdin.getBytes()); 2221 process.getOutputStream().close(); 2222 } 2223 2224 processes.add(process); 2225 2226 final BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getInputStream())); 2227 boolean noCommandLog = Boolean.valueOf(attr(aCurrentNode, "noCommandLog")); 2228 if (!noCommandLog) { 2229 debug("Command: " + theCommandAttribut); 2230 } else { 2231 debug("Command: ****** **** *****"); 2232 } 2233 2234 try { 2235 final BufferedReader theOutputStream = new BufferedReader( 2236 new InputStreamReader(process.getInputStream())); 2237 String theLine; 2238 2239 boolean line_output = aCurrentNode.size() == 0; 2240 final StringBuffer theBuffer = new StringBuffer(); 2241 while ((theLine = theOutputStream.readLine()) != null && !isStoppedTest()) { 2242 if (breakFlag > 0) { 2243 break; 2244 } 2245 2246 if (line_output) { 2247 theBuffer.append(theLine); 2248 theBuffer.append('\n'); 2249 } else { 2250 setVariableValue(theNameAttribut, theLine); 2251 taskNode(aCurrentNode, false); 2252 } 2253 } 2254 2255 if (this.breakFlag > 0) { 2256 breakFlag--; 2257 } 2258 2259 String exitValueName = attr(aCurrentNode, "exitValue"); 2260 if (exitValueName != null) { 2261 int exitValue = 0; 2262 try { 2263 exitValue = process.exitValue(); 2264 if (exitValue > 0) { 2265 String error = IOUtils.toString(errorStream); 2266 if (StringUtils.isNotBlank(error)) { 2267 throw new RuntimeException(error); 2268 } 2269 } 2270 } catch (IllegalThreadStateException e) { 2271 // 2272 } 2273 setVariableValue(exitValueName, Integer.toString(exitValue)); 2274 } 2275 2276 if (line_output) { 2277 if (theNameAttribut == null) { 2278 debug("System output:" + theBuffer.toString()); 2279 } else { 2280 setVariableValue(theNameAttribut, theBuffer.toString()); 2281 } 2282 } 2283 } finally { 2284 processes.remove(process); 2285 process.destroyForcibly(); 2286 try { 2287 if (!process.waitFor(5, TimeUnit.SECONDS)) { 2288 process.destroyForcibly(); 2289 } 2290 } catch (InterruptedException e) { 2291 Thread.currentThread().interrupt(); 2292 process.destroyForcibly(); 2293 } 2294 } 2295 2296 } else { 2297 final Thread thread = new SystemCommandStart(theCommandAttribut.substring(prefix.length()), this.log); 2298 thread.start(); 2299 } 2300 } 2301 2302 @CommandExamples({ "<ArraySize name = 'type:property' array = 'type:property'/>" }) 2303 public void runCommandArraySize(final Node aCurrentVar) throws Throwable { 2304 final String theNameAttribut = replaceProperties(aCurrentVar.getAttribute("name")); 2305 final String theArrayNameAttribut = replaceProperties(aCurrentVar.getAttribute("array")); 2306 final Object theValue = getVariableValue(theArrayNameAttribut); 2307 2308 int theResult = 0; 2309 if (theValue instanceof String[]) { 2310 theResult = ((String[]) theValue).length; 2311 } else if (theValue instanceof List) { 2312 theResult = ((List<String>) theValue).size(); 2313 } else if (theValue instanceof byte[]) { 2314 theResult = ((byte[]) theValue).length; 2315 } else if (theValue instanceof String && StringUtils.isNotBlank((String) theValue)) { 2316 theResult = 1; 2317 } else { 2318 theResult = 0; 2319 } 2320 2321 setVariableValue(theNameAttribut, String.valueOf(theResult)); 2322 } 2323 2324 @CommandExamples({ "Get string or array length: <Size name = 'type:property' source = 'type:property'/>" }) 2325 public void runCommandSize(final Node aCurrentVar) throws Throwable { 2326 final String theNameAttribut = replaceProperties(aCurrentVar.getAttribute("name")); 2327 final String theArrayNameAttribut = replaceProperties(aCurrentVar.getAttribute("source")); 2328 final Object theValue = getVariableValue(theArrayNameAttribut); 2329 2330 int theResult = 0; 2331 if (theValue instanceof String[]) { 2332 String[] theValue2 = (String[]) theValue; 2333 for (int i = 0; i < theValue2.length; i++) { 2334 theResult += theValue2[i].length(); 2335 } 2336 } else if (theValue instanceof byte[]) { 2337 theResult = ((byte[]) theValue).length; 2338 } else if (theValue instanceof Collection) { 2339 theResult = ((Collection) theValue).size(); 2340 } else if (theValue instanceof String && StringUtils.isNotBlank((String) theValue)) { 2341 theResult = ((String) theValue).length(); 2342 } else { 2343 theResult = 0; 2344 } 2345 2346 setVariableValue(theNameAttribut, String.valueOf(theResult)); 2347 } 2348 2349 @CommandExamples({ "<Time name = 'type:property' action = 'enum:start|continue|pause|stop'/>", 2350 "<Time name = 'type:property' action = 'format' format='mm:ss:SSS'/>", 2351 "<Time name = 'type:property' action = 'duration' >...code whose execution time is to be measured...</Time>" }) 2352 public void runCommandTime(final Node command) throws Throwable { 2353 final String theNameAttribut = replaceProperties(command.getAttribute("name")); 2354 final String format = replaceProperties(command.getAttribute("format")); 2355 final String theTimeCaption = "Time"; 2356 String action = replaceProperties(command.getAttribute("action")); 2357 2358 if ("duration".equals(action)) { 2359 long start = System.currentTimeMillis(); 2360 2361 taskNode(command, false); 2362 2363 long stop = System.currentTimeMillis(); 2364 final String[] variableValue = new String[] { theTimeCaption, String.valueOf(start), String.valueOf(stop), 2365 "" }; 2366 2367 String result = formatTime(format, variableValue); 2368 setVariableValue(theNameAttribut, result); 2369 return; 2370 } 2371 2372 if ("start".equals(action)) { 2373 final String[] theTime = new String[] { theTimeCaption, String.valueOf(System.currentTimeMillis()), "", 2374 "" }; 2375 setVariableValue(theNameAttribut, theTime); 2376 return; 2377 } 2378 2379 if ("continue".equals(action)) { 2380 String[] theTime = (String[]) getVariableValue(theNameAttribut); 2381 if (theTime == null) { 2382 theTime = new String[] { theTimeCaption, String.valueOf(System.currentTimeMillis()), "", 2383 String.valueOf(System.currentTimeMillis()) }; 2384 } 2385 2386 if (theTime == null || theTime[3] == null || theTime[3].length() == 0) { 2387 throw new Exception("Timer is not paused."); 2388 } 2389 2390 if (theTimeCaption.equals(theTime[0])) { 2391 final long theStart = Long.parseLong(theTime[1]); 2392 final long thePaused = Long.parseLong(theTime[3]); 2393 theTime[1] = String.valueOf(theStart - (System.currentTimeMillis() - thePaused)); 2394 theTime[3] = ""; 2395 setVariableValue(theNameAttribut, theTime); 2396 } else { 2397 throw new Exception("Incorrect type."); 2398 } 2399 return; 2400 } 2401 2402 if ("pause".equals(action)) { 2403 final String[] theTime = (String[]) getVariableValue(theNameAttribut); 2404 2405 if (theTime[3] != null && theTime[3].length() > 0) { 2406 throw new Exception("Timer is paused."); 2407 } 2408 if (theTimeCaption.equals(theTime[0])) { 2409 theTime[3] = String.valueOf(System.currentTimeMillis()); 2410 setVariableValue(theNameAttribut, theTime); 2411 } else { 2412 throw new Exception("Incorrect type."); 2413 } 2414 return; 2415 } 2416 2417 if ("stop".equals(action)) { 2418 final String[] theTime = (String[]) getVariableValue(theNameAttribut); 2419 2420 final long theStart = Long.parseLong(theTime[1]); 2421 2422 if (theTime[3] != null && theTime[3].length() > 0) { 2423 final long thePaused = Long.parseLong(theTime[3]); 2424 theTime[1] = String.valueOf(theStart + (System.currentTimeMillis() - thePaused)); 2425 theTime[3] = ""; 2426 } 2427 2428 if (theTimeCaption.equals(theTime[0])) { 2429 theTime[2] = String.valueOf(System.currentTimeMillis()); 2430 setVariableValue(theNameAttribut, theTime); 2431 } else { 2432 throw new Exception("Incorrect type."); 2433 } 2434 return; 2435 } 2436 2437 if ("format".equals(action)) { 2438 Object variableValue = getVariableValue(theNameAttribut); 2439 String theResult = formatTime(format, variableValue); 2440 setVariableValue(theNameAttribut, theResult); 2441 return; 2442 } 2443 } 2444 2445 private String formatTime(final String format, Object variableValue) throws Exception { 2446 final String[] theTime; 2447 if (variableValue instanceof String[]) { 2448 theTime = (String[]) variableValue; 2449 } else { 2450 theTime = new String[] { "", "0", (String) variableValue }; 2451 } 2452 2453 if (ArrayUtils.getLength(theTime) < 2) { 2454 throw new Exception("Timer is not defined."); 2455 } 2456 2457 if (ArrayUtils.getLength(theTime) < 3) { 2458 throw new Exception("Timer is not stoped."); 2459 } 2460 2461 String theResult = null; 2462 if (format == null) { 2463 theResult = String.valueOf(Long.parseLong(theTime[2]) - Long.parseLong(theTime[1])); 2464 } else { 2465 final DateFormat dateFormat = new SimpleDateFormat(format); 2466 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 2467 long date = Long.parseLong(theTime[2]) - Long.parseLong(theTime[1]); 2468 theResult = dateFormat.format(new Date(date)); 2469 } 2470 return theResult; 2471 } 2472 2473 @CommandExamples({ "<ArrayElement name='type:property' array='type:property' elementId='type:number'/>" }) 2474 public void runCommandArrayElement(final Node aCurrentVar) throws Throwable { 2475 final String theNameAttribut = replaceProperties(aCurrentVar.getAttribute("name")); 2476 final String theArrayNameAttribut = replaceProperties(aCurrentVar.getAttribute("array")); 2477 if (theArrayNameAttribut == null) { 2478 throw new IllegalArgumentException("'array' attribute required."); 2479 } 2480 2481 final String theElementAttribut = replaceProperties(aCurrentVar.getAttribute("elementId")); 2482 if (theElementAttribut == null) { 2483 throw new IllegalArgumentException("'elementId' attribute required."); 2484 } 2485 2486 final String type = replaceProperties(aCurrentVar.getAttribute("type")); 2487 Object theValue = getVariableValue(theArrayNameAttribut); 2488 2489 final int theElementId = Integer.parseInt(theElementAttribut); 2490 2491 theValue = convert(theValue, type); 2492 2493 Object theResult = null; 2494 if (theValue instanceof JSONArray) { 2495 JSONArray jsonArray = (JSONArray) theValue; 2496 theResult = jsonArray.get(theElementId); 2497 } else if (theValue instanceof String[]) { 2498 theResult = ((String[]) theValue)[theElementId]; 2499 } else if (theValue instanceof String) { 2500 if ("string".equalsIgnoreCase(type)) { 2501 theResult = new String(new char[] { ((String) theValue).charAt(theElementId) }); 2502 } else if (theElementId == 0) { 2503 theResult = theValue; 2504 } 2505 } else if (theElementId == 0) { 2506 theResult = theValue; 2507 } 2508 2509 setVariableValue(theNameAttribut, theResult); 2510 } 2511 2512 @CommandDescription("The Calculate command is implemented in the Java Expression Language (JEXL), " 2513 + "for more information see: https://commons.apache.org/proper/commons-jexl. " 2514 + "The value of the expression will be stored in the variable with the name specified in the `name` attribute.") 2515 @CommandExamples({ "<Calculate name='type:property' expressions='type:string'/>", 2516 "<Calculate name='type:property'>...</Calculate>" }) 2517 public void runCommandCalculate(final Node command) throws Throwable { 2518 final String name = replaceProperties(command.getAttribute("name")); 2519 String expressions = replaceProperties(command.getAttribute("expressions")); 2520 if (expressions == null) { 2521 expressions = replaceProperties(command.getInnerText()); 2522 } 2523 2524 JexlEngine jexl = new JexlBuilder().create(); 2525 2526 JexlExpression expr_c = jexl.createExpression(expressions); 2527 JexlContext context = new MapContext(); 2528 2529 Map<String, String> attributes = command.getAttributes(); 2530 for (Map.Entry<String, String> entry : attributes.entrySet()) { 2531 String key = entry.getKey(); 2532 String val = entry.getValue(); 2533 2534 Object variableValue = getVariableValue(val); 2535 if (variableValue instanceof String) { 2536 try { 2537 variableValue = Double.parseDouble((String) variableValue); 2538 } catch (NumberFormatException e) { 2539 // DO NOTHING 2540 } 2541 } 2542 2543 context.set(key, variableValue); 2544 } 2545 2546 if (expr_c != null) { 2547 Object result = expr_c.evaluate(context); 2548 2549 if (result != null) { 2550 setVariableValue(name, result); 2551 } else { 2552 setVariableValue(name, null); 2553 } 2554 } 2555 } 2556 2557 @CommandExamples({ 2558 "<Parse name='type:property' source='type:property' type='enum:array|json|csv|fixed-length-line'/>", 2559 "<Parse name='type:property' source='type:property' type='fixed-length-line' length='type:integer'/>" }) 2560 public void runCommandParse(final Node command) throws Throwable { 2561 Object source = attrValue(command, "source"); 2562 final String theNameAttribut = replaceProperties(command.getAttribute("name")); 2563 final String type = replaceProperties(command.getAttribute("type")); 2564 2565 if ("json".equalsIgnoreCase(type)) { 2566 String theValue = ObjectUtils.toString(source); 2567 if (StringUtils.isNotBlank(theValue)) { 2568 Object obj = new JSONObject(theValue); 2569 if (obj instanceof JSONObject) { 2570 JSONObject result = new JSONObject(theValue); 2571 setVariableValue(theNameAttribut, result); 2572 } else if (obj instanceof JSONArray) { 2573 JSONArray result = new JSONArray(theValue); 2574 String[] array = new String[result.length()]; 2575 for (int i = 0; i < result.length(); i++) { 2576 array[i] = ObjectUtils.toString(result.get(i)); 2577 } 2578 setVariableValue(theNameAttribut, array); 2579 } 2580 } else { 2581 setVariableValue(theNameAttribut, theValue); 2582 } 2583 2584 } else if ("array".equalsIgnoreCase(type)) { 2585 String theValue = ObjectUtils.toString(source); 2586 2587 String[] array = StringUtils.split(theValue, "\r\n"); 2588 setVariableValue(theNameAttribut, array); 2589 } else if ("csv".equalsIgnoreCase(type)) { 2590 String theValue = ObjectUtils.toString(source); 2591 2592 CSVReader reader = new CSVReader(new StringReader(theValue)); 2593 List<String[]> r = reader.readAll(); 2594 2595 setVariableValue(theNameAttribut, r); 2596 } else if ("fixed-length-line".equalsIgnoreCase(type)) { 2597 if (source instanceof String) { 2598 String input = (String) source; 2599 int lineLength = Integer.parseInt(attr(command, "length")); 2600 List<Object> result = IntStream.range(0, (input.length() + lineLength - 1) / lineLength) 2601 .mapToObj(i -> input.substring(i * lineLength, Math.min((i + 1) * lineLength, input.length()))) 2602 .collect(Collectors.toList()); 2603 setVariableValue(theNameAttribut, result); 2604 } 2605 } 2606 } 2607 2608 @CommandExamples({ "<FindObject name='type:property' source='type:property' withValue='type:string'/>" }) 2609 public void runCommandFindObject(final Node aCurrentNode) throws Throwable { 2610 Object json = getVariableValue(replaceProperties(aCurrentNode.getAttribute("source"))); 2611 String withValue = replaceProperties(aCurrentNode.getAttribute("withValue")); 2612 2613 if (json instanceof String) { 2614 String jsonStr = (String) json; 2615 if (StringUtils.startsWith(jsonStr, "{")) { 2616 json = new JSONObject(jsonStr); 2617 } else if (StringUtils.startsWith(jsonStr, "[")) { 2618 json = new JSONArray(jsonStr); 2619 } 2620 } else if (json instanceof String[]) { 2621 String[] jsonStrArray = (String[]) json; 2622 JSONArray array = new JSONArray(); 2623 for (int i = 0; i < jsonStrArray.length; i++) { 2624 String jsonStr = jsonStrArray[i]; 2625 array.put(new JSONObject(jsonStr)); 2626 } 2627 json = array; 2628 } 2629 2630 Object value = find(json, withValue); 2631 2632 final String name = replaceProperties(aCurrentNode.getAttribute("name")); 2633 applyResult(aCurrentNode, name, value); 2634 } 2635 2636 private JSONObject find(Object obj, String withValue) throws JSONException { 2637 if (obj instanceof JSONObject) { 2638 JSONObject json = (JSONObject) obj; 2639 2640 JSONArray names = json.names(); 2641 if (names != null) { 2642 for (int i = 0; i < names.length(); i++) { 2643 String name = names.getString(i); 2644 Object object = json.get(name); 2645 if (object instanceof String) { 2646 if (ObjectUtils.equals(object, withValue)) { 2647 return json; 2648 } 2649 } else { 2650 JSONObject find = find(object, withValue); 2651 if (find != null) { 2652 return find; 2653 } 2654 } 2655 } 2656 } 2657 } else if (obj instanceof JSONArray) { 2658 JSONArray array = (JSONArray) obj; 2659 2660 for (int j = 0; j < array.length(); j++) { 2661 Object item = array.get(j); 2662 2663 JSONObject find = find(item, withValue); 2664 if (find != null) { 2665 return find; 2666 } 2667 } 2668 } 2669 return null; 2670 } 2671 2672 @CommandDescription("Var is used to define or update a variable. If the init attribute is set to console, a user " 2673 + "input dialog box is activated. The text type is used only for large text values.") 2674 @CommandExamples({ 2675 "Input dialog: <Var name='type:property' init='enum:console|mandatory|default' type='enum:string|text|password|path'/>", 2676 "Apply data type: <Var name='type:property' type='enum:array|number|map|json|string' />", 2677 "Substring extracting: <Var name='type:property' source='type:property' start='type:string' end='type:string'/>", 2678 "Array definition: <Var name='type:property'><item>...</item></Var>", 2679 "Map definition: <Var name='type:property' type='map'><item key='type:string'>...</item></Var>", 2680 "Input file path value: <Var name='type:property' type='enum:array|number' file='type:path'/>", 2681 "Copy value from sourse variable: <Var name='type:property' source='type:property' />" }) 2682 public void runCommandVar(final Node aCurrentVar) throws Throwable { 2683 final String name = replaceProperties(aCurrentVar.getAttribute("name")); 2684 String description = replaceProperties(aCurrentVar.getAttribute("description")); 2685 String theInit = replaceProperties(aCurrentVar.getAttribute("init")); 2686 2687 Object theOldValue = getVariableValue(name); 2688 if ("default".equals(theInit) && theOldValue != null) { 2689 if (theOldValue instanceof String) { 2690 if (StringUtils.isNotBlank((String) theOldValue)) { 2691 return; 2692 } 2693 } else if (theOldValue instanceof String[] && ((String[]) theOldValue).length > 0) { 2694 return; 2695 } 2696 } 2697 2698 if ("file".equals(theInit)) { 2699 loadProperties(getFile(name), this.variables, false); 2700 return; 2701 } 2702 String source = replaceProperties(aCurrentVar.getAttribute("source"), true); 2703 Object theValue = getVariableValue(name); 2704 if (source != null) { 2705 String sourceVarName = replaceProperties(source); 2706 theValue = getVariableValue(sourceVarName); 2707 theOldValue = theValue; 2708 setVariableValue(name, theValue); 2709 } 2710 2711 String value = aCurrentVar.getAttribute("value"); 2712 if (value != null) { 2713 theValue = replaceProperties(value); 2714 } 2715 2716 // Item setting 2717 String type = StringUtils.defaultIfEmpty(aCurrentVar.getAttribute("type"), ""); 2718 if (aCurrentVar.size() > 0) { 2719 if (Node.TEXT_TEAG_NAME.equals(aCurrentVar.getNode(0).getTag())) { 2720 final Node theTextNode = aCurrentVar.getNode(0); 2721 theValue = replaceProperties(theTextNode.getText()); 2722 2723 } else { 2724 switch (type) { 2725 case "map": 2726 Node[] nodes = aCurrentVar.getNodes("item"); 2727 theValue = new LinkedHashMap<String, String>(); 2728 for (Node node : nodes) { 2729 ((Map) theValue).put(node.getAttribute("key"), replaceProperties(node.getInnerText())); 2730 } 2731 break; 2732 2733 default: 2734 List<Object> theItemArray = new ArrayList<>(); 2735 for (int i = 0; i < aCurrentVar.size(); i++) { 2736 final Node theCurrentAction = (Node) aCurrentVar.get(i); 2737 Node[] theItemNodes = theCurrentAction.getTextNodes(); 2738 if (theItemNodes != null && theItemNodes.length == 1) { 2739 final String replaceProperties = replaceProperties(theItemNodes[0].getText(), true); 2740 theItemArray.add(replaceProperties); 2741 } else { 2742 if (theCurrentAction.size() == 1) { 2743 Node node = theCurrentAction.get(0); 2744 EasyUtils.removeAllAttributes(node, Node.TAG_ID); 2745 theItemArray.add(replaceProperties(node.getXMLText(), true)); 2746 } else { 2747 theItemArray = null; 2748 } 2749 break; 2750 } 2751 } 2752 theValue = theItemArray; 2753 } 2754 } 2755 } 2756 2757 boolean contains = StringUtils.contains(theInit, "mandatory"); 2758 boolean isConsoleInput = StringUtils.contains(theInit, "console"); 2759 boolean mandatory = StringUtils.contains(theInit, "mandatory"); 2760 if (mandatory) { 2761 if (!isEmpty(theOldValue)) { 2762 setVariableValue(name, theValue); 2763 } else { 2764 isConsoleInput = true; 2765 } 2766 } 2767 2768 final boolean theIntegerType = "number".equals(type); 2769 if (theIntegerType) { 2770 String string = ObjectUtils.toString(theValue); 2771 if (StringUtils.isNotBlank(string) && !NumberUtils.isNumber(string)) { 2772 setVariableValue(name, null); 2773 throw new NumberFormatException(string); 2774 } 2775 } 2776 2777 final boolean theArrayType = "array".equals(type); 2778 if (name != null && !(theValue == null && theArrayType == false)) { 2779 if (theArrayType) { 2780 char separatorChar = ','; 2781 if (theValue instanceof String) { 2782 String[] split = StringUtils.split((String) theValue, separatorChar); 2783 theValue = split != null ? Arrays.asList(split) : null; 2784 } 2785 } 2786 if (theArrayType && theValue == null) { 2787 theValue = new String[0]; 2788 } 2789 2790 String file = replaceProperties(aCurrentVar.getAttribute("file")); 2791 if (theArrayType && file != null) { 2792 ArrayList<String> buffer = new ArrayList<String>(); 2793 2794 if (theValue instanceof String[]) { 2795 for (String string : (String[]) theValue) { 2796 buffer.add(string); 2797 } 2798 } else if (theValue instanceof Collection) { 2799 buffer = new ArrayList<String>((Collection<String>) theValue); 2800 } 2801 2802 try (InputStream inputStream = AEUtils.getInputStream(file, getBaseDir())) { 2803 String encoding = replaceProperties(aCurrentVar.getAttribute("charset")); 2804 if (encoding == null) { 2805 encoding = "UTF-8"; 2806 } 2807 final BufferedReader theFileReader = new BufferedReader( 2808 new InputStreamReader(inputStream, encoding)); 2809 String readLine; 2810 while ((readLine = theFileReader.readLine()) != null) { 2811 buffer.add(readLine); 2812 } 2813 } 2814 theValue = buffer; 2815 } 2816 2817 theValue = convert(theValue, type); 2818 setVariableValue(name, theValue); 2819 } 2820 2821 if (isConsoleInput) { 2822 2823 if (theOldValue instanceof List && CollectionUtils.size(theOldValue) == 1) { 2824 theOldValue = ((List) theOldValue).get(0); 2825 } 2826 2827 if ((aCurrentVar.size() == 0 || !aCurrentVar.getInnerText().isEmpty()) 2828 && (isEmpty(theOldValue) || theOldValue instanceof String)) { 2829 Object theInitialSelectionValue = null; 2830 final Object o = getVariableValue(name); 2831 if (o instanceof String) { 2832 theInitialSelectionValue = o; 2833 } 2834 if (o instanceof String[] && ((String[]) o).length > 0) { 2835 if (this.random == null) { 2836 this.random = SecureRandom.getInstance("SHA1PRNG"); 2837 } 2838 theInitialSelectionValue = ((String[]) o)[this.random.nextInt(((String[]) o).length)]; 2839 } 2840 2841 String defaultValue = AEWorkspace.getInstance().getDefaultUserConfiguration(".inputValue." + name, 2842 (String) theInitialSelectionValue); 2843 if (this.recipeListener.getManager().isConsoleDefaultInput(name, description) 2844 && !(mandatory && defaultValue == null)) { 2845 2846 if ((o instanceof String[] && ArrayUtils.contains((String[]) o, defaultValue)) || o == null) { 2847 theInitialSelectionValue = defaultValue; 2848 } 2849 2850 setVariableValue(name, theInitialSelectionValue); 2851 } else { 2852 boolean notifyMe = this.recipeListener.isNotifyMe(); 2853 Object inputValue; 2854 2855 inputValue = this.recipeListener.getManager().inputValue(name, description, defaultValue, log, type, 2856 notifyMe, this); 2857 2858 setVariableValue(name, inputValue); 2859 } 2860 2861 } else { 2862 List possibleValues = null; 2863 if (theOldValue instanceof List) { 2864 final List theStringArray = (List) theOldValue; 2865 possibleValues = theStringArray; 2866 } else if (theOldValue instanceof String[]) { 2867 possibleValues = new ArrayList(); 2868 String[] array = (String[]) theOldValue; 2869 for (String item : array) { 2870 possibleValues.add(item); 2871 } 2872 } else { 2873 possibleValues = new ArrayList(); 2874 for (int i = 0; i < aCurrentVar.size(); i++) { 2875 final Node theCurrentAction = (Node) aCurrentVar.get(i); 2876 possibleValues.add(theCurrentAction.getInnerText()); 2877 } 2878 } 2879 2880 if (this.recipeListener.getManager().isConsoleDefaultInput(name, null)) { 2881 String theInitialSelectionValue = randomSelect(possibleValues); 2882 if (!randomSelect) { 2883 theInitialSelectionValue = AEWorkspace.getInstance() 2884 .getDefaultUserConfiguration(".choiceValue." + name, theInitialSelectionValue); 2885 2886 } 2887 setVariableValue(name, theInitialSelectionValue); 2888 } else { 2889 boolean notifyMe = this.recipeListener.isNotifyMe(); 2890 final Object theValueOut = this.recipeListener.getManager().choiceValue(name, description, 2891 possibleValues.toArray(), log, notifyMe, this); 2892 setVariableValue(name, theValueOut); 2893 } 2894 } 2895 } 2896 2897 theValue = getVariableValue(name); 2898 2899 String start = replaceProperties(aCurrentVar.getAttribute("start")); 2900 String end = replaceProperties(aCurrentVar.getAttribute("end")); 2901 2902 if (StringUtils.isNotEmpty(start)) { 2903 if (theValue instanceof byte[]) { 2904 theValue = new String((byte[]) theValue); 2905 } 2906 theValue = StringUtils.substringAfter(ObjectUtils.toString(theValue), start); 2907 if (StringUtils.isBlank((String) theValue)) { 2908 theValue = null; 2909 } 2910 } 2911 if (StringUtils.isNotEmpty(end)) { 2912 theValue = StringUtils.substringBefore((String) theValue, end); 2913 if (StringUtils.isBlank((String) theValue)) { 2914 theValue = null; 2915 } 2916 } 2917 2918 applyResult(aCurrentVar, name, theValue); 2919 2920 if (contains && theValue == null) { 2921 stop(); 2922 } 2923 } 2924 2925 private Object convert(Object theValue, String type) throws JSONException { 2926 if ("json".equals(type)) { 2927 Object parse = theValue; 2928 if (theValue instanceof String[]) { 2929 String[] array = (String[]) theValue; 2930 List<String> asList = Arrays.asList(array); 2931 theValue = new JSONArray(asList); 2932 } else if (theValue instanceof String) { 2933 if (StringUtils.startsWith((String) theValue, "{")) { 2934 parse = new JSONObject(theValue.toString()); 2935 } else if (StringUtils.startsWith((String) theValue, "[")) { 2936 parse = new JSONArray(theValue.toString()); 2937 } 2938 } 2939 theValue = parse; 2940 } else if ("string".equals(type) && theValue instanceof String[]) { 2941 theValue = StringUtils.join((String[]) theValue); 2942 } 2943 2944 return theValue; 2945 } 2946 2947 private String randomSelect(List possibleValues) throws NoSuchAlgorithmException { 2948 final String theInitialSelectionValue; 2949 if (this.random == null) { 2950 this.random = SecureRandom.getInstance("SHA1PRNG"); 2951 } 2952 theInitialSelectionValue = (String) possibleValues.get(this.random.nextInt(possibleValues.size())); 2953 return theInitialSelectionValue; 2954 } 2955 2956 @CommandExamples({ "<Note name='type:string' connection='type:string'>...</Note>" }) 2957 public void runCommandNote(final Node aCurrentAction) throws Throwable { 2958 } 2959 2960 @CommandExamples({ "<!-- ... -->" }) 2961 public void runCommandComment(final Node aCurrentAction) throws Throwable { 2962 } 2963 2964 @CommandExamples({ "<Extern class='type:processor'>\n...\n</Extern>" }) 2965 public void runCommandExtern(final Node command) throws Throwable { 2966 final Processor newInstance = makeProcessor(command); 2967 boolean success = false; 2968 try { 2969 this.externProcessor = newInstance; 2970 externProcessor.setTestName(getTestName()); 2971 newInstance.init(this, command); 2972 boolean rootRecipe = isRootRecipe(); 2973 newInstance.setRootContext(rootRecipe); 2974 newInstance.stackTask.addAll(this.stackTask); 2975 newInstance.taskNode(command, false); 2976 2977 this.variables = newInstance.variables; 2978 success = true; 2979 } finally { 2980 externProcessor.complete(success); 2981 externProcessor = null; 2982 } 2983 } 2984 2985 @CommandExamples({ "<Confirm message='type:string' name='type:string'/>", 2986 "<Confirm message='type:string' name='type:string'>...</Confirm>" }) 2987 public void runCommandConfirm(final Node aCurrentAction) throws Throwable { 2988 final String message = attr(aCurrentAction, "message"); 2989 final String name = attr(aCurrentAction, "name"); 2990 final Object nameVar = getVariableValue(name); 2991 2992 boolean confirmed = false; 2993 if (nameVar != null && nameVar instanceof String) { 2994 confirmed = BooleanUtils.toBoolean((String) nameVar); 2995 } else { 2996 AEManager manager = this.recipeListener.getManager(); 2997 confirmed = manager.confirmation(name, message, this, this.recipeListener.isNotifyMe()); 2998 } 2999 3000 if (aCurrentAction.size() > 0) { 3001 if (confirmed) { 3002 taskNode(aCurrentAction, false); 3003 } 3004 } else { 3005 if (!confirmed) { 3006 stop(); 3007 } 3008 } 3009 } 3010 3011 @CommandExamples({ "<WhileRun name='type:string' message='type:string'>...</WhileRun>" }) 3012 public void runCommandWhileRun(final Node aCurrentAction) throws Throwable { 3013 final String message = replaceProperties(aCurrentAction.getAttribute("message")); 3014 final String name = replaceProperties(aCurrentAction.getAttribute("name")); 3015 final Object nameVar = getVariableValue(name); 3016 3017 if (!(nameVar instanceof String) || BooleanUtils.toBoolean((String) nameVar)) { 3018 AEManager manager = this.recipeListener.getManager(); 3019 MessageHandler handler = manager.message(this, name, message, this.recipeListener.isNotifyMe()); 3020 taskNode(aCurrentAction, false); 3021 handler.close(); 3022 } 3023 }; 3024 3025 @CommandDescription("The `Server` command initializes and starts a server socket listener, " 3026 + "operating as a blocking command that prevents the execution of subsequent commands until it completes.") 3027 @CommandExamples({ "<Server port='type:integer' request='type:property' response='type:property' > ... </Server>", 3028 "<Server port='type:integer' numbers='type:integer' request='type:property' response='type:property' > ... </Server>" }) 3029 public void runCommandServer(final Node aCurrentAction) throws Throwable { 3030 3031 String encoding = replaceProperties(aCurrentAction.getAttribute("charset")); 3032 if (encoding == null) { 3033 encoding = "UTF-8"; 3034 } 3035 3036 final int thePort = Integer.parseInt(replaceProperties(aCurrentAction.getAttribute("port"))); 3037 int maxNumber = 0; 3038 3039 final String theMaxNumbers = replaceProperties(aCurrentAction.getAttribute("numbers")); 3040 if (theMaxNumbers != null) { 3041 maxNumber = Integer.parseInt(theMaxNumbers); 3042 } 3043 final String request = attr(aCurrentAction, "request"); 3044 final String response = attr(aCurrentAction, "response"); 3045 3046 ServerAction server = new ServerAction(this, aCurrentAction, thePort, request, response, encoding, maxNumber); 3047 server.perform(); 3048 } 3049 3050 @CommandExamples({ "<Restore/>", "<Restore name='type:property'> ... </Restore>", 3051 "<Restore except='type:property'> ... </Restore>" }) 3052 public void runCommandRestore(final Node command) throws Throwable { 3053 String name = attr(command, "name"); 3054 String except = attr(command, "except"); 3055 3056 if (CollectionUtils.isEmpty(command)) { 3057 final Map<String, Object> systemVariables = getListener().getManager().getSystemVariables(); 3058 this.variables.clear(); 3059 this.variables.putAll(systemVariables); 3060 debug("Task variables has been restored."); 3061 } else if (name != null) { 3062 Object savedVariable = getVariableValue(name); 3063 taskNode(command, false); 3064 setVariableValue(name, savedVariable); 3065 3066 } else if (except != null) { 3067 Map<String, Object> savedVariables = this.variables; 3068 this.variables = new HashMap<String, Object>(this.variables); 3069 3070 taskNode(command, false); 3071 3072 Object object = getVariableValue(except); 3073 this.variables.clear(); 3074 this.variables = savedVariables; 3075 setVariableValue(except, object); 3076 } 3077 3078 } 3079 3080 @CommandDescription("Use the Finally command tag before protected code to ensure it is executed " 3081 + "before exiting the current parent tag, as usual Finally is defined as a first executable command.\n" 3082 + "Example: `<Recipe><Finally> ...finally code... </Finally> ...some code... </Recipe>`") 3083 @CommandExamples({ "<Finally> ... </Finally>" }) 3084 public void runCommandFinally(final Node aCurrentAction) throws Throwable { 3085 } 3086 3087 @CommandExamples({ "<Break/>" }) 3088 public void runCommandBreak(final Node aCurrentAction) throws Throwable { 3089 } 3090 3091 @CommandExamples({ "<Stop/>", "<Stop ifNull='type:property'/>" }) 3092 public void runCommandStop(final Node aCurrentAction) throws Throwable { 3093 } 3094 3095 private boolean isEmpty(Object theOldValue) { 3096 boolean result = false; 3097 if (theOldValue == null) { 3098 result = true; 3099 } else if (theOldValue instanceof String[] && ((String[]) theOldValue).length == 0) { 3100 result = true; 3101 } else if (theOldValue instanceof Map && ((Map) theOldValue).size() == 0) { 3102 result = true; 3103 } 3104 return result; 3105 } 3106 3107 public void setVariableValue(String name, final Object value) { 3108 if (name != null) { 3109 super.setVariableValue(name, value); 3110 if (this.recipeListener != null && name.startsWith("!") == false) { 3111 this.recipeListener.changeVariable(name, value); 3112 } 3113 } 3114 } 3115 3116}