/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.wicket.util.string.interpolator; import org.apache.wicket.util.io.IClusterable; /** * Base class for variable interpolators. An interpolator substitutes values into a * <code>String</code>. So, a variable interpolator substitutes the values of one or more variables * into a <code>String</code>. * <p> * The <code>String</code> to interpolate (substitute into) is passed to the * <code>VariableInterpolator</code>'s constructor. Variables are denoted in this string by the * syntax <code>${variableName}</code>. A subclass provides an implementation for the abstract * method <code>getValue(String variableName)</code>. The <code>toString()</code> method then * performs an interpolation by replacing each variable of the form <code>${variableName}</code> * with the value returned by <code>getValue("variableName")</code>. * <p> * "$" is the escape char. Thus "$${text}" can be used to escape it (ignore interpretation). If * '$3.24' is needed then '$$${amount}' should be used. The first $ sign escapes the second, and the * third is used to interpolate the variable. * * @author Jonathan Locke * @since 1.2.6 */ @SuppressWarnings("serial") public abstract class VariableInterpolator implements IClusterable { /** The <code>String</code> to interpolate into */ protected final String string; private final boolean exceptionOnNullVarValue; /** * Constructor. * * @param string * a <code>String</code> to interpolate with variable values */ public VariableInterpolator(final String string) { this(string, false); } /** * Constructor. * * @param string * a <code>String</code> to interpolate with variable values * @param exceptionOnNullVarValue * if <code>true</code> an {@link IllegalStateException} will be thrown if * {@link #getValue(String)} returns <code>null</code>, otherwise the * <code>${varname}</code> string will be left in the <code>String</code> so that * multiple interpolators can be chained */ public VariableInterpolator(final String string, final boolean exceptionOnNullVarValue) { this.string = string; this.exceptionOnNullVarValue = exceptionOnNullVarValue; } /** * Retrieves a value for a variable name during interpolation. * * @param variableName * a variable name * @return the value */ protected abstract String getValue(String variableName); private int lowerPositive(final int i1, final int i2) { if (i2 < 0) { return i1; } else if (i1 < 0) { return i2; } else { return i1 < i2 ? i1 : i2; } } /** * Interpolates using variables. * * @return the interpolated <code>String</code> */ @Override public String toString() { // If there's any reason to go to the expense of property expressions if (!string.contains("${")) { return string; } // Result buffer final StringBuilder buffer = new StringBuilder(); // For each occurrences of "${"or "$$" int start; int pos = 0; while ((start = lowerPositive(string.indexOf("$$", pos), string.indexOf("${", pos))) != -1) { // Append text before possible variable buffer.append(string.substring(pos, start)); if (string.charAt(start + 1) == '$') { buffer.append("$"); pos = start + 2; continue; } // Position is now where we found the "${" pos = start; // Get start and end of variable name final int startVariableName = start + 2; final int endVariableName = string.indexOf('}', startVariableName); // Found a close brace? if (endVariableName != -1) { // Get variable name inside brackets final String variableName = string.substring(startVariableName, endVariableName); // Get value of variable final String value = getValue(variableName); // If there's no value if (value == null) { if (exceptionOnNullVarValue) { throw new IllegalArgumentException("Value of variable [[" + variableName + "]] could not be resolved while interpolating [[" + string + "]]"); } else { // Leave variable uninterpolated, allowing multiple // interpolators to // do their work on the same string buffer.append("${").append(variableName).append("}"); } } else { // Append variable value buffer.append(value); } // Move past variable pos = endVariableName + 1; } else { break; } } // Append anything that might be left if (pos < string.length()) { buffer.append(string.substring(pos)); } // Convert result to String return buffer.toString(); } }