org.mule.util.TemplateParser Maven / Gradle / Ivy
/*
* $Id: TemplateParser.java 23329 2011-11-04 17:41:07Z dirk.olmes $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
*
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* TemplateParser
is a simple string parser that will substitute
* tokens in a string with values supplied in a Map.
*/
public final class TemplateParser
{
public static final String ANT_TEMPLATE_STYLE = "ant";
public static final String SQUARE_TEMPLATE_STYLE = "square";
public static final String CURLY_TEMPLATE_STYLE = "curly";
public static final String WIGGLY_MULE_TEMPLATE_STYLE = "mule";
private static final String DOLLAR_ESCAPE = "@@@";
private static final Map patterns = new HashMap();
static
{
patterns.put(ANT_TEMPLATE_STYLE, new PatternInfo(ANT_TEMPLATE_STYLE, "\\$\\{[^\\}]+\\}", "${", "}"));
patterns.put(SQUARE_TEMPLATE_STYLE, new PatternInfo(SQUARE_TEMPLATE_STYLE, "\\[[^\\]]+\\]", "[", "]"));
patterns.put(CURLY_TEMPLATE_STYLE, new PatternInfo(CURLY_TEMPLATE_STYLE, "\\{[^\\}]+\\}", "{", "}"));
// Such a complex regex is needed to support nested expressions, otherwise we
// have to do this manually or using an ANTLR grammar etc.
// Support for 3 levels (2 nested)
patterns.put(WIGGLY_MULE_TEMPLATE_STYLE, new PatternInfo(WIGGLY_MULE_TEMPLATE_STYLE,
"#\\[((?:#\\[(?:#\\[.*?\\]|\\[.*?\\]|.)*?\\]|\\[.*?\\]|.)*?)\\]", "#[", "]"));
// Support for 2 levels (1 nested)
// "#\\[((?:#\\[.*?\\]|\\[.*?\\]|.)*?)\\]"
}
/**
* logger used by this class
*/
protected static final Log logger = LogFactory.getLog(TemplateParser.class);
public static final Pattern ANT_TEMPLATE_PATTERN = patterns.get(ANT_TEMPLATE_STYLE).getPattern();
public static final Pattern SQUARE_TEMPLATE_PATTERN = patterns.get(SQUARE_TEMPLATE_STYLE).getPattern();
public static final Pattern CURLY_TEMPLATE_PATTERN = patterns.get(CURLY_TEMPLATE_STYLE).getPattern();
public static final Pattern WIGGLY_MULE_TEMPLATE_PATTERN = patterns.get(WIGGLY_MULE_TEMPLATE_STYLE).getPattern();
private final Pattern pattern;
private final int pre;
private final int post;
private final PatternInfo style;
public static TemplateParser createAntStyleParser()
{
return new TemplateParser(ANT_TEMPLATE_STYLE);
}
public static TemplateParser createSquareBracesStyleParser()
{
return new TemplateParser(SQUARE_TEMPLATE_STYLE);
}
public static TemplateParser createCurlyBracesStyleParser()
{
return new TemplateParser(CURLY_TEMPLATE_STYLE);
}
public static TemplateParser createMuleStyleParser()
{
return new TemplateParser(WIGGLY_MULE_TEMPLATE_STYLE);
}
private TemplateParser(String styleName)
{
this.style = patterns.get(styleName);
if (this.style == null)
{
throw new IllegalArgumentException("Unknown template style: " + styleName);
}
pattern = style.getPattern();
pre = style.getPrefix().length();
post = style.getSuffix().length();
}
/**
* Matches one or more templates against a Map of key value pairs. If a value for
* a template is not found in the map the template is left as is in the return
* String
*
* @param props the key/value pairs to match against
* @param template the string containing the template place holders i.e. My name
* is ${name}
* @return the parsed String
*/
public String parse(Map, ?> props, String template)
{
return parse(props, template, null);
}
/**
* Matches one or more templates against a Map of key value pairs. If a value for
* a template is not found in the map the template is left as is in the return
* String
*
* @param callback a callback used to resolve the property name
* @param template the string containing the template place holders i.e. My name
* is ${name}
* @return the parsed String
*/
public String parse(TemplateCallback callback, String template)
{
return parse(null, template, callback);
}
protected String parse(Map, ?> props, String template, TemplateCallback callback)
{
String result = template;
Map, ?> newProps = props;
if (props != null && !(props instanceof CaseInsensitiveHashMap))
{
newProps = new CaseInsensitiveHashMap(props);
}
Matcher m = pattern.matcher(result);
while (m.find())
{
Object value = null;
String match = m.group();
String propname = match.substring(pre, match.length() - post);
if (callback != null)
{
value = callback.match(propname);
}
else if (newProps != null)
{
value = newProps.get(propname);
}
if (value == null)
{
if (logger.isDebugEnabled())
{
logger.debug("Value " + propname + " not found in context");
}
}
else
{
String matchRegex = escape(match);
String valueString = value.toString();
//need to escape $ as they resolve into group references, escaping them was not enough
//This smells a bit like a hack, but one way or another these characters need to be escaped
if (valueString.indexOf('$') != -1)
{
valueString = valueString.replaceAll("\\$", DOLLAR_ESCAPE);
}
if (valueString.indexOf('\\') != -1)
{
valueString = valueString.replaceAll("\\\\", "\\\\\\\\");
}
result = result.replaceAll(matchRegex, valueString);
}
}
if (result.indexOf(DOLLAR_ESCAPE) != -1)
{
result = result.replaceAll(DOLLAR_ESCAPE, "\\$");
}
return result;
}
/**
* Matches one or more templates against a Map of key value pairs. If a value for
* a template is not found in the map the template is left as is in the return
* String
*
* @param props the key/value pairs to match against
* @param templates A List of templates
* @return the parsed String
*/
public List> parse(Map, ?> props, List> templates)
{
if (templates == null)
{
return new ArrayList
© 2015 - 2024 Weber Informatics LLC | Privacy Policy