+++ /dev/null
-package de.juplo.thymeleaf;
-
-
-import com.fasterxml.jackson.core.JsonFactory;
-import de.juplo.jackson.SimpleMapper;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.thymeleaf.Arguments;
-import org.thymeleaf.Configuration;
-import org.thymeleaf.TemplateProcessingParameters;
-import org.thymeleaf.context.IContext;
-import org.thymeleaf.context.VariablesMap;
-import org.thymeleaf.dom.Element;
-import org.thymeleaf.dom.Node;
-import org.thymeleaf.exceptions.TemplateProcessingException;
-import org.thymeleaf.processor.ProcessorResult;
-import org.thymeleaf.processor.attr.AbstractAttrProcessor;
-import org.thymeleaf.resourceresolver.IResourceResolver;
-import org.thymeleaf.standard.expression.IStandardExpression;
-import org.thymeleaf.standard.expression.IStandardExpressionParser;
-import org.thymeleaf.standard.expression.StandardExpressions;
-import org.thymeleaf.templateresolver.ITemplateResolver;
-import org.thymeleaf.templateresolver.TemplateResolution;
-
-
-
-/**
- * Retrievs and parses JSON-data and imports the parsed variables as node-local
- * variables.
- * @author Kai Moritz
- */
-public class ImportVariablesAttrProcessor extends AbstractAttrProcessor
-{
- private static final Logger LOG =
- LoggerFactory.getLogger(ImportVariablesAttrProcessor.class);
- private static final JsonFactory FACTORY = new JsonFactory();
- private static final String PROPERTY_NAME =
- ImportVariablesAttrProcessor.class.getCanonicalName() + "_VARIABLES";
-
- public static final Pattern PATTERN =
- Pattern.compile(
- "^\\s*(?:(?:(merge)|replace):)?\\s*(?:(\\{.*\\})|(.*))\\s*$",
- Pattern.DOTALL | Pattern.CASE_INSENSITIVE
- );
- public static final int ATTR_PRECEDENCE = 200;
-
-
- public ImportVariablesAttrProcessor()
- {
- super("variables");
- }
-
-
- @Override
- public final ProcessorResult processAttribute(
- final Arguments arguments,
- final Element element,
- final String name
- )
- {
- Configuration config = arguments.getConfiguration();
-
- Configuration configuration = arguments.getConfiguration();
-
- String parameter = element.getAttributeValue(name);
- try
- {
- IStandardExpressionParser parser =
- StandardExpressions.getExpressionParser(configuration);
- IStandardExpression expression =
- parser.parseExpression(configuration, arguments, parameter);
- parameter = (String)expression.execute(configuration, arguments);
- }
- catch (TemplateProcessingException e) { }
-
- if (parameter != null && !parameter.trim().isEmpty())
- {
- LOG.info("ignoring empty parameter");
- return ProcessorResult.OK;
- }
-
- Iterator<Entry<String, Object>> it = null;
-
- Matcher matcher = PATTERN.matcher(parameter);
- boolean merge = false;
- String json = null;
- String resource = parameter;
-
- if (matcher.matches())
- {
- merge = matcher.group(1) != null;
- json = matcher.group(2);
- resource = matcher.group(3);
- }
-
- if (json != null)
- {
- LOG.info("parsing parameter as JSON");
- LOG.debug("parameter: {}", json);
- try
- {
- it = SimpleMapper.getObjectIterator(FACTORY.createParser(json));
- }
- catch (IOException e)
- {
- LOG.error("cannot parse parameter as JSON: {}", json, e.getMessage());
- throw new RuntimeException(e);
- }
- }
- else
- {
- LOG.info("retriving {} as JSON-template", resource);
- TemplateProcessingParameters params =
- new TemplateProcessingParameters(
- config,
- resource,
- new IContext() // << We will not execute the template, hence we need no context
- {
- @Override
- public VariablesMap<String, Object> getVariables()
- {
- return new VariablesMap<>();
- }
-
- @Override
- public Locale getLocale()
- {
- return Locale.getDefault();
- }
-
- @Override
- public void addContextExecutionInfo(String templateName)
- {
- }
- });
-
- for (ITemplateResolver t_resolver : config.getTemplateResolvers())
- {
- TemplateResolution resolution = t_resolver.resolveTemplate(params);
- if (resolution == null)
- continue;
- if (!"JSON".equals(resolution.getTemplateMode()))
- continue;
- IResourceResolver r_resolver = resolution.getResourceResolver();
- InputStream is =
- r_resolver.getResourceAsStream(params, resolution.getResourceName());
- if (is == null)
- continue;
-
- try
- {
- it = SimpleMapper.getObjectIterator(FACTORY.createParser(is));
- break;
- }
- catch (IOException | IllegalArgumentException e)
- {
- LOG.error("cannot retreive {} as JSON: {}", parameter, e.getMessage());
- throw new RuntimeException(e);
- }
- }
-
- if (it == null)
- {
- LOG.error("cannot resolve {} as JSON (not found)!", parameter);
- throw new RuntimeException("Template not found: " + parameter);
- }
- }
-
- try
- {
- Map<String, Object> variables = getVariables(element);
- if (merge)
- {
- while(it.hasNext())
- {
- Entry<String, Object> variable = it.next();
- String key = variable.getKey();
- Object value = variable.getValue();
- Object existing = variables.get(key);
- if (existing != null)
- {
- if (value instanceof String)
- {
- if (!(existing instanceof String))
- {
- LOG.error(
- "cannot merge variable {} of type {} with a string",
- key,
- existing.getClass()
- );
- throw new RuntimeException(
- "Type-Missmatch for variable " + key
- );
- }
-
- String string = ((String)existing).concat((String) value);
- LOG.info("appending variable to string {}", key);
- element.setNodeLocalVariable(key, string);
- }
- else if (value instanceof Map)
- {
- if (!(existing instanceof Map))
- {
- LOG.error(
- "cannot merge variable {} of type {} with a map",
- key,
- existing.getClass()
- );
- throw new RuntimeException(
- "Type-Missmatch for variable " + key
- );
- }
-
- Map map = ((Map)existing);
- map.putAll((Map) value);
- LOG.info("merging variable with map {}", key);
- element.setNodeLocalVariable(key, map);
- }
- else if (value instanceof List)
- {
- if (!(existing instanceof List))
- {
- LOG.error(
- "cannot merge variable {} of type {} with a list",
- key,
- existing.getClass()
- );
- throw new RuntimeException(
- "Type-Missmatch for variable " + key
- );
- }
-
- List list = ((List)existing);
- list.addAll((List) value);
- LOG.info("appending contents of variable to list {}", key);
- element.setNodeLocalVariable(key, list);
- }
- else
- {
- LOG.error(
- "variable {} is of unexpected type {}", key, value.getClass()
- );
- throw new RuntimeException(
- "Found variable of unexpected type: " + key
- );
- }
- }
- else
- {
- LOG.info("adding new variable {}", key);
- element.setNodeLocalVariable(key, value);
- }
- }
- }
- else
- while(it.hasNext())
- {
- Entry<String, Object> variable = it.next();
- String key = variable.getKey();
- Object value = variable.getValue();
- LOG.info("adding variable {}", key);
- variables.put(key, value);
- element.setNodeLocalVariable(key, value);
- }
- }
- catch (IllegalArgumentException e)
- {
- LOG.error("cannot parse {} as JSON: {}", parameter, e.getMessage());
- throw new RuntimeException(e);
- }
-
- element.removeAttribute(name);
-
- return ProcessorResult.OK;
- }
-
-
- Map<String, Object> getVariables(Node node)
- {
- Node parent = node;
- do
- {
- Map<String, Object> variables =
- (Map<String, Object>)parent.getNodeProperty(PROPERTY_NAME);
-
- if (variables != null)
- return variables;
-
- parent = parent.getParent();
- }
- while (parent != null);
-
- Map<String, Object> variables = new HashMap<>();
- node.setNodeProperty(PROPERTY_NAME, variables);
- return variables;
- }
-
-
- @Override
- public int getPrecedence()
- {
- return ATTR_PRECEDENCE;
- }
-}