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

com.github.datalking.util.web.UriTemplate Maven / Gradle / Ivy

package com.github.datalking.util.web;

import com.github.datalking.util.Assert;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Represents a URI template. A URI template is a URI-like String that contains variables enclosed
 * by braces ({@code {}}), which can be expanded to produce an actual URI.
 */
public class UriTemplate implements Serializable {

    /**
     * Captures URI template variable names.
     */
    private static final Pattern NAMES_PATTERN = Pattern.compile("\\{([^/]+?)\\}");

    /**
     * Replaces template variables in the URI template.
     */
    private static final String DEFAULT_VARIABLE_PATTERN = "(.*)";

    private final UriComponents uriComponents;

    private final List variableNames;

    private final Pattern matchPattern;

    private final String uriTemplate;


    /**
     * Construct a new {@code UriTemplate} with the given URI String.
     *
     * @param uriTemplate the URI template string
     */
    public UriTemplate(String uriTemplate) {
        Parser parser = new Parser(uriTemplate);
        this.uriTemplate = uriTemplate;
        this.variableNames = parser.getVariableNames();
        this.matchPattern = parser.getMatchPattern();
        this.uriComponents = UriComponentsBuilder.fromUriString(uriTemplate).build();
    }


    /**
     * Return the names of the variables in the template, in order.
     *
     * @return the template variable names
     */
    public List getVariableNames() {
        return this.variableNames;
    }

    /**
     * Given the Map of variables, expands this template into a URI. The Map keys represent variable names,
     * the Map values variable values. The order of variables is not significant.
     * 

Example: *

     * UriTemplate template = new UriTemplate("http://example.com/hotels/{hotel}/bookings/{booking}");
     * Map<String, String> uriVariables = new HashMap<String, String>();
     * uriVariables.put("booking", "42");
     * uriVariables.put("hotel", "Rest & Relax");
     * System.out.println(template.expand(uriVariables));
     * 
* will print:
{@code http://example.com/hotels/Rest%20%26%20Relax/bookings/42}
* * @param uriVariables the map of URI variables * @return the expanded URI * @throws IllegalArgumentException if {@code uriVariables} is {@code null}; * or if it does not contain values for all the variable names */ public URI expand(Map uriVariables) { UriComponents expandedComponents = this.uriComponents.expand(uriVariables); UriComponents encodedComponents = expandedComponents.encode(); return encodedComponents.toUri(); } /** * Given an array of variables, expand this template into a full URI. The array represent variable values. * The order of variables is significant. *

Example: *

     * UriTemplate template = new UriTemplate("http://example.com/hotels/{hotel}/bookings/{booking}");
     * System.out.println(template.expand("Rest & Relax", "42));
     * 
* will print:
{@code http://example.com/hotels/Rest%20%26%20Relax/bookings/42}
* * @param uriVariableValues the array of URI variables * @return the expanded URI * @throws IllegalArgumentException if {@code uriVariables} is {@code null} * or if it does not contain sufficient variables */ public URI expand(Object... uriVariableValues) { UriComponents expandedComponents = this.uriComponents.expand(uriVariableValues); UriComponents encodedComponents = expandedComponents.encode(); return encodedComponents.toUri(); } /** * Indicate whether the given URI matches this template. * * @param uri the URI to match to * @return {@code true} if it matches; {@code false} otherwise */ public boolean matches(String uri) { if (uri == null) { return false; } Matcher matcher = this.matchPattern.matcher(uri); return matcher.matches(); } /** * Match the given URI to a map of variable values. Keys in the returned map are variable names, * values are variable values, as occurred in the given URI. *

Example: *

     * UriTemplate template = new UriTemplate("http://example.com/hotels/{hotel}/bookings/{booking}");
     * System.out.println(template.match("http://example.com/hotels/1/bookings/42"));
     * 
* will print:
{@code {hotel=1, booking=42}}
* * @param uri the URI to match to * @return a map of variable values */ public Map match(String uri) { Assert.notNull(uri, "'uri' must not be null"); Map result = new LinkedHashMap(this.variableNames.size()); Matcher matcher = this.matchPattern.matcher(uri); if (matcher.find()) { for (int i = 1; i <= matcher.groupCount(); i++) { String name = this.variableNames.get(i - 1); String value = matcher.group(i); result.put(name, value); } } return result; } /** * Encodes the given String as URL. *

Defaults to {@link UriUtils#encodeUri(String, String)}. * * @param uri the URI to encode * @return the encoded URI * @deprecated No longer in use; to be removed in Spring 4.0. */ @Deprecated protected URI encodeUri(String uri) { try { String encoded = UriUtils.encodeUri(uri, "UTF-8"); return new URI(encoded); } catch (UnsupportedEncodingException ex) { // should not happen, UTF-8 is always supported throw new IllegalStateException(ex); } catch (URISyntaxException ex) { throw new IllegalArgumentException("Could not create URI from [" + uri + "]: " + ex, ex); } } @Override public String toString() { return this.uriTemplate; } /** * Static inner class to parse URI template strings into a matching regular expression. */ private static class Parser { private final List variableNames = new LinkedList(); private final StringBuilder patternBuilder = new StringBuilder(); private Parser(String uriTemplate) { Assert.hasText(uriTemplate, "'uriTemplate' must not be null"); Matcher matcher = NAMES_PATTERN.matcher(uriTemplate); int end = 0; while (matcher.find()) { this.patternBuilder.append(quote(uriTemplate, end, matcher.start())); String match = matcher.group(1); int colonIdx = match.indexOf(':'); if (colonIdx == -1) { this.patternBuilder.append(DEFAULT_VARIABLE_PATTERN); this.variableNames.add(match); } else { if (colonIdx + 1 == match.length()) { throw new IllegalArgumentException( "No custom regular expression specified after ':' in \"" + match + "\""); } String variablePattern = match.substring(colonIdx + 1, match.length()); this.patternBuilder.append('('); this.patternBuilder.append(variablePattern); this.patternBuilder.append(')'); String variableName = match.substring(0, colonIdx); this.variableNames.add(variableName); } end = matcher.end(); } this.patternBuilder.append(quote(uriTemplate, end, uriTemplate.length())); int lastIdx = this.patternBuilder.length() - 1; if (lastIdx >= 0 && this.patternBuilder.charAt(lastIdx) == '/') { this.patternBuilder.deleteCharAt(lastIdx); } } private String quote(String fullPath, int start, int end) { if (start == end) { return ""; } return Pattern.quote(fullPath.substring(start, end)); } private List getVariableNames() { return Collections.unmodifiableList(this.variableNames); } private Pattern getMatchPattern() { return Pattern.compile(this.patternBuilder.toString()); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy