All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.configuration2.interpol.ExprLookup Maven / Gradle / Ivy

/*
 * 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.commons.configuration2.interpol;

import java.util.ArrayList;
import java.util.Objects;

import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
import org.apache.commons.configuration2.io.ConfigurationLogger;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;
import org.apache.commons.text.lookup.StringLookup;

/**
 * Lookup that allows expressions to be evaluated.
 *
 * 
 *     ExprLookup.Variables vars = new ExprLookup.Variables();
 *     vars.add(new ExprLookup.Variable("String", org.apache.commons.lang.StringUtils.class));
 *     vars.add(new ExprLookup.Variable("Util", new Utility("Hello")));
 *     vars.add(new ExprLookup.Variable("System", "Class:java.lang.System"));
 *     XMLConfiguration config = new XMLConfiguration(TEST_FILE);
 *     config.setLogger(log);
 *     ExprLookup lookup = new ExprLookup(vars);
 *     lookup.setConfiguration(config);
 *     String str = lookup.lookup("'$[element] ' + String.trimToEmpty('$[space.description]')");
 * 
* * In the example above TEST_FILE contains xml that looks like: *
 * <configuration>
 *   <element>value</element>
 *   <space xml:space="preserve">
 *     <description xml:space="default">     Some text      </description>
 *   </space>
 * </configuration>
 * 
* * The result will be "value Some text". * * This lookup uses Apache Commons Jexl and requires that the dependency be added to any * projects which use this. * * @since 1.7 */ public class ExprLookup implements Lookup { /** Prefix to identify a Java Class object */ private static final String CLASS = "Class:"; /** The default prefix for subordinate lookup expressions */ private static final String DEFAULT_PREFIX = "$["; /** The default suffix for subordinate lookup expressions */ private static final String DEFAULT_SUFFIX = "]"; /** The ConfigurationInterpolator used by this object. */ private ConfigurationInterpolator interpolator; /** The StringSubstitutor for performing replace operations. */ private StringSubstitutor substitutor; /** The logger used by this instance. */ private ConfigurationLogger logger; /** The engine. */ private final JexlEngine engine = new JexlEngine(); /** The variables maintained by this object. */ private Variables variables; /** The String to use to start subordinate lookup expressions */ private String prefixMatcher = DEFAULT_PREFIX; /** The String to use to terminate subordinate lookup expressions */ private String suffixMatcher = DEFAULT_SUFFIX; /** * The default constructor. Will get used when the Lookup is constructed via * configuration. */ public ExprLookup() { } /** * Constructor for use by applications. * @param list The list of objects to be accessible in expressions. */ public ExprLookup(final Variables list) { setVariables(list); } /** * Constructor for use by applications. * @param list The list of objects to be accessible in expressions. * @param prefix The prefix to use for subordinate lookups. * @param suffix The suffix to use for subordinate lookups. */ public ExprLookup(final Variables list, final String prefix, final String suffix) { this(list); setVariablePrefixMatcher(prefix); setVariableSuffixMatcher(suffix); } /** * Set the prefix to use to identify subordinate expressions. This cannot be the * same as the prefix used for the primary expression. * @param prefix The String identifying the beginning of the expression. */ public void setVariablePrefixMatcher(final String prefix) { prefixMatcher = prefix; } /** * Set the suffix to use to identify subordinate expressions. This cannot be the * same as the suffix used for the primary expression. * @param suffix The String identifying the end of the expression. */ public void setVariableSuffixMatcher(final String suffix) { suffixMatcher = suffix; } /** * Add the Variables that will be accessible within expressions. * @param list The list of Variables. */ public void setVariables(final Variables list) { variables = new Variables(list); } /** * Returns the list of Variables that are accessible within expressions. * This method returns a copy of the variables managed by this lookup; so * modifying this object has no impact on this lookup. * * @return the List of Variables that are accessible within expressions. */ public Variables getVariables() { return new Variables(variables); } /** * Returns the logger used by this object. * * @return the {@code Log} * @since 2.0 */ public ConfigurationLogger getLogger() { return logger; } /** * Sets the logger to be used by this object. If no logger is passed in, no * log output is generated. * * @param logger the {@code Log} * @since 2.0 */ public void setLogger(final ConfigurationLogger logger) { this.logger = logger; } /** * Returns the {@code ConfigurationInterpolator} used by this object. * * @return the {@code ConfigurationInterpolator} * @since 2.0 */ public ConfigurationInterpolator getInterpolator() { return interpolator; } /** * Sets the {@code ConfigurationInterpolator} to be used by this object. * * @param interpolator the {@code ConfigurationInterpolator} (may be * null) * @since 2.0 */ public void setInterpolator(final ConfigurationInterpolator interpolator) { this.interpolator = interpolator; installSubstitutor(interpolator); } /** * Evaluates the expression. * @param var The expression. * @return The String result of the expression. */ @Override public String lookup(final String var) { if (substitutor == null) { return var; } String result = substitutor.replace(var); try { final Expression exp = engine.createExpression(result); final Object exprResult = exp.evaluate(createContext()); result = exprResult != null ? String.valueOf(exprResult) : null; } catch (final Exception e) { final ConfigurationLogger l = getLogger(); if (l != null) { l.debug("Error encountered evaluating " + result + ": " + e); } } return result; } /** * Creates a {@code StringSubstitutor} object which uses the passed in * {@code ConfigurationInterpolator} as lookup object. * * @param ip the {@code ConfigurationInterpolator} to be used */ private void installSubstitutor(final ConfigurationInterpolator ip) { if (ip == null) { substitutor = null; } else { final StringLookup variableResolver = key -> Objects.toString(ip.resolve(key), null); substitutor = new StringSubstitutor(variableResolver, prefixMatcher, suffixMatcher, StringSubstitutor.DEFAULT_ESCAPE); } } /** * Creates a new {@code JexlContext} and initializes it with the variables * managed by this Lookup object. * * @return the newly created context */ private JexlContext createContext() { final JexlContext ctx = new MapContext(); initializeContext(ctx); return ctx; } /** * Initializes the specified context with the variables managed by this * Lookup object. * * @param ctx the context to be initialized */ private void initializeContext(final JexlContext ctx) { for (final Variable var : variables) { ctx.set(var.getName(), var.getValue()); } } /** * List wrapper used to allow the Variables list to be created as beans in * DefaultConfigurationBuilder. */ public static class Variables extends ArrayList { /** * The serial version UID. */ private static final long serialVersionUID = 20111205L; /** * Creates a new empty instance of {@code Variables}. */ public Variables() { super(); } /** * Creates a new instance of {@code Variables} and copies the content of * the given object. * * @param vars the {@code Variables} object to be copied */ public Variables(final Variables vars) { super(vars); } public Variable getVariable() { return size() > 0 ? get(size() - 1) : null; } } /** * The key and corresponding object that will be made available to the * JexlContext for use in expressions. */ public static class Variable { /** The name to be used in expressions */ private String key; /** The object to be accessed in expressions */ private Object value; public Variable() { } public Variable(final String name, final Object value) { setName(name); setValue(value); } public String getName() { return key; } public void setName(final String name) { this.key = name; } public Object getValue() { return value; } public void setValue(final Object value) throws ConfigurationRuntimeException { try { if (!(value instanceof String)) { this.value = value; return; } final String val = (String) value; final String name = StringUtils.removeStartIgnoreCase(val, CLASS); final Class clazz = ClassUtils.getClass(name); if (name.length() == val.length()) { this.value = clazz.newInstance(); } else { this.value = clazz; } } catch (final Exception e) { throw new ConfigurationRuntimeException("Unable to create " + value, e); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy