Package org.restlet.routing

Source Code of org.restlet.routing.Template

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.routing;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Reference;
import org.restlet.util.Resolver;

/**
* String template with a pluggable model. Supports both formatting and parsing.
* The template variables can be inserted using the "{name}" syntax and
* described using the modifiable map of variable descriptors. When no
* descriptor is found for a given variable, the template logic uses its default
* variable property initialized using the default {@link Variable} constructor.<br>
* <br>
* Note that the variable descriptors can be changed before the first parsing or
* matching call. After that point, changes won't be taken into account.<br>
* <br>
* Format and parsing methods are specially available to deal with requests and
* response. See {@link #format(Request, Response)} and
* {@link #parse(String, Request)}.
*
* @see Resolver
* @see <a href="http://code.google.com/p/uri-templates/">URI Template
*      specification</a>
* @author Jerome Louvel
*/
public class Template {

    /** Mode where all characters must match the template and size be identical. */
    public static final int MODE_EQUALS = 2;

    /** Mode where characters at the beginning must match the template. */
    public static final int MODE_STARTS_WITH = 1;

    /**
     * Appends to a pattern a repeating group of a given content based on a
     * class of characters.
     *
     * @param pattern
     *            The pattern to append to.
     * @param content
     *            The content of the group.
     * @param required
     *            Indicates if the group is required.
     */
    private static void appendClass(StringBuilder pattern, String content,
            boolean required) {

        pattern.append("(");

        if (content.equals(".")) {
            // Special case for the TYPE_ALL variable type because the
            // dot looses its meaning inside a character class
            pattern.append(content);
        } else {
            pattern.append("[").append(content).append(']');
        }

        if (required) {
            pattern.append("+");
        } else {
            pattern.append("*");
        }

        pattern.append(")");
    }

    /**
     * Appends to a pattern a repeating group of a given content based on a
     * non-capturing group.
     *
     * @param pattern
     *            The pattern to append to.
     * @param content
     *            The content of the group.
     * @param required
     *            Indicates if the group is required.
     */
    private static void appendGroup(StringBuilder pattern, String content,
            boolean required) {
        pattern.append("((?:").append(content).append(')');

        if (required) {
            pattern.append("+");
        } else {
            pattern.append("*");
        }

        pattern.append(")");
    }

