package org.jboss.seam.core; import static org.jboss.seam.ScopeType.STATELESS; import static org.jboss.seam.annotations.Install.BUILT_IN; import java.text.MessageFormat; import java.util.StringTokenizer; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.contexts.Contexts; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; /** * Interpolates EL expressions in Strings * * @author Gavin King */ @BypassInterceptors @Scope(STATELESS) @Name("org.jboss.seam.core.interpolator") @Install(precedence = BUILT_IN) public class Interpolator { private static final LogProvider log = Logging.getLogProvider(Interpolator.class); public static Interpolator instance() { if (Contexts.isApplicationContextActive()) { return (Interpolator) Component.getInstance(Interpolator.class, ScopeType.APPLICATION); } else { return new Interpolator(); // for unit testing } } /** * Replace all EL expressions in the form #{...} with their evaluated values. * * @param string * a template * @return the interpolated string */ public String interpolate(String string, Object... params) { if (params == null) { params = new Object[0]; } if (params.length > 10) { throw new IllegalArgumentException("more than 10 parameters"); } if (string.indexOf('#') >= 0 || string.indexOf('{') >= 0) { string = interpolateExpressions(string, params); } return string; } private String interpolateExpressions(String string, Object... params) { StringTokenizer tokens = new StringTokenizer(string, "#{}", true); StringBuilder builder = new StringBuilder(string.length()); while (tokens.hasMoreTokens()) { String tok = tokens.nextToken(); if ("#".equals(tok) && tokens.hasMoreTokens()) { String nextTok = tokens.nextToken(); while (nextTok.equals("#") && tokens.hasMoreTokens()) { builder.append(tok); nextTok = tokens.nextToken(); } if ("{".equals(nextTok)) { String expression = "#{" + tokens.nextToken() + "}"; try { Object value = Expressions.instance().createValueExpression(expression).getValue(); if (value != null) builder.append(value); } catch (Exception e) { log.debug("exception interpolating string: " + string, e); } tokens.nextToken(); // the trailing "}" } else if (nextTok.equals("#")) { // could be trailing # builder.append("#"); } else { int index; try { index = Integer.parseInt(nextTok.substring(0, 1)); if (index >= params.length) { // log.warn("parameter index out of bounds: " + index + // " in: " + string); builder.append("#").append(nextTok); } else { builder.append(params[index]).append(nextTok.substring(1)); } } catch (NumberFormatException nfe) { builder.append("#").append(nextTok); } } } else if ("{".equals(tok)) { StringBuilder expr = new StringBuilder(); expr.append(tok); int level = 1; while (tokens.hasMoreTokens()) { String nextTok = tokens.nextToken(); expr.append(nextTok); if (nextTok.equals("{")) { ++level; } else if (nextTok.equals("}")) { if (--level == 0) { try { if (params.length == 0) { builder.append(expr.toString()); } else { String value = new MessageFormat(expr.toString(), Locale.instance()).format(params); builder.append(value); } } catch (Exception e) { // if it is a bad message, use the expression itself builder.append(expr); } expr = null; break; } } } if (expr != null) { builder.append(expr); } } else { builder.append(tok); } } return builder.toString(); } }