001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.util; 018 019import java.net.URI; 020import java.net.URISyntaxException; 021import java.util.Collections; 022import java.util.HashMap; 023import java.util.Map; 024 025import org.springframework.util.Assert; 026 027/** 028 * Abstract base class for {@link UriTemplateHandler} implementations. 029 * 030 * <p>Support {@link #setBaseUrl} and {@link #setDefaultUriVariables} properties 031 * that should be relevant regardless of the URI template expand and encode 032 * mechanism used in sub-classes. 033 * 034 * @author Rossen Stoyanchev 035 * @since 4.3 036 */ 037public abstract class AbstractUriTemplateHandler implements UriTemplateHandler { 038 039 private String baseUrl; 040 041 private final Map<String, Object> defaultUriVariables = new HashMap<String, Object>(); 042 043 044 /** 045 * Configure a base URL to prepend URI templates with. The base URL must 046 * have a scheme and host but may optionally contain a port and a path. 047 * The base URL must be fully expanded and encoded which can be done via 048 * {@link UriComponentsBuilder}. 049 * @param baseUrl the base URL. 050 */ 051 public void setBaseUrl(String baseUrl) { 052 if (baseUrl != null) { 053 UriComponents uriComponents = UriComponentsBuilder.fromUriString(baseUrl).build(); 054 Assert.hasText(uriComponents.getScheme(), "'baseUrl' must have a scheme"); 055 Assert.hasText(uriComponents.getHost(), "'baseUrl' must have a host"); 056 Assert.isNull(uriComponents.getQuery(), "'baseUrl' cannot have a query"); 057 Assert.isNull(uriComponents.getFragment(), "'baseUrl' cannot have a fragment"); 058 } 059 this.baseUrl = baseUrl; 060 } 061 062 /** 063 * Return the configured base URL. 064 */ 065 public String getBaseUrl() { 066 return this.baseUrl; 067 } 068 069 /** 070 * Configure default URI variable values to use with every expanded URI 071 * template. These default values apply only when expanding with a Map, and 072 * not with an array, where the Map supplied to {@link #expand(String, Map)} 073 * can override the default values. 074 * @param defaultUriVariables the default URI variable values 075 * @since 4.3 076 */ 077 public void setDefaultUriVariables(Map<String, ?> defaultUriVariables) { 078 this.defaultUriVariables.clear(); 079 if (defaultUriVariables != null) { 080 this.defaultUriVariables.putAll(defaultUriVariables); 081 } 082 } 083 084 /** 085 * Return a read-only copy of the configured default URI variables. 086 */ 087 public Map<String, ?> getDefaultUriVariables() { 088 return Collections.unmodifiableMap(this.defaultUriVariables); 089 } 090 091 092 @Override 093 public URI expand(String uriTemplate, Map<String, ?> uriVariables) { 094 if (!getDefaultUriVariables().isEmpty()) { 095 Map<String, Object> map = new HashMap<String, Object>(); 096 map.putAll(getDefaultUriVariables()); 097 map.putAll(uriVariables); 098 uriVariables = map; 099 } 100 URI url = expandInternal(uriTemplate, uriVariables); 101 return insertBaseUrl(url); 102 } 103 104 @Override 105 public URI expand(String uriTemplate, Object... uriVariables) { 106 URI url = expandInternal(uriTemplate, uriVariables); 107 return insertBaseUrl(url); 108 } 109 110 111 /** 112 * Actually expand and encode the URI template. 113 */ 114 protected abstract URI expandInternal(String uriTemplate, Map<String, ?> uriVariables); 115 116 /** 117 * Actually expand and encode the URI template. 118 */ 119 protected abstract URI expandInternal(String uriTemplate, Object... uriVariables); 120 121 122 /** 123 * Insert a base URL (if configured) unless the given URL has a host already. 124 */ 125 private URI insertBaseUrl(URI url) { 126 try { 127 String baseUrl = getBaseUrl(); 128 if (baseUrl != null && url.getHost() == null) { 129 url = new URI(baseUrl + url.toString()); 130 } 131 return url; 132 } 133 catch (URISyntaxException ex) { 134 throw new IllegalArgumentException("Invalid URL after inserting base URL: " + url, ex); 135 } 136 } 137 138}