/**
* Copyright 2012 Universitat Pompeu Fabra.
*
* Licensed 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.onexus.resource.api.utils.string;
import java.io.Serializable;
/**
* Original code extract from Apache Wicket core
*/
public abstract class VariableInterpolator implements Serializable {
/**
* The <code>String</code> to interpolate into
*/
private 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 (string == null) {
return null;
}
// 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();
}
}