    /**
     * Returns the Regex pattern string corresponding to a variable.
     *
     * @param variable
     *            The variable.
     * @return The Regex pattern string corresponding to a variable.
     */
    private static String getVariableRegex(Variable variable) {
        String result = null;

        if (variable.isFixed()) {
            result = "(" + Pattern.quote(variable.getDefaultValue()) + ")";
        } else {
            // Expressions to create character classes
            final String ALL = ".";
            final String ALPHA = "a-zA-Z";
            final String DIGIT = "\\d";
            final String ALPHA_DIGIT = ALPHA + DIGIT;
            final String HEXA = DIGIT + "ABCDEFabcdef";
            final String URI_UNRESERVED = ALPHA_DIGIT + "\\-\\.\\_\\~";
            final String URI_GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@";
            final String URI_SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=";
            final String URI_RESERVED = URI_GEN_DELIMS + URI_SUB_DELIMS;
            final String WORD = "\\w";

            // Basic rules expressed by the HTTP rfc.
            final String CRLF = "\\r\\n";
            final String CTL = "\\p{Cntrl}";
            final String LWS = CRLF + "\\ \\t";
            final String SEPARATOR = "\\(\\)\\<\\>\\@\\,\\;\\:\\[\\]\"\\/\\\\?\\=\\{\\}\\ \\t";
            final String TOKEN = "[^" + SEPARATOR + "]";
            final String COMMENT = "[^" + CTL + "]" + "[^\\(\\)]" + LWS;
            final String COMMENT_ATTRIBUTE = "[^\\;\\(\\)]";

            // Expressions to create non-capturing groups
            final String PCT_ENCODED = "\\%[" + HEXA + "][" + HEXA + "]";
            // final String PCHAR = "[" + URI_UNRESERVED + "]|(?:" + PCT_ENCODED
            // + ")|[" + URI_SUB_DELIMS + "]|\\:|\\@";
            final String PCHAR = "[" + URI_UNRESERVED + URI_SUB_DELIMS
                    + "\\:\\@]|(?:" + PCT_ENCODED + ")";
            final String QUERY = PCHAR + "|\\/|\\?";
            final String FRAGMENT = QUERY;
            final String URI_PATH = PCHAR + "|\\/";
            final String URI_ALL = "[" + URI_RESERVED + URI_UNRESERVED
                    + "]|(?:" + PCT_ENCODED + ")";

            // Special case of query parameter characters
            final String QUERY_PARAM_DELIMS = "\\!\\$\\'\\(\\)\\*\\+\\,\\;";
            final String QUERY_PARAM_CHAR = "[" + URI_UNRESERVED
                    + QUERY_PARAM_DELIMS + "\\:\\@]|(?:" + PCT_ENCODED + ")";
            final String QUERY_PARAM = QUERY_PARAM_CHAR + "|\\/|\\?";

            final StringBuilder coreRegex = new StringBuilder();

            switch (variable.getType()) {
            case Variable.TYPE_ALL:
                appendClass(coreRegex, ALL, variable.isRequired());
                break;
            case Variable.TYPE_ALPHA:
                appendClass(coreRegex, ALPHA, variable.isRequired());
                break;
            case Variable.TYPE_DIGIT:
                appendClass(coreRegex, DIGIT, variable.isRequired());
                break;
            case Variable.TYPE_ALPHA_DIGIT:
                appendClass(coreRegex, ALPHA_DIGIT, variable.isRequired());
                break;
            case Variable.TYPE_URI_ALL:
                appendGroup(coreRegex, URI_ALL, variable.isRequired());
                break;
            case Variable.TYPE_URI_UNRESERVED:
                appendClass(coreRegex, URI_UNRESERVED, variable.isRequired());
                break;
            case Variable.TYPE_WORD:
                appendClass(coreRegex, WORD, variable.isRequired());
                break;
            case Variable.TYPE_URI_FRAGMENT:
                appendGroup(coreRegex, FRAGMENT, variable.isRequired());
                break;
            case Variable.TYPE_URI_PATH:
                appendGroup(coreRegex, URI_PATH, variable.isRequired());
                break;
            case Variable.TYPE_URI_QUERY:
                appendGroup(coreRegex, QUERY, variable.isRequired());
                break;
            case Variable.TYPE_URI_QUERY_PARAM:
                appendGroup(coreRegex, QUERY_PARAM, variable.isRequired());
                break;
            case Variable.TYPE_URI_SEGMENT:
                appendGroup(coreRegex, PCHAR, variable.isRequired());
                break;
            case Variable.TYPE_TOKEN:
                appendClass(coreRegex, TOKEN, variable.isRequired());
                break;
            case Variable.TYPE_COMMENT:
                appendClass(coreRegex, COMMENT, variable.isRequired());
                break;
            case Variable.TYPE_COMMENT_ATTRIBUTE:
                appendClass(coreRegex, COMMENT_ATTRIBUTE, variable.isRequired());
                break;
            }

            result = coreRegex.toString();
        }

        return result;
    }

    /** The default variable to use when no matching variable descriptor exists. */
    private volatile Variable defaultVariable;

    /** True if the variables must be encoded when formatting the template. */
    private volatile boolean encodingVariables;

    /** The logger to use. */
    private volatile Logger logger;

    /** The matching mode to use when parsing a formatted reference. */
    private volatile int matchingMode;

    /** The pattern to use for formatting or parsing. */
    private volatile String pattern;

    /** The internal Regex pattern. */
    private volatile Pattern regexPattern;

    /** The sequence of Regex variable names as found in the pattern string. */
    private volatile List<String> regexVariables;

    /** The map of variables associated to the route's template. */
    private final Map<String, Variable> variables;

    /**
     * Default constructor. Each variable matches any sequence of characters by
     * default. When parsing, the template will attempt to match the whole
     * template. When formatting, the variable are replaced by an empty string
     * if they don't exist in the model.
     *
     * @param pattern
     *            The pattern to use for formatting or parsing.
     */
    public Template(String pattern) {
        this(pattern, MODE_EQUALS, Variable.TYPE_ALL, "", true, false);
    }

