001: /*
002: * $Id: UrlHelper.java 565492 2007-08-13 20:00:08Z jholmes $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: package org.apache.struts2.views.util;
023:
024: import java.io.UnsupportedEncodingException;
025: import java.net.URLDecoder;
026: import java.net.URLEncoder;
027: import java.util.ArrayList;
028: import java.util.Arrays;
029: import java.util.Iterator;
030: import java.util.LinkedHashMap;
031: import java.util.List;
032: import java.util.Map;
033:
034: import javax.servlet.http.HttpServletRequest;
035: import javax.servlet.http.HttpServletResponse;
036:
037: import org.apache.commons.logging.Log;
038: import org.apache.commons.logging.LogFactory;
039: import org.apache.struts2.ServletActionContext;
040: import org.apache.struts2.StrutsConstants;
041:
042: import com.opensymphony.xwork2.inject.Inject;
043: import com.opensymphony.xwork2.util.TextParseUtil;
044: import com.opensymphony.xwork2.util.ValueStack;
045:
046: /**
047: * UrlHelper
048: *
049: */
050: public class UrlHelper {
051: private static final Log LOG = LogFactory.getLog(UrlHelper.class);
052:
053: /**
054: * Default HTTP port (80).
055: */
056: private static final int DEFAULT_HTTP_PORT = 80;
057:
058: /**
059: * Default HTTPS port (443).
060: */
061: private static final int DEFAULT_HTTPS_PORT = 443;
062:
063: private static final String AMP = "&";
064:
065: private static int httpPort = DEFAULT_HTTP_PORT;
066: private static int httpsPort = DEFAULT_HTTPS_PORT;
067: private static String customEncoding;
068:
069: @Inject(StrutsConstants.STRUTS_URL_HTTP_PORT)
070: public static void setHttpPort(String val) {
071: httpPort = Integer.parseInt(val);
072: }
073:
074: @Inject(StrutsConstants.STRUTS_URL_HTTPS_PORT)
075: public static void setHttpsPort(String val) {
076: httpsPort = Integer.parseInt(val);
077: }
078:
079: @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
080: public static void setCustomEncoding(String val) {
081: customEncoding = val;
082: }
083:
084: public static String buildUrl(String action,
085: HttpServletRequest request, HttpServletResponse response,
086: Map params) {
087: return buildUrl(action, request, response, params, null, true,
088: true);
089: }
090:
091: public static String buildUrl(String action,
092: HttpServletRequest request, HttpServletResponse response,
093: Map params, String scheme, boolean includeContext,
094: boolean encodeResult) {
095: return buildUrl(action, request, response, params, scheme,
096: includeContext, encodeResult, false);
097: }
098:
099: public static String buildUrl(String action,
100: HttpServletRequest request, HttpServletResponse response,
101: Map params, String scheme, boolean includeContext,
102: boolean encodeResult, boolean forceAddSchemeHostAndPort) {
103: return buildUrl(action, request, response, params, scheme,
104: includeContext, encodeResult,
105: forceAddSchemeHostAndPort, true);
106: }
107:
108: public static String buildUrl(String action,
109: HttpServletRequest request, HttpServletResponse response,
110: Map params, String scheme, boolean includeContext,
111: boolean encodeResult, boolean forceAddSchemeHostAndPort,
112: boolean escapeAmp) {
113: StringBuffer link = new StringBuffer();
114:
115: boolean changedScheme = false;
116:
117: // only append scheme if it is different to the current scheme *OR*
118: // if we explicity want it to be appended by having forceAddSchemeHostAndPort = true
119: if (forceAddSchemeHostAndPort) {
120: String reqScheme = request.getScheme();
121: changedScheme = true;
122: link.append(scheme != null ? scheme : reqScheme);
123: link.append("://");
124: link.append(request.getServerName());
125:
126: if (scheme != null) {
127: // If switching schemes, use the configured port for the particular scheme.
128: if (!scheme.equals(reqScheme)) {
129: if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT))
130: || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT)) {
131: link.append(":");
132: link.append(scheme.equals("http") ? httpPort
133: : httpsPort);
134: }
135: // Else use the port from the current request.
136: } else {
137: int reqPort = request.getServerPort();
138:
139: if ((scheme.equals("http") && (reqPort != DEFAULT_HTTP_PORT))
140: || (scheme.equals("https") && reqPort != DEFAULT_HTTPS_PORT)) {
141: link.append(":");
142: link.append(reqPort);
143: }
144: }
145: }
146: } else if ((scheme != null)
147: && !scheme.equals(request.getScheme())) {
148: changedScheme = true;
149: link.append(scheme);
150: link.append("://");
151: link.append(request.getServerName());
152:
153: if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT))
154: || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT)) {
155: link.append(":");
156: link.append(scheme.equals("http") ? httpPort
157: : httpsPort);
158: }
159: }
160:
161: if (action != null) {
162: // Check if context path needs to be added
163: // Add path to absolute links
164: if (action.startsWith("/") && includeContext) {
165: String contextPath = request.getContextPath();
166: if (!contextPath.equals("/")) {
167: link.append(contextPath);
168: }
169: } else if (changedScheme) {
170:
171: // (Applicable to Servlet 2.4 containers)
172: // If the request was forwarded, the attribute below will be set with the original URL
173: String uri = (String) request
174: .getAttribute("javax.servlet.forward.request_uri");
175:
176: // If the attribute wasn't found, default to the value in the request object
177: if (uri == null) {
178: uri = request.getRequestURI();
179: }
180:
181: link.append(uri.substring(0, uri.lastIndexOf('/') + 1));
182: }
183:
184: // Add page
185: link.append(action);
186: } else {
187: // Go to "same page"
188: String requestURI = (String) request
189: .getAttribute("struts.request_uri");
190:
191: // (Applicable to Servlet 2.4 containers)
192: // If the request was forwarded, the attribute below will be set with the original URL
193: if (requestURI == null) {
194: requestURI = (String) request
195: .getAttribute("javax.servlet.forward.request_uri");
196: }
197:
198: // If neither request attributes were found, default to the value in the request object
199: if (requestURI == null) {
200: requestURI = request.getRequestURI();
201: }
202:
203: link.append(requestURI);
204: }
205:
206: //if the action was not explicitly set grab the params from the request
207: if (escapeAmp) {
208: buildParametersString(params, link);
209: } else {
210: buildParametersString(params, link, "&");
211: }
212:
213: String result;
214:
215: try {
216: result = encodeResult ? response.encodeURL(link.toString())
217: : link.toString();
218: } catch (Exception ex) {
219: // Could not encode the URL for some reason
220: // Use it unchanged
221: result = link.toString();
222: }
223:
224: return result;
225: }
226:
227: public static void buildParametersString(Map params,
228: StringBuffer link) {
229: buildParametersString(params, link, AMP);
230: }
231:
232: public static void buildParametersString(Map params,
233: StringBuffer link, String paramSeparator) {
234: if ((params != null) && (params.size() > 0)) {
235: if (link.toString().indexOf("?") == -1) {
236: link.append("?");
237: } else {
238: link.append(paramSeparator);
239: }
240:
241: // Set params
242: Iterator iter = params.entrySet().iterator();
243:
244: String[] valueHolder = new String[1];
245:
246: while (iter.hasNext()) {
247: Map.Entry entry = (Map.Entry) iter.next();
248: String name = (String) entry.getKey();
249: Object value = entry.getValue();
250:
251: String[] values;
252:
253: if (value instanceof String[]) {
254: values = (String[]) value;
255: } else {
256: valueHolder[0] = value.toString();
257: values = valueHolder;
258: }
259:
260: for (int i = 0; i < values.length; i++) {
261: if (values[i] != null) {
262: link.append(name);
263: link.append('=');
264: link.append(translateAndEncode(values[i]));
265: }
266:
267: if (i < (values.length - 1)) {
268: link.append(paramSeparator);
269: }
270: }
271:
272: if (iter.hasNext()) {
273: link.append(paramSeparator);
274: }
275: }
276: }
277: }
278:
279: /**
280: * Translates any script expressions using {@link com.opensymphony.xwork2.util.TextParseUtil#translateVariables} and
281: * encodes the URL using {@link java.net.URLEncoder#encode} with the encoding specified in the configuration.
282: *
283: * @param input
284: * @return the translated and encoded string
285: */
286: public static String translateAndEncode(String input) {
287: String translatedInput = translateVariable(input);
288: String encoding = getEncodingFromConfiguration();
289:
290: try {
291: return URLEncoder.encode(translatedInput, encoding);
292: } catch (UnsupportedEncodingException e) {
293: LOG.warn("Could not encode URL parameter '" + input
294: + "', returning value un-encoded");
295: return translatedInput;
296: }
297: }
298:
299: public static String translateAndDecode(String input) {
300: String translatedInput = translateVariable(input);
301: String encoding = getEncodingFromConfiguration();
302:
303: try {
304: return URLDecoder.decode(translatedInput, encoding);
305: } catch (UnsupportedEncodingException e) {
306: LOG.warn("Could not encode URL parameter '" + input
307: + "', returning value un-encoded");
308: return translatedInput;
309: }
310: }
311:
312: private static String translateVariable(String input) {
313: ValueStack valueStack = ServletActionContext.getContext()
314: .getValueStack();
315: String output = TextParseUtil.translateVariables(input,
316: valueStack);
317: return output;
318: }
319:
320: private static String getEncodingFromConfiguration() {
321: final String encoding;
322: if (customEncoding != null) {
323: encoding = customEncoding;
324: } else {
325: encoding = "UTF-8";
326: }
327: return encoding;
328: }
329:
330: public static Map parseQueryString(String queryString) {
331: Map queryParams = new LinkedHashMap();
332: if (queryString != null) {
333: String[] params = queryString.split("&");
334: for (int a = 0; a < params.length; a++) {
335: if (params[a].trim().length() > 0) {
336: String[] tmpParams = params[a].split("=");
337: String paramName = null;
338: String paramValue = "";
339: if (tmpParams.length > 0) {
340: paramName = tmpParams[0];
341: }
342: if (tmpParams.length > 1) {
343: paramValue = tmpParams[1];
344: }
345: if (paramName != null) {
346: String translatedParamValue = translateAndDecode(paramValue);
347:
348: if (queryParams.containsKey(paramName)) {
349: // WW-1619 append new param value to existing value(s)
350: Object currentParam = queryParams
351: .get(paramName);
352: if (currentParam instanceof String) {
353: queryParams.put(paramName,
354: new String[] {
355: (String) currentParam,
356: translatedParamValue });
357: } else {
358: String currentParamValues[] = (String[]) currentParam;
359: List paramList = new ArrayList(Arrays
360: .asList(currentParamValues));
361: paramList.add(translatedParamValue);
362: String newParamValues[] = new String[paramList
363: .size()];
364: queryParams.put(paramName, paramList
365: .toArray(newParamValues));
366: }
367: } else {
368: queryParams.put(paramName,
369: translatedParamValue);
370: }
371: }
372: }
373: }
374: }
375: return queryParams;
376: }
377: }
|