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