    /**
     * Constructor.
     *
     * @param pattern
     *            The pattern to use for formatting or parsing.
     * @param matchingMode
     *            The matching mode to use when parsing a formatted reference.
     */
    public Template(String pattern, int matchingMode) {
        this(pattern, matchingMode, Variable.TYPE_ALL, "", true, false);
    }

    /**
     * Constructor.
     *
     * @param pattern
     *            The pattern to use for formatting or parsing.
     * @param matchingMode
     *            The matching mode to use when parsing a formatted reference.
     * @param defaultType
     *            The default type of variables with no descriptor.
     * @param defaultDefaultValue
     *            The default value for null variables with no descriptor.
     * @param defaultRequired
     *            The default required flag for variables with no descriptor.
     * @param defaultFixed
     *            The default fixed value for variables with no descriptor.
     */
    public Template(String pattern, int matchingMode, int defaultType,
            String defaultDefaultValue, boolean defaultRequired,
            boolean defaultFixed) {
        this(pattern, matchingMode, defaultType, defaultDefaultValue,
                defaultRequired, defaultFixed, false);
    }

    /**
     * Constructor.
     *
     * @param pattern
     *            The pattern to use for formatting or parsing.
     * @param matchingMode
     *            The matching mode to use when parsing a formatted reference.
     * @param defaultType
     *            The default type of variables with no descriptor.
     * @param defaultDefaultValue
     *            The default value for null variables with no descriptor.
     * @param defaultRequired
     *            The default required flag for variables with no descriptor.
     * @param defaultFixed
     *            The default fixed value for variables with no descriptor.
     * @param encodingVariables
     *            True if the variables must be encoded when formatting the
     *            template.
     */
    public Template(String pattern, int matchingMode, int defaultType,
            String defaultDefaultValue, boolean defaultRequired,
            boolean defaultFixed, boolean encodingVariables) {
        this.logger = (logger == null) ? Context.getCurrentLogger() : logger;
        this.pattern = pattern;
        this.defaultVariable = new Variable(defaultType, defaultDefaultValue,
                defaultRequired, defaultFixed);
        this.matchingMode = matchingMode;
        this.variables = new ConcurrentHashMap<String, Variable>();
        this.regexPattern = null;
        this.encodingVariables = encodingVariables;
    }

    /**
     * Creates a formatted string based on the given map of values.
     *
     * @param values
     *            The values to use when formatting.
     * @return The formatted string.
     * @see Resolver#createResolver(Map)
     */
    public String format(Map<String, ?> values) {
        return format(Resolver.createResolver(values));
    }

    /**
     * Creates a formatted string based on the given request and response.
     *
     * @param request
     *            The request to use as a model.
     * @param response
     *            The response to use as a model.
     * @return The formatted string.
     * @see Resolver#createResolver(Request, Response)
     */
    public String format(Request request, Response response) {
        return format(Resolver.createResolver(request, response));
    }

    /**
     * Creates a formatted string based on the given variable resolver.
     *
     * @param resolver
     *            The variable resolver to use.
     * @return The formatted string.
     */
    public String format(Resolver<?> resolver) {
        final StringBuilder result = new StringBuilder();
        StringBuilder varBuffer = null;
        char next;
        boolean inVariable = false;
        final int patternLength = getPattern().length();
        for (int i = 0; i < patternLength; i++) {
            next = getPattern().charAt(i);

            if (inVariable) {
                if (Reference.isUnreserved(next)) {
                    // Append to the variable name
                    varBuffer.append(next);
                } else if (next == '}') {
                    // End of variable detected
                    if (varBuffer.length() == 0) {
                        getLogger().warning(
                                "Empty pattern variables are not allowed : "
                                        + this.regexPattern);
                    } else {
                        final String varName = varBuffer.toString();
                        Object varValue = resolver.resolve(varName);

                        Variable var = getVariables().get(varName);

                        // Use the default values instead
                        if (varValue == null) {
                            if (var == null) {
                                var = getDefaultVariable();
                            }

                            if (var != null) {
                                varValue = var.getDefaultValue();
                            }
                        }

                        String varValueString = (varValue == null) ? null
                                : varValue.toString();

                        if (this.encodingVariables) {
                            // In case the values must be encoded.
                            if (var != null) {
                                result.append(var.encode(varValueString));
                            } else {
                                result.append(Reference.encode(varValueString));
                            }
                        } else {
                            if ((var != null) && var.isEncodingOnFormat()) {
                                result.append(Reference.encode(varValueString));
                            } else {
                                result.append(varValueString);
                            }
                        }

                        // Reset the variable name buffer
                        varBuffer = new StringBuilder();
                    }
                    inVariable = false;
                } else {
                    getLogger().warning(
                            "An invalid character was detected inside a pattern variable : "
                                    + this.regexPattern);
                }
            } else {
                if (next == '{') {
                    inVariable = true;
                    varBuffer = new StringBuilder();
                } else if (next == '}') {
                    getLogger().warning(
                            "An invalid character was detected inside a pattern variable : "
                                    + this.regexPattern);
                } else {
                    result.append(next);
                }
            }
        }
        return result.toString();
    }

