1 package de.juplo.thymeleaf;
4 import com.fasterxml.jackson.core.JsonFactory;
5 import de.juplo.simplemapper.SimpleMapper;
6 import java.io.IOException;
7 import java.util.HashMap;
8 import java.util.Iterator;
11 import java.util.Map.Entry;
12 import java.util.regex.Matcher;
13 import java.util.regex.Pattern;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16 import org.thymeleaf.IEngineConfiguration;
17 import org.thymeleaf.context.ITemplateContext;
18 import org.thymeleaf.engine.AttributeName;
19 import org.thymeleaf.engine.EngineEventUtils;
20 import org.thymeleaf.exceptions.TemplateProcessingException;
21 import org.thymeleaf.model.IProcessableElementTag;
22 import org.thymeleaf.processor.element.AbstractAttributeTagProcessor;
23 import org.thymeleaf.processor.element.IElementTagStructureHandler;
24 import org.thymeleaf.standard.expression.FragmentExpression;
25 import org.thymeleaf.standard.expression.FragmentExpression.ExecutedFragmentExpression;
26 import org.thymeleaf.standard.expression.IStandardExpression;
27 import org.thymeleaf.standard.expression.NoOpToken;
28 import org.thymeleaf.standard.expression.StandardExpressionExecutionContext;
29 import org.thymeleaf.templatemode.TemplateMode;
30 import org.thymeleaf.templateresolver.ITemplateResolver;
31 import org.thymeleaf.templateresolver.TemplateResolution;
36 * Retrievs and parses JSON-data and imports the parsed variables as node-local
40 public class ImportVariablesAttributeProcessor extends AbstractAttributeTagProcessor
42 private static final Logger LOG =
43 LoggerFactory.getLogger(ImportVariablesAttributeProcessor.class);
44 private static final JsonFactory FACTORY = new JsonFactory();
45 private static final String PROPERTY_NAME =
46 ImportVariablesAttributeProcessor.class.getCanonicalName() + "_VARIABLES";
48 public static final Pattern PATTERN =
50 "^\\s*(?:(?:(merge)|replace):)?\\s*(?:(\\{.*\\})|(.*))\\s*$",
51 Pattern.DOTALL | Pattern.CASE_INSENSITIVE
54 public static final String ATTR_NAME = "variables";
55 public static final int ATTR_PRECEDENCE = 200;
58 public ImportVariablesAttributeProcessor(String prefix)
60 super(TemplateMode.HTML, prefix, null, false, ATTR_NAME, true, ATTR_PRECEDENCE, true);
65 protected void doProcess(
66 final ITemplateContext context,
67 final IProcessableElementTag element,
68 final AttributeName name,
69 final String attribute,
70 final IElementTagStructureHandler handler
73 if (attribute == null)
80 final IStandardExpression expression =
81 EngineEventUtils.computeAttributeExpression(
88 if (expression != null && expression instanceof FragmentExpression)
90 final ExecutedFragmentExpression executedFragmentExpression =
91 FragmentExpression.createExecutedFragmentExpression(
93 (FragmentExpression) expression,
94 StandardExpressionExecutionContext.NORMAL
97 FragmentExpression.resolveExecutedFragmentExpression(
99 executedFragmentExpression,
105 result = expression.execute(context);
108 // If the result of this expression is NO-OP, there is nothing to execute
109 if (result == NoOpToken.VALUE)
111 handler.removeAttribute(name);
115 location = result.toString();
117 catch (final TemplateProcessingException e)
119 location = attribute;
123 Iterator<Entry<String, Object>> it = null;
125 Matcher matcher = PATTERN.matcher(location);
126 boolean merge = false;
129 if (matcher.matches())
131 merge = matcher.group(1) != null;
132 json = matcher.group(2);
133 location = matcher.group(3);
138 LOG.info("parsing parameter as JSON");
139 LOG.debug("parameter: {}", json);
142 it = SimpleMapper.getObjectIterator(FACTORY.createParser(json));
144 catch (IOException e)
146 LOG.error("cannot parse parameter as JSON: {}", json, e.getMessage());
152 LOG.info("retriving {} as Spring-resource", location);
153 IEngineConfiguration config = context.getConfiguration();
154 for (ITemplateResolver resolver : config.getTemplateResolvers())
156 TemplateResolution resolution =
157 resolver.resolveTemplate(
159 context.getTemplateData().getTemplate(),
163 if (resolution != null)
167 it = SimpleMapper.getObjectIterator(FACTORY.createParser(resolution.getTemplateResource().reader()));
170 catch (IOException e) {}
176 LOG.error("cannot resolve {} as JSON (not found)!", location);
183 Map<String, Object> variables = getVariables(context);
188 Entry<String, Object> variable = it.next();
189 String key = variable.getKey();
190 Object value = variable.getValue();
191 Object existing = context.getVariable(key);
192 if (existing != null)
194 if (value instanceof String)
196 if (!(existing instanceof String))
199 "cannot merge variable {} of type {} with a string",
203 throw new RuntimeException(
204 "Type-Missmatch for variable " + key
208 String string = ((String)existing).concat((String) value);
209 LOG.info("appending variable to string {}", key);
210 handler.setLocalVariable(key, string);
212 else if (value instanceof Map)
214 if (!(existing instanceof Map))
217 "cannot merge variable {} of type {} with a map",
221 throw new RuntimeException(
222 "Type-Missmatch for variable " + key
226 Map map = ((Map)existing);
227 map.putAll((Map) value);
228 LOG.info("merging variable with map {}", key);
229 handler.setLocalVariable(key, map);
231 else if (value instanceof List)
233 if (!(existing instanceof List))
236 "cannot merge variable {} of type {} with a list",
240 throw new RuntimeException(
241 "Type-Missmatch for variable " + key
245 List list = ((List)existing);
246 list.addAll((List) value);
247 LOG.info("appending contents of variable to list {}", key);
248 handler.setLocalVariable(key, list);
253 "variable {} is of unexpected type {}", key, value.getClass()
255 throw new RuntimeException(
256 "Found variable of unexpected type: " + key
262 LOG.info("adding new variable {}", key);
263 handler.setLocalVariable(key, value);
270 Entry<String, Object> variable = it.next();
271 String key = variable.getKey();
272 Object value = variable.getValue();
273 LOG.info("adding variable {}", key);
274 variables.put(key, value);
275 handler.setLocalVariable(key, value);
278 catch (IllegalArgumentException e)
280 LOG.error("cannot parse {} as JSON: {}", location, e.getMessage());
281 throw new RuntimeException(e);
284 handler.removeAttribute(name);
288 Map<String, Object> getVariables(ITemplateContext context)
290 Map<String, Object> variables = new HashMap<>();