001 // Copyright 2009, 2010, 2011 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.internal.services;
016
017 import org.apache.tapestry5.Link;
018 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
019 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
020 import org.apache.tapestry5.services.BaseURLSource;
021 import org.apache.tapestry5.services.ContextPathEncoder;
022 import org.apache.tapestry5.services.Response;
023
024 import java.util.List;
025 import java.util.Map;
026
027 public class LinkImpl implements Link
028 {
029 private Map<String, String> parameters;
030
031 private final String basePath;
032
033 private final boolean forForm;
034
035 private LinkSecurity defaultSecurity;
036
037 private final Response response;
038
039 private final ContextPathEncoder contextPathEncoder;
040
041 private final BaseURLSource baseURLSource;
042
043 private String anchor;
044
045 public LinkImpl(String basePath, boolean forForm, LinkSecurity defaultSecurity, Response response,
046 ContextPathEncoder contextPathEncoder, BaseURLSource baseURLSource)
047 {
048 assert basePath != null;
049
050 this.basePath = basePath;
051 this.forForm = forForm;
052 this.defaultSecurity = defaultSecurity;
053 this.response = response;
054 this.contextPathEncoder = contextPathEncoder;
055 this.baseURLSource = baseURLSource;
056 }
057
058 public Link copyWithBasePath(String basePath)
059 {
060 LinkImpl copy = new LinkImpl(basePath, forForm, defaultSecurity, response, contextPathEncoder, baseURLSource);
061
062 copy.anchor = anchor;
063
064 for (String name : getParameterNames())
065 {
066 copy.addParameter(name, parameters.get(name));
067 }
068
069 return copy;
070 }
071
072 public void addParameter(String parameterName, String value)
073 {
074 assert InternalUtils.isNonBlank(parameterName);
075
076 if (parameters == null)
077 parameters = CollectionFactory.newMap();
078
079 parameters.put(parameterName, value == null ? "" : value);
080 }
081
082 public String getBasePath()
083 {
084 return basePath;
085 }
086
087 public void removeParameter(String parameterName)
088 {
089 assert InternalUtils.isNonBlank(parameterName);
090 if (parameters != null)
091 parameters.remove(parameterName);
092 }
093
094 public String getAnchor()
095 {
096 return anchor;
097 }
098
099 public List<String> getParameterNames()
100 {
101 return InternalUtils.sortedKeys(parameters);
102 }
103
104 public String getParameterValue(String name)
105 {
106 return InternalUtils.get(parameters, name);
107 }
108
109 public void setAnchor(String anchor)
110 {
111 this.anchor = anchor;
112 }
113
114 public String toAbsoluteURI()
115 {
116 return buildAnchoredURI(defaultSecurity.promote());
117 }
118
119 public String toAbsoluteURI(boolean secure)
120 {
121 return buildAnchoredURI(secure ? LinkSecurity.FORCE_SECURE : LinkSecurity.FORCE_INSECURE);
122 }
123
124 public void setSecurity(LinkSecurity newSecurity)
125 {
126 assert newSecurity != null;
127
128 defaultSecurity = newSecurity;
129 }
130
131 public LinkSecurity getSecurity()
132 {
133 return defaultSecurity;
134 }
135
136 public String toRedirectURI()
137 {
138 return appendAnchor(response.encodeRedirectURL(buildURI(defaultSecurity)));
139 }
140
141 public String toURI()
142 {
143 return buildAnchoredURI(defaultSecurity);
144 }
145
146 private String appendAnchor(String path)
147 {
148 return InternalUtils.isBlank(anchor) ? path : path + "#" + anchor;
149 }
150
151 private String buildAnchoredURI(LinkSecurity security)
152 {
153 return appendAnchor(response.encodeURL(buildURI(security)));
154 }
155
156 /**
157 * Returns the value from {@link #toURI()}
158 */
159 @Override
160 public String toString()
161 {
162 return toURI();
163 }
164
165 /**
166 * Extends the absolute path with any query parameters. Query parameters are never added to a forForm link.
167 *
168 * @return absoluteURI appended with query parameters
169 */
170 private String buildURI(LinkSecurity security)
171 {
172
173 if (!security.isAbsolute() && (forForm || parameters == null))
174 return basePath;
175
176 StringBuilder builder = new StringBuilder(basePath.length() * 2);
177
178 switch (security)
179 {
180 case FORCE_SECURE:
181 builder.append(baseURLSource.getBaseURL(true));
182 break;
183 case FORCE_INSECURE:
184 builder.append(baseURLSource.getBaseURL(false));
185 break;
186 default:
187 }
188
189 // The base URL (from BaseURLSource) does not end with a slash.
190 // The basePath does (the context path begins with a slash or is blank, then there's
191 // always a slash before the local name or page name.
192
193 builder.append(basePath);
194
195 if (!forForm)
196 {
197 String sep = basePath.contains("?") ? "&" : "?";
198
199 for (String name : getParameterNames())
200 {
201 String value = parameters.get(name);
202
203 builder.append(sep);
204
205 // We assume that the name is URL safe and that the value will already have been URL
206 // encoded if it is not known to be URL safe.
207
208 builder.append(name);
209 builder.append("=");
210 builder.append(value);
211
212 sep = "&";
213 }
214 }
215
216 return builder.toString();
217 }
218
219 public Link addParameterValue(String parameterName, Object value)
220 {
221 addParameter(parameterName, contextPathEncoder.encodeValue(value));
222
223 return this;
224 }
225
226 }