    /**
     * Returns the default variable.
     *
     * @return The default variable.
     */
    public Variable getDefaultVariable() {
        return this.defaultVariable;
    }

    /**
     * Returns the logger to use.
     *
     * @return The logger to use.
     */
    public Logger getLogger() {
        return this.logger;
    }

    /**
     * Returns the matching mode to use when parsing a formatted reference.
     *
     * @return The matching mode to use when parsing a formatted reference.
     */
    public int getMatchingMode() {
        return this.matchingMode;
    }

    /**
     * Returns the pattern to use for formatting or parsing.
     *
     * @return The pattern to use for formatting or parsing.
     */
    public String getPattern() {
        return this.pattern;
    }

    /**
     * Compiles the URI pattern into a Regex pattern.
     *
     * @return The Regex pattern.
     */
    private Pattern getRegexPattern() {
        if (this.regexPattern == null) {
            synchronized (this) {
                if (this.regexPattern == null) {
                    getRegexVariables().clear();
                    final StringBuilder patternBuffer = new StringBuilder();
                    StringBuilder varBuffer = null;
                    char next;
                    boolean inVariable = false;
                    for (int i = 0; i < getPattern().length(); i++) {
                        next = getPattern().charAt(i);

                        if (inVariable) {
                            if (Reference.isUnreserved(next)) {
                                // Append to the variable name
                                varBuffer.append(next);
                            } else if (next == '}') {
                                // End of variable detected
                                if (varBuffer.length() == 0) {
                                    getLogger().warning(
                                            "Empty pattern variables are not allowed : "
                                                    + this.regexPattern);
                                } else {
                                    final String varName = varBuffer.toString();
                                    final int varIndex = getRegexVariables()
                                            .indexOf(varName);

                                    if (varIndex != -1) {
                                        // The variable is used several times in
                                        // the pattern, ensure that this
                                        // constraint is enforced when parsing.
                                        patternBuffer.append("\\"
                                                + (varIndex + 1));
                                    } else {
                                        // New variable detected. Insert a
                                        // capturing group.
                                        getRegexVariables().add(varName);
                                        Variable var = getVariables().get(
                                                varName);
                                        if (var == null) {
                                            var = getDefaultVariable();
                                        }
                                        patternBuffer
                                                .append(getVariableRegex(var));
                                    }

                                    // Reset the variable name buffer
                                    varBuffer = new StringBuilder();
                                }
                                inVariable = false;

                            } else {
                                getLogger().warning(
                                        "An invalid character was detected inside a pattern variable : "
                                                + this.regexPattern);
                            }
                        } else {
                            if (next == '{') {
                                inVariable = true;
                                varBuffer = new StringBuilder();
                            } else if (next == '}') {
                                getLogger().warning(
                                        "An invalid character was detected inside a pattern variable : "
                                                + this.regexPattern);
                            } else {
                                patternBuffer.append(quote(next));
                            }
                        }
                    }

                    this.regexPattern = Pattern.compile(patternBuffer
                            .toString());
                }
            }
        }

        return this.regexPattern;
    }

