Commit d61fd27c authored by Nico Mack's avatar Nico Mack

Preparation to merge dev-nico branch into master

Adaptations to ensure scenario project won't break while doing so
Implemented Interpolation framework
parent 2b7a81bd
......@@ -13,7 +13,7 @@
*/
package lu.list.itis.dkd.tui.bootstrapping;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.cps.utility.EquationSystemBundle;
import lu.list.itis.dkd.tui.cps.variable.BooleanVariable;
import lu.list.itis.dkd.tui.cps.variable.NumericalVariable;
import lu.list.itis.dkd.tui.cps.variable.TextVariable;
......@@ -33,15 +33,15 @@ public class VariableBootstrapper {
if (variableNode == null)
return null;
String name = BootstrappingUtils.getContentAsString(variableNode, Externalization.NAME_ATTRIBUTE, BootstrappingUtils.MANDATORY, null, context);
String type = BootstrappingUtils.getContentAsString(variableNode, Externalization.TYPE_NODE, BootstrappingUtils.MANDATORY, null, context);
String name = BootstrappingUtils.getContentAsString(variableNode, EquationSystemBundle.NAME_ATTRIBUTE, BootstrappingUtils.MANDATORY, null, context);
String type = BootstrappingUtils.getContentAsString(variableNode, EquationSystemBundle.TYPE_NODE, BootstrappingUtils.MANDATORY, null, context);
switch (type) {
case Externalization.NUMERIC_TYPE:
String unit = BootstrappingUtils.getContentAsString(variableNode, Externalization.UNIT_ATTRIBUTE, BootstrappingUtils.OPTIONAL, Externalization.EMPTY_STRING, context);
double minValue = BootstrappingUtils.getContentAsDouble(variableNode, Externalization.MINIMUM_ATTRIBUTE, BootstrappingUtils.OPTIONAL, -Double.MAX_VALUE, context);
double maxValue = BootstrappingUtils.getContentAsDouble(variableNode, Externalization.MAXIMUM_ATTRIBUTE, BootstrappingUtils.OPTIONAL, Double.MAX_VALUE, context);
double scale = BootstrappingUtils.getContentAsDouble(variableNode, Externalization.SCALE_ATTRIBUTE, BootstrappingUtils.OPTIONAL, 1.0, context);
double numericValue = BootstrappingUtils.getContentAsDouble(variableNode, Externalization.INITIAL_ATTRIBUTE, BootstrappingUtils.OPTIONAL, 0.0, context);
case EquationSystemBundle.NUMERIC_TYPE:
String unit = BootstrappingUtils.getContentAsString(variableNode, EquationSystemBundle.UNIT_ATTRIBUTE, BootstrappingUtils.OPTIONAL, EquationSystemBundle.EMPTY_STRING, context);
double minValue = BootstrappingUtils.getContentAsDouble(variableNode, EquationSystemBundle.MINIMUM_ATTRIBUTE, BootstrappingUtils.OPTIONAL, -Double.MAX_VALUE, context);
double maxValue = BootstrappingUtils.getContentAsDouble(variableNode, EquationSystemBundle.MAXIMUM_ATTRIBUTE, BootstrappingUtils.OPTIONAL, Double.MAX_VALUE, context);
double scale = BootstrappingUtils.getContentAsDouble(variableNode, EquationSystemBundle.SCALE_ATTRIBUTE, BootstrappingUtils.OPTIONAL, 1.0, context);
double numericValue = BootstrappingUtils.getContentAsDouble(variableNode, EquationSystemBundle.INITIAL_ATTRIBUTE, BootstrappingUtils.OPTIONAL, 0.0, context);
NumericalVariable numerical = new NumericalVariable(name, unit, numericValue);
numerical.setMinValue(minValue);
......@@ -49,15 +49,15 @@ public class VariableBootstrapper {
numerical.setScale(scale);
variable = numerical;
break;
case Externalization.LOGIC_TYPE:
boolean booleanValue = BootstrappingUtils.getContentAsBoolean(variableNode, Externalization.INITIAL_ATTRIBUTE, BootstrappingUtils.OPTIONAL, false, context);
case EquationSystemBundle.LOGIC_TYPE:
boolean booleanValue = BootstrappingUtils.getContentAsBoolean(variableNode, EquationSystemBundle.INITIAL_ATTRIBUTE, BootstrappingUtils.OPTIONAL, false, context);
BooleanVariable booleanVariable = new BooleanVariable(name, booleanValue);
variable = booleanVariable;
break;
case Externalization.TEXT_TYPE:
String textValue = BootstrappingUtils.getContentAsString(variableNode, Externalization.INITIAL_ATTRIBUTE, BootstrappingUtils.OPTIONAL, Externalization.EMPTY_STRING, context);
case EquationSystemBundle.TEXT_TYPE:
String textValue = BootstrappingUtils.getContentAsString(variableNode, EquationSystemBundle.INITIAL_ATTRIBUTE, BootstrappingUtils.OPTIONAL, EquationSystemBundle.EMPTY_STRING, context);
TextVariable textVariable = new TextVariable(name, textValue);
variable = textVariable;
break;
......
......@@ -28,8 +28,8 @@ import org.eclipse.osgi.util.NLS;
* @version 1.3.0
*/
@SuppressWarnings({"javadoc", "nls"})
public class Externalization extends NLS {
private static final String BUNDLE_NAME = "lu.list.itis.dkd.tui.cps.utility.externalization";
public class EquationSystemBundle extends NLS {
private static final String BUNDLE_NAME = "lu.list.itis.dkd.tui.cps.utility.equationsystem";
public static String EXECUTOR_NAMESPACE;
public static String NAMESPACE_SEPARATOR;
......@@ -54,6 +54,7 @@ public class Externalization extends NLS {
public static String PARAMETERS_ELEMENT;
public static String PERIODIC_ATTRIBUTE;
public static String RESULT_ELEMENT;
public static String EPSILON_ATTRIBUTE;
public static String EQUATE_ATTRIBUTE;
public static String RESULTS_ELEMENT;
public static String IMPORT_ELEMENT;
......@@ -82,8 +83,8 @@ public class Externalization extends NLS {
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Externalization.class);
NLS.initializeMessages(BUNDLE_NAME, EquationSystemBundle.class);
}
private Externalization() {}
private EquationSystemBundle() {}
}
......@@ -13,6 +13,7 @@ EQUATIONS_ELEMENT=equations
EQUATION_ELEMENT=equation
MODE_ATTRIBUTE=mode
INVOKE_ELEMENT=invoke
EPSILON_ATTRIBUTE=epsilon
EXECUTOR_ATTRIBUTE=executor
NAME_ATTRIBUTE=name
OUTPUTS_ELEMENT=outputs
......
......@@ -20,7 +20,7 @@
*/
package lu.list.itis.dkd.tui.cps.variable;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.cps.utility.EquationSystemBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -41,7 +41,7 @@ public class BooleanVariable extends Variable<Boolean> {
private static final Logger LOGGER = LoggerFactory.getLogger(BooleanVariable.class.getSimpleName());
public BooleanVariable(String name, boolean value) {
super(Externalization.LOGIC_TYPE, name, "boolean"); //$NON-NLS-1$
super(EquationSystemBundle.LOGIC_TYPE, name, "boolean"); //$NON-NLS-1$
this.value = value;
}
......
......@@ -22,7 +22,8 @@ package lu.list.itis.dkd.tui.cps.variable;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.utility.EquationSystemBundle;
import com.google.common.base.Objects;
......@@ -52,6 +53,7 @@ public class NumericalVariable extends Variable<Double> {
protected double valueRange;
protected double normalizedValue;
protected double epsilon;
private DecimalFormat format;
......@@ -59,7 +61,7 @@ public class NumericalVariable extends Variable<Double> {
// * Constants *
// ***************************************************************************
public static final double EPSILON = 0.00001;
public static final double DEFAULT_EPSILON = 1e-6;
private static final Logger LOGGER = LoggerFactory.getLogger(NumericalVariable.class.getSimpleName());
......@@ -82,7 +84,7 @@ public class NumericalVariable extends Variable<Double> {
// ---------------------------------------------------------------------------
public NumericalVariable(String name, String unit, Double value) {
super(Externalization.NUMERIC_TYPE, name, unit);
super(EquationSystemBundle.NUMERIC_TYPE, name, unit);
this.value = value;
format = new DecimalFormat();
......@@ -93,6 +95,7 @@ public class NumericalVariable extends Variable<Double> {
minValue = -Double.MAX_VALUE;
maxValue = Double.MAX_VALUE;
valueRange = getValueRange(minValue, maxValue);
epsilon = DEFAULT_EPSILON;
scale = 1;
}
......@@ -170,8 +173,8 @@ public class NumericalVariable extends Variable<Double> {
// ***************************************************************************
// ---------------------------------------------------------------------------
public static boolean isEqual(double firstValue, double secondValue) {
return (Math.abs(firstValue - secondValue) < EPSILON);
public static boolean isEqual(double firstValue, double secondValue, double epsilon) {
return (Math.abs(firstValue - secondValue) < epsilon);
}
// ---------------------------------------------------------------------------
......@@ -257,7 +260,12 @@ public class NumericalVariable extends Variable<Double> {
double val = (newValue != null) ? newValue + 0.0d : 0d; // Avoid -0.0 values
this.normalizedValue = this.normalizeValue(val);
super.setValue(val);
this.modified = ((newValue != null) && (!isEqual(newValue, this.value, this.epsilon)));
this.value = newValue;
if (this.modified) {
this.notifyInputChangeListeners(new InputEvent(this));
}
}
// ---------------------------------------------------------------------------
......@@ -320,6 +328,30 @@ public class NumericalVariable extends Variable<Double> {
}
// ---------------------------------------------------------------------------
/**
* Specifies the smallest difference between a given number and the next different number.
*
* @param value
* specifies the smallest acceptable difference between subsequent values.
*/
// ---------------------------------------------------------------------------
public void setEpsilon(double value) {
this.epsilon = value;
}
// ---------------------------------------------------------------------------
/**
*
* @return the smallest difference between a given number and the next different number.
*/
// ---------------------------------------------------------------------------
public double getEpsilon() {
return this.epsilon;
}
// ---------------------------------------------------------------------------
public double getValueRange() {
......
......@@ -15,7 +15,7 @@ package lu.list.itis.dkd.tui.cps.variable;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.utility.ExecutorScope;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.cps.utility.EquationSystemBundle;
import lu.list.itis.dkd.tui.utility.Point;
import org.slf4j.Logger;
......@@ -42,7 +42,7 @@ public class SpatialVariable extends Variable<Point> {
* @param unit
*/
public SpatialVariable(String name, String unit, Point value) {
super(Externalization.SPATIAL_TYPE, name, unit);
super(EquationSystemBundle.SPATIAL_TYPE, name, unit);
this.value = value;
}
......
......@@ -22,7 +22,7 @@ package lu.list.itis.dkd.tui.cps.variable;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.cps.utility.EquationSystemBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -54,7 +54,7 @@ public class TextVariable extends Variable<String> {
* The value held by the variable.
*/
public TextVariable(String name, String value) {
super(Externalization.TEXT_TYPE, name, Externalization.EMPTY_STRING);
super(EquationSystemBundle.TEXT_TYPE, name, EquationSystemBundle.EMPTY_STRING);
this.value = value;
}
......
......@@ -14,7 +14,7 @@
package lu.list.itis.dkd.tui.cps.variable;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.cps.utility.EquationSystemBundle;
import java.util.ArrayList;
import java.util.Collection;
......@@ -46,7 +46,7 @@ public class VectorVariable<B> extends Variable<List<B>> implements Collection<B
// ---------------------------------------------------------------------------
public VectorVariable(String name, String unit) {
super(Externalization.VECTOR_TYPE, name, unit);
super(EquationSystemBundle.VECTOR_TYPE, name, unit);
value = new ArrayList<B>();
}
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.utility.interpolation;
/**
* Chunks are the base class for interpolation activities. It represents a piece of a format string
* which may be broken down into; static text, format qualifier, variable names, etc to name only a
* few. The actual interpolation process will consist in breaking down the format string into a list
* of chunks.
*
* @author Nico Mack [nico.mack@list.lu]
* @since 1.5
* @version 1.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public abstract class Chunk<C> extends Object {
protected C content;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
public Chunk(C content) {
this.content = content;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Returns the content embodied by this chunk.
*
* @return the content embodied by this chunk
*/
// ---------------------------------------------------------------------------
public C getContent() {
return this.content;
}
// ---------------------------------------------------------------------------
/**
* Renderes the content embodied by this chunk
*
* @return a rendering of this chunks' content if previously defined, <code>null</code>
* otherwise
*/
// ---------------------------------------------------------------------------
public String render() {
return (content != null) ? content.toString() : "null"; //$NON-NLS-1$
}
// ---------------------------------------------------------------------------
/**
* Returns the parsing pattern defined for this chunk if used for decoding
*
* @return a string representation of the regex pattern to be used to parse this chunks'
* content.
*/
// ---------------------------------------------------------------------------
public abstract String getPattern();
// ---------------------------------------------------------------------------
/**
* Asks this chunk to evaluate the specified substring.
*
* @param group
* specifies the substring to be evaluated by this chunk.
* @return <code>true</code> if specified substring has been consumed, <code>false</code>
* otherwise
*/
// ---------------------------------------------------------------------------
public boolean evaluate(String group) {
return false;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class
// ***************************************************************************
// ---------------------------------------------------------------------------
}
......@@ -11,31 +11,28 @@
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.utility;
package lu.list.itis.dkd.tui.utility.interpolation;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import com.jgoodies.common.base.Strings;
/**
* Represent a chunk peforming actual conversions of variable values.
*
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
* @since 1.5
* @version 1.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class Interpolator {
// ***************************************************************************
// * Constants *
// ***************************************************************************
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{([a-z0-9\\-_]+)(\\.(%[bhscxoegat\\+\\.0-9]+))?\\}", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
private static final Pattern INTEGER_FORMAT = Pattern.compile("\\%(\\d*(\\.\\d+)?)([xod])", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
public class Conversion extends Chunk<Variable<?>> {
private Object target;
private String format;
private String pattern;
// ---------------------------------------------------------------------------
// ***************************************************************************
......@@ -43,7 +40,9 @@ public class Interpolator {
// ***************************************************************************
// ---------------------------------------------------------------------------
private Interpolator() {}
public Conversion(Variable<?> content) {
super(content);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
......@@ -51,44 +50,64 @@ public class Interpolator {
// ***************************************************************************
// ---------------------------------------------------------------------------
public static String interpolate(String template, Map<String, Object> parameters) {
Matcher interpolator;
String format;
String variable;
int position = 0;
StringBuilder interpolated;
interpolator = VARIABLE_PATTERN.matcher(template);
interpolated = new StringBuilder();
while (interpolator.find()) {
interpolated.append(template.substring(position, interpolator.start()));
variable = interpolator.group(1);
format = (interpolator.groupCount() == 3) ? interpolator.group(3) : ""; //$NON-NLS-1$
if ((variable != null) && (!variable.isEmpty())) {
if (parameters.containsKey(variable)) {
if (!format.isEmpty()) {
if (INTEGER_FORMAT.matcher(format).matches()) {
Object value = parameters.get(variable);
if (value instanceof Number) {
interpolated.append(String.format(format, ((Number) value).intValue()));
}
} else {
interpolated.append(String.format(format, parameters.get(variable)));
}
} else {
interpolated.append(parameters.get(variable));
}
}
} else {
interpolated.append(interpolated.substring(interpolator.start(), interpolator.end()));
public void setTarget(Object target) {
this.target = target;
}
// ---------------------------------------------------------------------------
public void setFormat(String format) {
this.format = format;
}
// ---------------------------------------------------------------------------
public void setPattern(String regex) {
this.pattern = regex;
}
// ---------------------------------------------------------------------------
@Override
public String render() {
String rendered;
if (this.content == null)
return "";
Object value = this.content.getValue();
if (Strings.isNotBlank(this.format)) {
if (this.target instanceof Integer) {
value = ((Number) value).intValue();
}
position = interpolator.end();
rendered = String.format(this.format, value);
} else {
rendered = value.toString();
}
interpolated.append(template.substring(position));
return rendered;
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public String getPattern() {
return this.pattern;
}
return interpolated.toString();
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public boolean evaluate(String group) {
if (this.content != null) {
content.setValueFromObject(group);
return true;
}
return super.evaluate(group);
}
// ---------------------------------------------------------------------------
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.utility.interpolation;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.utility.StringUtils;
import com.jgoodies.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 1.5
* @version 1.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class Interpolator {
// ***************************************************************************
// * Constants *
// ***************************************************************************
private static final String PARENTHESIS_OPENED = "("; //$NON-NLS-1$
private static final String PARENTHESIS_CLOSED = ")"; //$NON-NLS-1$
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
private static final String INTEGER_STEM = "[ +\\-0-9]\\{{}\\}"; //$NON-NLS-1$
private static final String DECIMALS_STEM = "\\.[0-9]\\{{}\\}"; //$NON-NLS-1$
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{([a-z0-9\\-_]+)(\\.(%[bscxoefgt\\+\\.0-9]+))?\\}", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
private static final Pattern FORMAT_PATTERN = Pattern.compile("\\%((\\d*)(\\.(\\d+))?)([bscxoefgt])", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
private static HashMap<String, Object> targetLookup = new HashMap<>();
static {
targetLookup.put("d", Integer.valueOf(0)); //$NON-NLS-1$
targetLookup.put("x", Integer.valueOf(0)); //$NON-NLS-1$
targetLookup.put("o", Integer.valueOf(0)); //$NON-NLS-1$
targetLookup.put("f", Double.valueOf(0)); //$NON-NLS-1$
targetLookup.put("e", Double.valueOf(0)); //$NON-NLS-1$
targetLookup.put("g", Double.valueOf(0)); //$NON-NLS-1$
targetLookup.put("s", EMPTY_STRING); //$NON-NLS-1$
targetLookup.put("c", EMPTY_STRING); //$NON-NLS-1$
targetLookup.put("b", Boolean.valueOf(false)); //$NON-NLS-1$
}
private static final Logger LOGGER = LoggerFactory.getLogger(Interpolator.class.getSimpleName());
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
private Interpolator() {}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives
// ***************************************************************************
// ---------------------------------------------------------------------------
private static String getRegexPattern(Matcher formatMatcher) {
StringBuilder regex = new StringBuilder(PARENTHESIS_OPENED);
boolean hasDecimals = (Strings.isNotBlank(formatMatcher.group(3)) && Strings.isNotBlank(formatMatcher.group(4)));
if (hasDecimals) {
int width = StringUtils.getIntegerValue(formatMatcher.group(2));
int precision = StringUtils.getIntegerValue(formatMatcher.group(4));
regex.append(StringUtils.build(INTEGER_STEM, width - precision - 1));
regex.append(StringUtils.build(DECIMALS_STEM, precision));
} else {
int width = StringUtils.getIntegerValue(formatMatcher.group(2));
regex.append(StringUtils.build(INTEGER_STEM, width));
}
regex.append(PARENTHESIS_CLOSED);
return regex.toString();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
public static List<Chunk<?>> decompose(String template, Map<String, Variable<?>> parameters) {
Matcher variableMatcher;
String format;
String variable;
int position = 0;
List<Chunk<?>> chunks;
variableMatcher = VARIABLE_PATTERN.matcher(template);
chunks = new ArrayList<>();
while (variableMatcher.find()) {
String fromStart = template.substring(position, variableMatcher.start());
if (Strings.isNotBlank(fromStart)) {
chunks.add(new Static(fromStart));
}
variable = variableMatcher.group(1);
format = (variableMatcher.groupCount() == 3) ? variableMatcher.group(3) : EMPTY_STRING;
if ((variable != null) && (!variable.isEmpty())) {
if (parameters.containsKey(variable)) {
Conversion conversion = new Conversion(parameters.get(variable));
if (Strings.isNotBlank(format)) {
Matcher formatMatcher = FORMAT_PATTERN.matcher(format);
if (formatMatcher.matches()) {
conversion.setFormat(format);
conversion.setTarget(targetLookup.get(formatMatcher.group(5).toLowerCase()));
conversion.setPattern(getRegexPattern(formatMatcher));
}
}
chunks.add(conversion);
} else {
LOGGER.warn("Encountered reference to unknown variable {}!", variable); //$NON-NLS-1$
}
} else {
chunks.add(new Static(template.substring(variableMatcher.start(), variableMatcher.end())));
}
position = variableMatcher.end();
}
String untilEnd = template.substring(position);
if (Strings.isNotBlank(untilEnd)) {
chunks.add(new Static(untilEnd));
}
return chunks;
}
// ---------------------------------------------------------------------------
public static String render(List<Chunk<?>> chunks) {
StringBuilder builder = new StringBuilder();
for (Chunk<?> chunk : chunks) {
builder.append(chunk.render());