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