    /**
     * Returns the sequence of Regex variable names as found in the pattern
     * string.
     *
     * @return The sequence of Regex variable names as found in the pattern
     *         string.
     */
    private List<String> getRegexVariables() {
        // Lazy initialization with double-check.
        List<String> rv = this.regexVariables;
        if (rv == null) {
            synchronized (this) {
                rv = this.regexVariables;
                if (rv == null) {
                    this.regexVariables = rv = new CopyOnWriteArrayList<String>();
                }
            }
        }
        return rv;
    }

    /**
     * Returns the list of variable names in the template.
     *
     * @return The list of variable names.
     */
    public List<String> getVariableNames() {
        final List<String> result = new ArrayList<String>();
        StringBuilder varBuffer = null;
        char next;
        boolean inVariable = false;
        final String pattern = getPattern();

        for (int i = 0; i < pattern.length(); i++) {
            next = pattern.charAt(i);

            if (inVariable) {
                if (Reference.isUnreserved(next)) {
                    // Append to the variable name
                    varBuffer.append(next);
                } else if (next == '}') {
                    // End of variable detected
                    if (varBuffer.length() == 0) {
                        getLogger().warning(
                                "Empty pattern variables are not allowed : "
                                        + this.pattern);
                    } else {
                        result.add(varBuffer.toString());

                        // Reset the variable name buffer
                        varBuffer = new StringBuilder();
                    }

                    inVariable = false;
                } else {
                    getLogger().warning(
                            "An invalid character was detected inside a pattern variable : "
                                    + this.pattern);
                }
            } else {
                if (next == '{') {
                    inVariable = true;
                    varBuffer = new StringBuilder();
                } else if (next == '}') {
                    getLogger().warning(
                            "An invalid character was detected inside a pattern variable : "
                                    + this.pattern);
                }
            }
        }

        return result;
    }

    /**
     * Returns the modifiable map of variable descriptors. Creates a new
     * instance if no one has been set. Note that those variables are only
     * descriptors that can influence the way parsing and formatting is done,
     * they don't contain the actual value parsed.
     *
     * @return The modifiable map of variables.
     */
    public synchronized Map<String, Variable> getVariables() {
        return this.variables;
    }

    /**
     * Indicates if the variables must be encoded when formatting the template.
     *
     * @return True if the variables must be encoded when formatting the
     *         template, false otherwise.
     */
    public boolean isEncodingVariables() {
        return this.encodingVariables;
    }

    /**
     * Indicates if the current pattern matches the given formatted string.
     *
     * @param formattedString
     *            The formatted string to match.
     * @return The number of matched characters or -1 if the match failed.
     */
    public int match(String formattedString) {
        int result = -1;

        try {
            if (formattedString != null) {
                final Matcher matcher = getRegexPattern().matcher(
                        formattedString);

                if ((getMatchingMode() == MODE_EQUALS) && matcher.matches()) {
                    result = matcher.end();
                } else if ((getMatchingMode() == MODE_STARTS_WITH)
                        && matcher.lookingAt()) {
                    result = matcher.end();
                }
            }
        } catch (StackOverflowError soe) {
            getLogger().warning(
                    "StackOverflowError exception encountered while matching this string : "
                            + formattedString);
        }

        return result;
    }

    /**
     * Attempts to parse a formatted reference. If the parsing succeeds, the
     * given request's attributes are updated.<br>
     * Note that the values parsed are directly extracted from the formatted
     * reference and are therefore not percent-decoded.
     *
     * @see Reference#decode(String)
     *
     * @param formattedString
     *            The string to parse.
     * @param variables
     *            The map of variables to update.
     * @return The number of matched characters or -1 if no character matched.
     */
    public int parse(String formattedString, Map<String, Object> variables) {
        return parse(formattedString, variables, true);
    }

