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 }