org.wrml.runtime.rest.UriTemplate.java Source code

Java tutorial

Introduction

Here is the source code for org.wrml.runtime.rest.UriTemplate.java

Source

/**
 * WRML - Web Resource Modeling Language
 *  __     __   ______   __    __   __
 * /\ \  _ \ \ /\  == \ /\ "-./  \ /\ \
 * \ \ \/ ".\ \\ \  __< \ \ \-./\ \\ \ \____
 *  \ \__/".~\_\\ \_\ \_\\ \_\ \ \_\\ \_____\
 *   \/_/   \/_/ \/_/ /_/ \/_/  \/_/ \/_____/
 *
 * http://www.wrml.org
 *
 * Copyright (C) 2011 - 2013 Mark Masse <mark@wrml.org> (OSS project WRML.org)
 *
 * 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.wrml.runtime.rest;

import org.apache.commons.lang3.StringUtils;
import org.wrml.runtime.syntax.SyntaxHandler;
import org.wrml.runtime.syntax.SyntaxLoader;

import java.net.URI;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @see <a href="http://www.ietf.org/rfc/rfc6570.txt">RFC 6570 - URI Template</a>
 */
public class UriTemplate {

    public static final char PATH_SEPARATOR_CHAR = '/';

    public static final String PATH_SEPARATOR = String.valueOf(PATH_SEPARATOR_CHAR);

    private static final Pattern PARAM_NAMES_PATTERN = Pattern.compile("\\{([^/]+?)\\}");

    private final SyntaxLoader _SyntaxLoader;

    private final String[] _ParamNames;

    private final Pattern _MatchPattern;

    private final String _UriTemplateString;

    private URI _StaticUri;

    public UriTemplate(final SyntaxLoader syntaxLoader, final String uriTemplateString) {

        _SyntaxLoader = syntaxLoader;
        _UriTemplateString = uriTemplateString;

        final int length = uriTemplateString.length();
        final Matcher matcher = UriTemplate.PARAM_NAMES_PATTERN.matcher(uriTemplateString);
        final StringBuilder pattern = new StringBuilder();
        final List<String> paramNames = new ArrayList<String>();
        int end = 0;

        while (matcher.find()) {
            final int start = matcher.start();

            if (start != end) {
                // Copy the none-match to the pattern
                pattern.append(uriTemplateString.substring(end, start));

                end = matcher.end();
                final String matcherGroup = matcher.group(1);

                // Append the fixed group name
                pattern.append("(?<" + matcherGroup + ">\\S+)");
            }
            paramNames.add(matcher.group(1));
            end = matcher.end();
        }

        if (end != length) {
            pattern.append(uriTemplateString.substring(end, length));
        }

        String patternString = pattern.toString();
        final int lastIndex = patternString.length() - 1;
        if ((lastIndex >= 0) && (patternString.charAt(lastIndex) == PATH_SEPARATOR_CHAR)) {
            patternString = patternString.substring(0, lastIndex);
        }

        _MatchPattern = Pattern.compile(patternString);
        _ParamNames = new String[paramNames.size()];

        paramNames.toArray(_ParamNames);

    }

    public URI evaluate(final Map<String, Object> parameterMap) {

        return evaluate(parameterMap, false);
    }

    public URI evaluate(final Map<String, Object> parameterMap, final boolean allowNulls) {

        final URI staticUri = getStaticUri();
        if (staticUri != null) {
            if (parameterMap == null || parameterMap.size() == 0) {
                return staticUri;
            } else {
                throw new UriTemplateException("The URI Template accepts no parameters", null, this);
            }

        }

        final SyntaxLoader syntaxLoader = getSyntaxLoader();

        String matchResult = _MatchPattern.toString();

        for (final String templateParamName : _ParamNames) {
            final Object templateParamValue = parameterMap.get(templateParamName);
            final String templateParamStringValue;
            if (templateParamValue == null) {
                if (allowNulls) {
                    templateParamStringValue = "null";
                } else {
                    return null;
                }
            } else {
                templateParamStringValue = syntaxLoader.formatSyntaxValue(templateParamValue);
            }

            matchResult = matchResult.replace("(?<" + templateParamName + ">\\S+)", templateParamStringValue);
        }

        final SyntaxHandler<URI> uriSyntaxHandler = syntaxLoader.getSyntaxHandler(URI.class);
        final URI uri = uriSyntaxHandler.parseSyntacticText(matchResult);

        // TODO:  This would be cleaner and more consistent, but it currently breaks UriTemplateTest (unit test) with mocking strategy that makes it impossible...?
        //final URI uri = syntaxLoader.parseSyntacticText(matchResult, URI.class);

        return uri;
    }

    public String[] getParameterNames() {

        return _ParamNames;
    }

    public SortedSet<Parameter> getParameters(final URI uri) {

        if (uri == null) {
            throw new UriTemplateException("Null URI", null, this);
        }

        String uriString = uri.toString();
        uriString = StringUtils.substringBefore(uriString, "?");

        final Matcher matcher = _MatchPattern.matcher(uriString);

        if (!matcher.matches()) {
            return null;
        }

        final SortedSet<Parameter> parameterSet = new TreeSet<>();
        for (final String paramName : _ParamNames) {
            final String paramValue = matcher.group(paramName);
            final Parameter parameter = new Parameter(paramName, paramValue);
            parameterSet.add(parameter);
        }

        return parameterSet;
    }

    public SyntaxLoader getSyntaxLoader() {

        return _SyntaxLoader;
    }

    public String getUriTemplateString() {

        return _UriTemplateString;
    }

    public boolean matches(final URI uri) {

        if (uri == null) {
            return false;
        }

        final URI staticUri = getStaticUri();
        if (staticUri != null && uri.equals(staticUri)) {
            return true;
        }

        final String uriString = uri.normalize().toString();
        final Matcher matcher = getMatchPattern().matcher(uriString);

        return matcher.matches();
    }

    @Override
    public String toString() {

        String retval = "";

        retval += _UriTemplateString;

        return retval;
    }

    private Pattern getMatchPattern() {

        return _MatchPattern;
    }

    private URI getStaticUri() {

        if (_StaticUri == null && _ParamNames.length == 0) {
            _StaticUri = URI.create(_UriTemplateString);
        }
        return _StaticUri;
    }
}