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

org.springframework.web.util.UriTemplate Maven / Gradle / Ivy

There is a newer version: 6.1.13
Show newest version
/*
 * Copyright 2002-2009 the original author or authors.
 *
 * 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.springframework.web.util;

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;

import org.springframework.util.Assert;

/**
 * Represents a URI template. An URI template is a URI-like String that contained variables marked of in braces
 * ({, }), which can be expanded to produce a URI. 

See {@link #expand(Map)}, * {@link #expand(Object[])}, and {@link #match(String)} for example usages. * * @author Arjen Poutsma * @author Juergen Hoeller * @see URI Templates * @since 3.0 */ public class UriTemplate { /** Captures URI template variable names. */ private static final Pattern NAMES_PATTERN = Pattern.compile("\\{([^/]+?)\\}"); /** Replaces template variables in the URI template. */ private static final String VALUE_REGEX = "(.*)"; private final List variableNames; private final Pattern matchPattern; private final String uriTemplate; /** * Construct a new {@link 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(); } /** * Return the names of the variables in the template, in order. * @return the template variable names */ public final 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", "1");
	 * System.out.println(template.expand(uriVariables));
	 * 
* will print:
http://example.com/hotels/1/bookings/42
* @param uriVariables the map of URI variables * @return the expanded URI * @throws IllegalArgumentException if uriVariables is null; or if it does not contain values * for all the variable names */ public URI expand(Map uriVariables) { Assert.notNull(uriVariables, "'uriVariables' must not be null"); Object[] values = new String[this.variableNames.size()]; for (int i = 0; i < this.variableNames.size(); i++) { String name = this.variableNames.get(i); if (!uriVariables.containsKey(name)) { throw new IllegalArgumentException("'uriVariables' Map has no value for '" + name + "'"); } values[i] = uriVariables.get(name); } return expand(values); } /** * Given an array of variables, expand this template into a full URI. The array represent variable values. * The order of variables is significant.

Example:

 will print: 
http://example.com/hotels/1/bookings/42
* @param uriVariableValues the array of URI variables * @return the expanded URI * @throws IllegalArgumentException if uriVariables is null; or if it does not contain * sufficient variables */ public URI expand(Object... uriVariableValues) { Assert.notNull(uriVariableValues, "'uriVariableValues' must not be null"); if (uriVariableValues.length != this.variableNames.size()) { throw new IllegalArgumentException( "Invalid amount of variables values in [" + this.uriTemplate + "]: expected " + this.variableNames.size() + "; got " + uriVariableValues.length); } Matcher matcher = NAMES_PATTERN.matcher(this.uriTemplate); StringBuffer buffer = new StringBuffer(); int i = 0; while (matcher.find()) { String uriVariable = uriVariableValues[i++].toString(); matcher.appendReplacement(buffer, uriVariable); } matcher.appendTail(buffer); return encodeUri(buffer.toString()); } /** * Indicate whether the given URI matches this template. * @param uri the URI to match to * @return true if it matches; 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:
{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; } @Override public String toString() { return this.uriTemplate; } private static 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); } } /** * 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 m = NAMES_PATTERN.matcher(uriTemplate); int end = 0; while (m.find()) { this.patternBuilder.append(encodeAndQuote(uriTemplate, end, m.start())); this.patternBuilder.append(VALUE_REGEX); this.variableNames.add(m.group(1)); end = m.end(); } this.patternBuilder.append(encodeAndQuote(uriTemplate, end, uriTemplate.length())); int lastIdx = this.patternBuilder.length() - 1; if (lastIdx >= 0 && this.patternBuilder.charAt(lastIdx) == '/') { this.patternBuilder.deleteCharAt(lastIdx); } } private String encodeAndQuote(String fullPath, int start, int end) { if (start == end) { return ""; } String result = encodeUri(fullPath.substring(start, end)).toASCIIString(); return Pattern.quote(result); } private List getVariableNames() { return Collections.unmodifiableList(this.variableNames); } private Pattern getMatchPattern() { return Pattern.compile(this.patternBuilder.toString()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy