001// Copyright 2004, 2005 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 015package org.apache.tapestry.engine; 016 017import java.io.UnsupportedEncodingException; 018import java.util.Map; 019 020import org.apache.commons.codec.net.URLCodec; 021import org.apache.hivemind.ApplicationRuntimeException; 022import org.apache.hivemind.util.Defense; 023import org.apache.tapestry.IRequestCycle; 024import org.apache.tapestry.Tapestry; 025import org.apache.tapestry.util.QueryParameterMap; 026import org.apache.tapestry.web.WebRequest; 027 028/** 029 * A EngineServiceLink represents a possible action within the client web browser; either clicking a 030 * link or submitting a form, which is constructed primarily from the servlet path, with some 031 * additional query parameters. A full URL for the EngineServiceLink can be generated, or the query 032 * parameters for the EngineServiceLink can be extracted (separately from the servlet path). The 033 * latter case is used when submitting constructing {@link org.apache.tapestry.form.Form forms}. 034 * 035 * @author Howard Lewis Ship 036 * @since 3.0 037 */ 038 039public class EngineServiceLink implements ILink 040{ 041 private static final int DEFAULT_HTTP_PORT = 80; 042 private static final int DEFAULT_HTTPS_PORT = 443; 043 044 private final IRequestCycle _cycle; 045 046 private final String _servletPath; 047 048 private final URLCodec _codec; 049 050 private String _encoding; 051 052 private boolean _stateful; 053 054 /** @since 4.0 */ 055 private final QueryParameterMap _parameters; 056 057 /** @since 4.0 */ 058 059 private final WebRequest _request; 060 061 /** 062 * Creates a new EngineServiceLink. 063 * 064 * @param cycle 065 * The {@link IRequestCycle} the EngineServiceLink is to be created for. 066 * @param servletPath 067 * The path used to invoke the Tapestry servlet. 068 * @param codec 069 * A codec for converting strings into URL-safe formats. 070 * @param encoding 071 * The output encoding for the request. 072 * @param parameters 073 * The query parameters to be encoded into the url. Keys are strings, values are 074 * null, string or array of string. The map is retained, not copied. 075 * @param stateful 076 * if true, the service which generated the EngineServiceLink is stateful and expects 077 * that the final URL will be passed through {@link IRequestCycle#encodeURL(String)}. 078 */ 079 080 public EngineServiceLink(IRequestCycle cycle, String servletPath, String encoding, 081 URLCodec codec, WebRequest request, Map parameters, boolean stateful) 082 { 083 Defense.notNull(cycle, "cycle"); 084 Defense.notNull(servletPath, "servletPath"); 085 Defense.notNull(encoding, "encoding"); 086 Defense.notNull(codec, "codec"); 087 Defense.notNull(request, "request"); 088 Defense.notNull(parameters, "parameters"); 089 090 _cycle = cycle; 091 _servletPath = servletPath; 092 _encoding = encoding; 093 _codec = codec; 094 _request = request; 095 _parameters = new QueryParameterMap(parameters); 096 _stateful = stateful; 097 } 098 099 public String getURL() 100 { 101 return getURL(null, true); 102 } 103 104 public String getURL(String anchor, boolean includeParameters) 105 { 106 return constructURL(new StringBuffer(), anchor, includeParameters); 107 } 108 109 public String getAbsoluteURL() 110 { 111 return getAbsoluteURL(null, null, 0, null, true); 112 } 113 114 public String getURL(String scheme, String server, int port, String anchor, 115 boolean includeParameters) 116 { 117 boolean useAbsolute = EngineUtils.needAbsoluteURL(scheme, server, port, _request); 118 119 return useAbsolute ? getAbsoluteURL(scheme, server, port, anchor, includeParameters) 120 : getURL(anchor, includeParameters); 121 } 122 123 public String getAbsoluteURL(String scheme, String server, int port, String anchor, 124 boolean includeParameters) 125 { 126 StringBuffer buffer = new StringBuffer(); 127 128 if (scheme == null) 129 scheme = _request.getScheme(); 130 131 buffer.append(scheme); 132 buffer.append("://"); 133 134 if (server == null) 135 server = _request.getServerName(); 136 137 buffer.append(server); 138 139 if (port == 0) 140 port = _request.getServerPort(); 141 142 if (!(scheme.equals("http") && port == DEFAULT_HTTP_PORT)) 143 { 144 buffer.append(':'); 145 buffer.append(port); 146 } 147 148 // Add the servlet path and the rest of the URL & query parameters. 149 // The servlet path starts with a leading slash. 150 151 return constructURL(buffer, anchor, includeParameters); 152 } 153 154 private String constructURL(StringBuffer buffer, String anchor, boolean includeParameters) 155 { 156 buffer.append(_servletPath); 157 158 if (includeParameters) 159 addParameters(buffer); 160 161 if (anchor != null) 162 { 163 buffer.append('#'); 164 buffer.append(anchor); 165 } 166 167 String result = buffer.toString(); 168 169 result = _cycle.encodeURL(result); 170 171 return result; 172 } 173 174 private void addParameters(StringBuffer buffer) 175 { 176 String[] names = getParameterNames(); 177 178 String sep = "?"; 179 180 for (int i = 0; i < names.length; i++) 181 { 182 String name = names[i]; 183 String[] values = getParameterValues(name); 184 185 if (values == null) 186 continue; 187 188 for (int j = 0; j < values.length; j++) 189 { 190 buffer.append(sep); 191 buffer.append(name); 192 buffer.append("="); 193 buffer.append(encode(values[j])); 194 195 sep = "&"; 196 } 197 198 } 199 } 200 201 private String encode(String value) 202 { 203 try 204 { 205 return _codec.encode(value, _encoding); 206 } 207 catch (UnsupportedEncodingException ex) 208 { 209 throw new ApplicationRuntimeException(Tapestry.format("illegal-encoding", _encoding), 210 ex); 211 } 212 } 213 214 public String[] getParameterNames() 215 { 216 return _parameters.getParameterNames(); 217 } 218 219 public String[] getParameterValues(String name) 220 { 221 return _parameters.getParameterValues(name); 222 } 223}