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