    /**
     * Attempts to parse a formatted reference. If the parsing succeeds, the
     * given request's attributes are updated.<br>
     * Note that the values parsed are directly extracted from the formatted
     * reference and are therefore not percent-decoded.
     *
     * @see Reference#decode(String)
     *
     * @param formattedString
     *            The string to parse.
     * @param variables
     *            The map of variables to update.
     * @param loggable
     *            True if the parsing should be logged.
     * @return The number of matched characters or -1 if no character matched.
     */
    public int parse(String formattedString, Map<String, Object> variables,
            boolean loggable) {
        int result = -1;

        if (formattedString != null) {
            try {
                Matcher matcher = getRegexPattern().matcher(formattedString);
                boolean matched = ((getMatchingMode() == MODE_EQUALS) && matcher
                        .matches())
                        || ((getMatchingMode() == MODE_STARTS_WITH) && matcher
                                .lookingAt());

                if (matched) {
                    // Update the number of matched characters
                    result = matcher.end();

                    // Update the attributes with the variables value
                    String attributeName = null;
                    String attributeValue = null;

                    for (int i = 0; i < getRegexVariables().size(); i++) {
                        attributeName = getRegexVariables().get(i);
                        attributeValue = matcher.group(i + 1);
                        Variable var = getVariables().get(attributeName);

                        if ((var != null) && var.isDecodingOnParse()) {
                            attributeValue = Reference.decode(attributeValue);
                        }

                        if (loggable) {
                            getLogger().fine(
                                    "Template variable \"" + attributeName
                                            + "\" matched with value \""
                                            + attributeValue + "\"");
                        }

                        variables.put(attributeName, attributeValue);
                    }
                }
            } catch (StackOverflowError soe) {
                getLogger().warning(
                        "StackOverflowError exception encountered while matching this string : "
                                + formattedString);
            }
        }

        return result;
    }

    /**
     * Attempts to parse a formatted reference. If the parsing succeeds, the
     * given request's attributes are updated.<br>
     * Note that the values parsed are directly extracted from the formatted
     * reference and are therefore not percent-decoded.
     *
     * @see Reference#decode(String)
     *
     * @param formattedString
     *            The string to parse.
     * @param request
     *            The request to update.
     * @return The number of matched characters or -1 if no character matched.
     */
    public int parse(String formattedString, Request request) {
        return parse(formattedString, request.getAttributes(),
                request.isLoggable());
    }

    /**
     * Quotes special characters that could be taken for special Regex
     * characters.
     *
     * @param character
     *            The character to quote if necessary.
     * @return The quoted character.
     */
    private String quote(char character) {
        switch (character) {
        case '[':
            return "\\[";
        case ']':
            return "\\]";
        case '.':
            return "\\.";
        case '\\':
            return "\\\\";
        case '$':
            return "\\$";
        case '^':
            return "\\^";
        case '?':
            return "\\?";
        case '*':
            return "\\*";
        case '|':
            return "\\|";
        case '(':
            return "\\(";
        case ')':
            return "\\)";
        case ':':
            return "\\:";
        case '-':
            return "\\-";
        case '!':
            return "\\!";
        case '<':
            return "\\<";
        case '>':
            return "\\>";
        default:
            return Character.toString(character);
        }
    }

    /**
     * Sets the variable to use, if no variable is given.
     *
     * @param defaultVariable
     */
    public void setDefaultVariable(Variable defaultVariable) {
        this.defaultVariable = defaultVariable;
    }

    /**
     * Indicates if the variables must be encoded when formatting the template.
     *
     * @param encodingVariables
     *            True if the variables must be encoded when formatting the
     *            template.
     */
    public void setEncodingVariables(boolean encodingVariables) {
        this.encodingVariables = encodingVariables;
    }

    /**
     * Sets the logger to use.
     *
     * @param logger
     *            The logger to use.
     */
    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    /**
     * Sets the matching mode to use when parsing a formatted reference.
     *
     * @param matchingMode
     *            The matching mode to use when parsing a formatted reference.
     */
    public void setMatchingMode(int matchingMode) {
        this.matchingMode = matchingMode;
    }

    /**
     * Sets the pattern to use for formatting or parsing.
     *
     * @param pattern
     *            The pattern to use for formatting or parsing.
     */
    public void setPattern(String pattern) {
        this.pattern = pattern;
        this.regexPattern = null;
    }

    /**
     * Sets the modifiable map of variables.
     *
     * @param variables
     *            The modifiable map of variables.
     */
    public void setVariables(Map<String, Variable> variables) {
        synchronized (this.variables) {
            if (variables != this.variables) {
                this.variables.clear();

                if (variables != null) {
                    this.variables.putAll(variables);
                }
            }
        }
    }

}
TOP

Related Classes of org.restlet.routing.Template

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.