/* * Copyright (c) 2009, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * SQL Power Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.object; import java.util.Collection; /** * Defines all methods to implement to make an object capable of resolving * variables into actual values. * * <p>Variables keys are {@link String} values and might be prefixed by a * namespace value. Typically, the namespace will be a specific object UUID. * You can ask the resolver directly if he is capable of resolving variables * in a given namespace by calling {@link SPVariableResolver#resolvesNamespace(String)}. * * <p>For example, one might expect an inserted variable to be something like: * * <blockquote><code>${w1234-1234-1234-1234::myVariableKey}</code></blockquote> * * <p>For performance reasons, it is strongly suggested of using those namespaces * and cache a map of namespaces<->resolvers. Large object models will benefit greatly * of this. * * <p>An inserted variable can also specify it's default value. This can be accomplished * by inserting a variable as so. * * <blockquote><code>${w1234-1234-1234-1234::myVariableKey->defValue}</code></blockquote> * * <p>In the above example, the default value is a string which contents is 'defValue'. * * <p>The usual way of using the Variables framework goes like this. {@link SPObject} that want * to expose variables must implement the {@link SPVariableResolverProvider} interface. * They then instanciate a variable resolver. One default implementation is available as * {@link SPSimpleVariableResolver}. * * <p>The {@link SPSimpleVariableResolver} has a dual role. It is able to store and * update variables in a MultiMap. Multiple values can therefore be stored under a * same variable key. It also implements the {@link SPVariableResolver} interface, * which allows it to share variable values with it's fellow objects. * * <p>In order to search through the tree and resolve variables, one instanciates * a {@link SPVariableHelper} object and uses a specific node of the tree as a * constructor argument. This node will serve as a starting point to resolve * variables. It will walk the tree and search for implementation of * {@link SPVariableResolverProvider}. There are lots of options available to configure * the helper's behavior and optimize it's search routine. Read it's javadoc for more details. * * @see {@link SPVariableHelper} * @author Luc Boudreau */ public interface SPVariableResolver { /** * The delimiter to use for namespaced variable names. */ public static final String NAMESPACE_DELIMITER = "::"; /** * Used to define an inserted variable default value if it cannot be resolved. * @see {@link SPVariableResolver} */ public static final String DEFAULT_VALUE_DELIMITER = "->"; /** * Stores a variable value. If a value with the same key already exists, * a new value will be added. * * @param key The key to store the value under. * @param value The value to store. */ public void store(String key, Object value); /** * Updates a variable value. This means that if a variable with the * same key was already stored, it will be wiped and replaced by * the new value. * * @param key The key to store the value under. * @param value The value to store. */ public void update(String key, Object value); /** * Removes all values associated with the specified key. * @param key The key for which we want to delete all occurences. */ public void delete(String key); /** * Resolves a variable to it's value by a String key. * Returns null if the variable cannot be resolved. * * <p>If more than one value is matched by the key, the actual returned * value is not guaranteed to be neither the first match or anything * alike. You should use {@link SPVariableResolver#resolveCollection(String)} * if you expect there might be more than one possible returned values. * * @param key The variable key to resolve * @return The variable object, or null if it cannot be resolved. */ public Object resolve(String key); /** * Resolves a variable to it's value by a String key. * Returns the default supplied value if the variable cannot be resolved. * * <p>If more than one value is matched by the key, the actual returned * value is not guaranteed to be neither the first match or anything * alike. You should use {@link SPVariableResolver#resolveCollection(String, Object)} * if you expect there might be more than one possible returned values. * * <p>A common mistake done by using this call is to receive the default * value without verifying prior to the call if the implementing resolver * can actually resolve it via the {@link SPVariableResolver#resolves(String)} * function. * * @param key The variable key to resolve * @param defaultValue The default value to return if the variable * cannot be resolved * @return The variable object, or the default value passed as * a parameter if it cannot be resolved. */ public Object resolve(String key, Object defaultValue); /** * Resolves a variable to it's value by a String key. * Returns an empty {@link Collection} if the variable cannot be resolved. * * @param key The variable key to resolve * @return The variable object, or an empty {@link Collection} * if it cannot be resolved. */ public Collection<Object> resolveCollection(String key); /** * Resolves a variable to it's value by a String key. Returns a * {@link Collection} containing only the supplied default value if the * variable cannot be resolved. * * <p> * A common mistake done by using this call is to receive the default value * without verifying prior to the call if the implementing resolver can * actually resolve it via the {@link SPVariableResolver#resolves(String)} * function. * * @param key * The variable key to resolve * @return The variable object, or a {@link Collection} containing only the * supplied default value if the variable cannot be resolved. */ public Collection<Object> resolveCollection(String key, Object defaultValue); /** * Verifies if this variable resolver can effectively resolve the * supplied variable. * @param key The key of the variable we would like to know if it * can be resolved. * @return True or false. */ public boolean resolves(String key); /** * Verifies if this variable resolver can effectively resolve * variables in the provided namespace value. * * <p>The rules are as follows. * * <ul> * <li>If this resolver's namespace is null and the namespace passed as * a parameter is null, return true. * <li>If this resolver's namespace is null but we pass a namespace as * a parameter, return false. * <li>If this resolver's namespace is defined and we pass a namespace as a parameter, * we return true IF both namespaces match. * <li>If this resolver's namespace is defined but we pass a null namespace * as a parameter, we return true; * </li> * * <p>Some resolvers don't follow these rules. For example, the builtin * {@link SPSimpleVariableResolver} by default operates in snobby mode. * This means that if you give it a namespace and ask him for non-namespaced * variables, he won't resolve them. * * @param namespace The namespace for which we want to know if this resolver * is capable of resolving variables. * @return True or false. */ public boolean resolvesNamespace(String namespace); /** * For a given key and the first characters of a variable value, * this method returns all matches. This is a auto-complete function. * * For example, if the key "foo" and the values "bar" and "bar2" are * resolved by a given variable resolver, sending to this function * "foo" as the key and "ba" as the partial match would return both * variable values. * * @param key The key of the variable we want all corresponding matches. * @param partialValue The first characters of a variable value to match * against all possible values. * @return A collection of matching variable values. */ public Collection<Object> matches(String key, String partialValue); /** * This function is used to get all available variable names * for a given namespace. Passing a null value as a namespace * means that we want to ignore namespaces and we want a complete * list of available namespaces/keys. * * @param namespace Either a namespace or null. * @return A collection of available variable names. */ public Collection<String> keySet(String namespace); /** * returns the namespace under which this resolver is registered. * @return The namespace of this resolver implementation. */ public String getNamespace(); /** * Returns the name of this resolver as to be exposed to * the end user. * @return A user friendly name for this resolver. */ public String getUserFriendlyName(); }