001package com.ganteater.ae;
002
003import java.io.File;
004import java.util.HashMap;
005import java.util.List;
006import java.util.Map;
007
008import org.apache.commons.lang.ObjectUtils;
009import org.apache.commons.lang.StringEscapeUtils;
010import org.apache.commons.lang.StringUtils;
011import org.apache.commons.lang.math.NumberUtils;
012import org.apache.sling.commons.json.JSONArray;
013import org.apache.sling.commons.json.JSONException;
014import org.apache.sling.commons.json.JSONObject;
015
016import com.ganteater.ae.util.AEUtils;
017import com.ganteater.ae.util.xml.easyparser.Node;
018
019public class TemplateProcessor {
020
021        protected static final String MAPPED_VAR_DELIM = "::";
022
023        public Map<String, Object> variables = new HashMap<String, Object>();
024
025        protected static Map<String, Object> fGlobalVariables = new HashMap<String, Object>();
026
027        private boolean fstoppedTest = false;
028
029        protected Node configNode;
030
031        private File fBaseDir;
032
033        protected TemplateProcessor() {
034        }
035
036        public TemplateProcessor(Map<String, Object> variables, Node configNode, File baseDir) {
037                super();
038                this.variables = variables;
039                this.configNode = configNode;
040                setBaseDir(baseDir);
041        }
042
043        public File getBaseDir() {
044                return fBaseDir;
045        }
046
047        public void setBaseDir(File theBaseDir) {
048                this.fBaseDir = theBaseDir;
049        }
050
051        public String replaceProperties(String aValue) {
052                if (aValue == null)
053                        return null;
054
055                do {
056                        aValue = replaceProperties(aValue, false);
057                } while (aValue.indexOf("$var{") >= 0);
058
059                return aValue;
060        }
061
062        protected String replaceProperties(String value, boolean aUseDefaultValue) {
063                value = replaceFile(value);
064                String theStartKey = "$var{";
065                String theEndKey = "}";
066                int theBeginPos = 0;
067                int theEndPos = 0;
068                if (value == null) {
069                        return value;
070                }
071                StringBuffer theStringBuffer = new StringBuffer();
072                while (true) {
073                        theBeginPos = value.indexOf(theStartKey, theEndPos);
074                        if (theBeginPos < 0) {
075                                break;
076                        }
077                        theStringBuffer.append(value.substring(theEndPos, theBeginPos));
078                        theEndPos = value.indexOf(theEndKey, theBeginPos);
079                        if (theEndPos < 0) {
080                                throw new RuntimeException(
081                                                "Variable getting incorrect syntax, absent symbol '" + theEndKey + "' for: " + value);
082                        }
083                        String theNameProperty = value.substring(theBeginPos + theStartKey.length(), theEndPos);
084                        String theDefaultValue = null;
085                        // default value checking
086                        int defaultPos = theNameProperty.indexOf(',');
087                        if (defaultPos >= 0) {
088                                theDefaultValue = theNameProperty.substring(defaultPos + 1);
089                                theNameProperty = theNameProperty.substring(0, defaultPos);
090                        }
091                        String theValue = null;
092
093                        if ("THREAD_INFO".equals(theNameProperty)) {
094                                theValue = Thread.currentThread().toString();
095
096                        } else if (StringUtils.startsWith(theNameProperty, "\\")) {
097                                theValue = specialVariableParsing(theNameProperty);
098
099                        } else {
100                                Object o = null;
101                                if (aUseDefaultValue == false || theDefaultValue == null) {
102                                        o = getVariableValue(theNameProperty);
103                                }
104                                if (AEUtils.isEmpty(o) && theDefaultValue != null) {
105                                        o = theDefaultValue;
106                                }
107
108                                if (o instanceof String) {
109                                        theValue = (String) o;
110                                } else if (o instanceof List) {
111                                        if (!((List) o).isEmpty()) {
112                                                theValue = String.valueOf(((List) o).get(0));
113                                        } else {
114                                                theValue = StringUtils.EMPTY;
115                                        }
116
117                                } else if (o instanceof byte[]) {
118                                        theValue = new String((byte[]) o);
119                                } else if (o instanceof String[]) {
120                                        theValue = StringUtils.join((String[]) o, "\n");
121                                } else {
122                                        theValue = ObjectUtils.toString(o);
123                                }
124
125                        }
126
127                        remarkExtendsReplacer(theStringBuffer, theValue, "/*$var{" + theNameProperty + "}*/");
128                        theEndPos += theEndKey.length();
129                }
130                theStringBuffer.append(value.substring(theEndPos));
131
132                return replaceTag(replaceCall(theStringBuffer.toString()));
133        }
134
135        protected String specialVariableParsing(String nameProperty) {
136                return StringEscapeUtils.unescapeJava(nameProperty);
137        }
138
139        private void remarkExtendsReplacer(StringBuffer aStringBuffer, String aValue, String aRemark) {
140                String s = null;
141                if (aStringBuffer.length() >= 4) {
142                        s = aStringBuffer.substring(aStringBuffer.length() - 4);
143                }
144                if ("';--".equals(s)) {
145                        int theEnd = 0;
146                        for (theEnd = aStringBuffer.length() - 5;; theEnd--) {
147                                char c = aStringBuffer.charAt(theEnd);
148                                if (c == '\'') {
149                                        break;
150                                }
151                        }
152                        aStringBuffer.setLength(theEnd);
153                        aStringBuffer.append('\'');
154                        aStringBuffer.append(aValue);
155                        aStringBuffer.append('\'');
156                        aStringBuffer.append(';');
157                        if (aRemark != null) {
158                                aStringBuffer.append(" " + aRemark);
159                        }
160                } else {
161                        s = null;
162                        if (aStringBuffer.length() >= 3) {
163                                s = aStringBuffer.substring(aStringBuffer.length() - 3);
164                        }
165                        if (";--".equals(s)) {
166                                int theEnd = 0;
167                                for (theEnd = aStringBuffer.length() - 4;; theEnd--) {
168                                        char c = aStringBuffer.charAt(theEnd);
169                                        if (c == ' ' || c == '=') {
170                                                break;
171                                        }
172                                }
173                                aStringBuffer.setLength(theEnd + 1);
174                                aStringBuffer.append(aValue);
175                                aStringBuffer.append(';');
176                                if (aRemark != null) {
177                                        aStringBuffer.append(" " + aRemark);
178                                }
179                        } else {
180                                s = null;
181                                if (aStringBuffer.length() >= 2) {
182                                        s = aStringBuffer.substring(aStringBuffer.length() - 2);
183                                }
184                                if ("--".equals(s)) {
185                                        aStringBuffer.setLength(aStringBuffer.length() - 2);
186                                        aStringBuffer.append(aValue);
187                                } else {
188                                        aStringBuffer.append(aValue);
189                                }
190                        }
191                }
192        }
193
194        protected String replaceCall(String aValue) {
195                return aValue;
196        }
197
198        protected String replaceTag(String aValue) {
199                String theStartKey = "$tag{";
200                String theEndKey = "}";
201                int theBeginPos = 0;
202                int theEndPos = 0;
203                if (aValue == null) {
204                        return aValue;
205                }
206                StringBuffer theStringBuffer = new StringBuffer();
207                while (true) {
208                        theBeginPos = aValue.indexOf(theStartKey, theEndPos);
209                        if (theBeginPos < 0) {
210                                break;
211                        }
212                        theStringBuffer.append(aValue.substring(theEndPos, theBeginPos));
213                        theEndPos = aValue.indexOf(theEndKey, theBeginPos);
214                        if (theEndPos < 0) {
215                                throw new RuntimeException("Tag created is incorrect syntax, absent symbol '" + theEndKey + "'.");
216                        }
217                        String theLine = aValue.substring(theBeginPos + theStartKey.length(), theEndPos);
218                        int thePbrk = theLine.indexOf(',');
219                        String theTagName = theLine;
220                        String theNameVar = theLine;
221                        if (thePbrk > 0) {
222                                theTagName = theLine.substring(0, thePbrk);
223                                theNameVar = theLine.substring(thePbrk + 1);
224                        }
225                        Object o = getVariableValue(theNameVar);
226                        String theValue = null;
227                        if (o instanceof String) {
228                                theValue = (String) o;
229                        }
230                        if (o instanceof List && !((List) o).isEmpty()) {
231                                theValue = String.valueOf(((List) o).get(0));
232                        }
233                        if (theValue != null) {
234                                theStringBuffer.append('<');
235                                theStringBuffer.append(theTagName);
236                                theStringBuffer.append('>');
237                                theValue = theValue.replaceAll("\"", "&quot;");
238                                theValue = theValue.replaceAll("\'", "&apos;");
239                                theValue = theValue.replaceAll("<", "&lt;");
240                                theValue = theValue.replaceAll(">", "&gt;");
241                                theStringBuffer.append(theValue);
242                                theStringBuffer.append("</");
243                                theStringBuffer.append(theTagName);
244                                theStringBuffer.append('>');
245                        } else {
246                                theStringBuffer.append('<');
247                                theStringBuffer.append(theTagName);
248                                theStringBuffer.append("/>");
249                        }
250                        theEndPos += theEndKey.length();
251                }
252                theStringBuffer.append(aValue.substring(theEndPos));
253                return theStringBuffer.toString();
254        }
255
256        protected String replaceFile(String aValue) {
257                String theStartKey = "$file{";
258                String theEndKey = "}";
259                int theBeginPos = 0;
260                int theEndPos = 0;
261                if (aValue == null) {
262                        return aValue;
263                }
264                StringBuffer theStringBuffer = new StringBuffer();
265                while (true) {
266                        theBeginPos = aValue.indexOf(theStartKey, theEndPos);
267                        if (theBeginPos < 0) {
268                                break;
269                        }
270                        theStringBuffer.append(aValue.substring(theEndPos, theBeginPos));
271                        theEndPos = aValue.indexOf(theEndKey, theBeginPos);
272                        if (theEndPos < 0) {
273                                throw new RuntimeException(
274                                                "Insert file marcer is incorrect syntax, absent symbol '" + theEndKey + "'.");
275                        }
276                        String theLine = aValue.substring(theBeginPos + theStartKey.length(), theEndPos);
277                        int thePbrk = theLine.indexOf(',');
278                        String theFileName = theLine;
279                        String theEncodeVar = "UTF-8";
280                        if (thePbrk > 0) {
281                                theFileName = theLine.substring(0, thePbrk);
282                                theEncodeVar = theLine.substring(thePbrk + 1);
283                        }
284                        String theXML;
285                        try {
286                                theXML = AEUtils.loadResource(theFileName, getBaseDir(), theEncodeVar);
287                        } catch (Exception e) {
288                                throw new RuntimeException(e);
289                        }
290                        theXML = replaceProperties(theXML);
291                        remarkExtendsReplacer(theStringBuffer, theXML, null);
292                        theEndPos += theEndKey.length();
293                }
294                theStringBuffer.append(aValue.substring(theEndPos));
295                return theStringBuffer.toString();
296        }
297
298        public Object getVariableValue(String aAttribut) {
299                if (aAttribut == null)
300                        return null;
301                aAttribut = toUpperCaseName(aAttribut).trim();
302                if ("BASEDIR".equals(aAttribut))
303                        return getBaseDir().getPath();
304                return getVariableValue(aAttribut, true);
305        }
306
307        public String getVariableString(String aAttribut) {
308                Object variableValue = getVariableValue(aAttribut);
309
310                if (variableValue instanceof List) {
311                        List theStringArr = (List) variableValue;
312                        if (theStringArr.size() > 0) {
313                                variableValue = theStringArr.get(0);
314                        }
315                }
316
317                return ObjectUtils.toString(variableValue, null);
318        }
319
320        public String toUpperCaseName(String aAttribut) {
321                String result = null;
322                if (aAttribut.indexOf(MAPPED_VAR_DELIM) >= 0) {
323                        result = StringUtils.substringBefore(aAttribut, MAPPED_VAR_DELIM).toUpperCase() + MAPPED_VAR_DELIM
324                                        + StringUtils.substringAfter(aAttribut, MAPPED_VAR_DELIM);
325                } else {
326                        result = aAttribut.toUpperCase();
327                }
328                return result;
329        }
330
331        public Object getVariableValue(String aAttribut, boolean aArrayTrimed) {
332                Object o = null;
333                aAttribut = toUpperCaseName(aAttribut);
334                Map<String, Object> theVariables = variables;
335                if (aAttribut.startsWith("!"))
336                        theVariables = fGlobalVariables;
337
338                boolean isMappedVar = aAttribut.indexOf(MAPPED_VAR_DELIM) > 0;
339                if (isMappedVar) {
340                        o = getValueByPath(aAttribut, theVariables);
341
342                } else {
343                        o = theVariables.get(aAttribut);
344                }
345
346                if (o instanceof List) {
347                        List theStringArr = (List) o;
348                        if (theStringArr.size() == 1 && aArrayTrimed) {
349                                o = theStringArr.get(0);
350                        }
351                }
352
353                if (o instanceof JSONArray) {
354                        JSONArray array = (JSONArray) o;
355                        String[] value = new String[array.length()];
356                        for (int i = 0; i < value.length; i++) {
357                                value[i] = ObjectUtils.toString(array.opt(i));
358                        }
359                        o = value;
360                }
361
362                return o;
363        }
364
365        private Object getValueByPath(String aAttribut, Map<String, Object> theVariables) {
366                Object o = null;
367                String mapVarName = StringUtils.substringBefore(aAttribut, MAPPED_VAR_DELIM);
368                try {
369                        Object object = theVariables.get(mapVarName);
370                        if (object instanceof String && ((String) object).trim().startsWith("{")) {
371                                object = new JSONObject(ObjectUtils.toString(object));
372                        }
373
374                        @SuppressWarnings("unchecked")
375                        Object mapVar = object;
376
377                        mapVarName = StringUtils.substringAfter(aAttribut, MAPPED_VAR_DELIM);
378
379                        if (mapVar instanceof Map) {
380                                o = getNestedValue(mapVarName, (Map) mapVar);
381                        } else if (mapVar instanceof JSONObject) {
382                                JSONObject json = (JSONObject) object;
383                                o = getNestedJsonValue(mapVarName, (JSONObject) json);
384                        }
385
386                } catch (ClassCastException | JSONException e) {
387                        e.printStackTrace();
388                        o = null;
389                }
390                return o;
391        }
392
393        private Object getNestedValue(String varName, Map<String, Object> mapVar) {
394                Object o;
395                if (mapVar != null) {
396                        String mapVarName = StringUtils.substringBefore(varName, MAPPED_VAR_DELIM);
397                        o = mapVar.get(mapVarName);
398
399                        mapVarName = StringUtils.substringAfter(varName, MAPPED_VAR_DELIM);
400                        if (StringUtils.isNotBlank(mapVarName) && o instanceof Map) {
401                                o = getNestedValue(mapVarName, (Map<String, Object>) o);
402                        }
403
404                } else {
405                        o = null;
406
407                }
408                return o;
409        }
410
411        private Object getNestedJsonValue(String varName, Object json) throws JSONException {
412                Object o = null;
413                try {
414                        if (json != null) {
415                                String mapVarName = StringUtils.substringBefore(varName, MAPPED_VAR_DELIM);
416                                if (json instanceof JSONObject) {
417                                        o = ((JSONObject) json).get(mapVarName);
418                                } else if (json instanceof JSONArray) {
419                                        JSONArray array = (JSONArray) json;
420                                        if (NumberUtils.isNumber(mapVarName)) {
421                                                o = array.get(Integer.parseInt(mapVarName));
422                                        } else {
423                                                o = null;
424                                        }
425                                }
426
427                                mapVarName = StringUtils.substringAfter(varName, MAPPED_VAR_DELIM);
428                                if (StringUtils.isNotBlank(mapVarName)) {
429                                        o = getNestedJsonValue(mapVarName, o);
430                                }
431
432                        } else {
433                                o = null;
434
435                        }
436                } catch (JSONException e) {
437                        o = null;
438                }
439                return o;
440        }
441
442        public File getFile(String theFileAttribut) {
443                return new File(theFileAttribut);
444        }
445
446        public static Map<String, Object> getGlobalVariables() {
447                return fGlobalVariables;
448        }
449
450        public void setVariableValue(String name, final Object value) {
451
452                if (name == null) {
453                        return;
454                }
455
456                name = toUpperCaseName(name);
457
458                Map<String, Object> variables = this.variables;
459                if (name.startsWith("!")) {
460                        variables = fGlobalVariables;
461                }
462                boolean isMappedVar = name.indexOf(MAPPED_VAR_DELIM) > 0;
463
464                if (value == null) {
465                        if (isMappedVar) {
466                                String mapVarName = StringUtils.substringBefore(name, MAPPED_VAR_DELIM);
467                                Object mapVar = variables.get(mapVarName);
468                                if (mapVar != null) {
469                                        if (mapVar instanceof Map) {
470                                                ((Map<?, ?>) mapVar).remove(name);
471                                                return;
472                                        }
473                                }
474
475                        } else {
476                                variables.remove(name);
477                                return;
478                        }
479                }
480
481                if (isMappedVar) {
482                        String mapVarName = StringUtils.substringBefore(name, MAPPED_VAR_DELIM);
483
484                        Object valueObj = variables.get(mapVarName);
485                        if (valueObj instanceof JSONObject) {
486                                String varName = StringUtils.substringAfter(name, MAPPED_VAR_DELIM);
487                                setJsonValue(valueObj, varName, value);
488                                return;
489
490                        } else if (!(valueObj instanceof Map)) {
491                                variables.put(mapVarName, new HashMap());
492                        }
493                        @SuppressWarnings("unchecked")
494                        Map<String, Object> mapVar = (Map<String, Object>) variables.get(mapVarName);
495
496                        if (mapVar == null) {
497                                mapVar = new HashMap<String, Object>();
498                                variables.put(mapVarName, mapVar);
499                        }
500
501                        String varName = StringUtils.substringAfter(name, MAPPED_VAR_DELIM);
502                        mapVar.put(varName, value);
503
504                } else {
505                        variables.put(name, value);
506                }
507
508        }
509
510        private void setJsonValue(Object value, String name, final Object aValue) {
511                String varName = StringUtils.substringBefore(name, MAPPED_VAR_DELIM);
512                String nestedName = StringUtils.substringAfter(name, MAPPED_VAR_DELIM);
513
514                JSONObject json = (JSONObject) value;
515                try {
516                        if (StringUtils.isEmpty(nestedName)) {
517                                if (aValue instanceof String[]) {
518                                        JSONArray jsonArray = new JSONArray();
519                                        String[] array = (String[]) aValue;
520                                        for (String item : array) {
521                                                jsonArray.put(new JSONObject(item));
522                                        }
523                                        json.put(varName, jsonArray);
524                                } else {
525                                        json.put(varName, aValue);
526                                }
527
528                        } else {
529                                Object object = json.get(varName);
530                                setJsonValue(object, nestedName, aValue);
531                        }
532
533                } catch (JSONException e) {
534                        // TODO Auto-generated catch block
535                        e.printStackTrace();
536                }
537        }
538
539        public void stop() {
540                this.setStopped(true);
541        }
542
543        public boolean isStopped() {
544                return fstoppedTest;
545        }
546
547        public void setStopped(boolean fstoppedTest) {
548                this.fstoppedTest = fstoppedTest;
549        }
550
551}