X-Git-Url: https://juplo.de/gitweb/?p=juplo-dialect;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fde%2Fjuplo%2Fthymeleaf%2FImportVariablesAttrProcessor.java;h=e864ab17bdb00e6628d7904ccf2add16ba4eaa68;hp=f679591942b3310a9d0dd09199392e7e36ab8488;hb=9df75bd83c2fd73df2aefdbb796424caccac6d4d;hpb=5059ccf31513c67ef6fce671c3385888b92c4a86 diff --git a/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java b/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java index f679591..e864ab1 100644 --- a/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java +++ b/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java @@ -5,9 +5,14 @@ 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; @@ -16,6 +21,7 @@ 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.processor.ProcessorResult; import org.thymeleaf.processor.attr.AbstractAttrProcessor; import org.thymeleaf.resourceresolver.IResourceResolver; @@ -31,11 +37,18 @@ import org.thymeleaf.templateresolver.TemplateResolution; */ public class ImportVariablesAttrProcessor extends AbstractAttrProcessor { - public static final int ATTR_PRECEDENCE = 200; - 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() @@ -52,73 +65,225 @@ public class ImportVariablesAttrProcessor extends AbstractAttrProcessor ) { Configuration config = arguments.getConfiguration(); - String templateName = element.getAttributeValue(name); + String parameter = element.getAttributeValue(name); - TemplateProcessingParameters params = - new TemplateProcessingParameters( - config, - templateName, - new IContext() // << We will not execute the template, hence we need no context - { - @Override - public VariablesMap getVariables() - { - return new VariablesMap<>(); - } + Iterator> it = null; - @Override - public Locale getLocale() - { - return Locale.getDefault(); - } + Matcher matcher = PATTERN.matcher(parameter); + boolean merge = false; + String json = null; + String resource = parameter; - @Override - public void addContextExecutionInfo(String templateName) - { - } - }); - - for (ITemplateResolver t_resolver : config.getTemplateResolvers()) + if (matcher.matches()) { - 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; + 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 { - Iterator> it = - SimpleMapper.getObjectIterator(FACTORY.createParser(is)); - while(it.hasNext()) - { - Entry entry = it.next(); - element.setNodeLocalVariable(entry.getKey(), entry.getValue()); - } + it = SimpleMapper.getObjectIterator(FACTORY.createParser(json)); } catch (IOException e) { - LOG.error("cannot retreive {} as JSON: {}", templateName, e.getMessage()); + LOG.error("cannot parse parameter as JSON: {}", json, e.getMessage()); throw new RuntimeException(e); } - catch (IllegalArgumentException 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 getVariables() + { + return new VariablesMap<>(); + } + + @Override + public Locale getLocale() + { + return Locale.getDefault(); + } + + @Override + public void addContextExecutionInfo(String templateName) + { + } + }); + + for (ITemplateResolver t_resolver : config.getTemplateResolvers()) { - LOG.error("cannot parse {} as JSON: {}", templateName, e.getMessage()); - throw new RuntimeException(e); + 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 variables = getVariables(element); + if (merge) + { + while(it.hasNext()) + { + Entry 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 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 getVariables(Node node) + { + Node parent = node; + do + { + Map variables = + (Map)parent.getNodeProperty(PROPERTY_NAME); + + if (variables != null) + return variables; + + parent = parent.getParent(); + } + while (parent != null); + + Map variables = new HashMap<>(); + node.setNodeProperty(PROPERTY_NAME, variables); + return variables; + } + + @Override public int getPrecedence() {