001: package com.opensymphony.webwork.views.util;
002:
003: import java.io.UnsupportedEncodingException;
004: import java.net.URLDecoder;
005: import java.net.URLEncoder;
006: import java.util.ArrayList;
007: import java.util.Arrays;
008: import java.util.Collections;
009: import java.util.Iterator;
010: import java.util.LinkedHashMap;
011: import java.util.List;
012: import java.util.Map;
013:
014: import javax.servlet.http.HttpServletRequest;
015: import javax.servlet.http.HttpServletResponse;
016:
017: import org.apache.commons.lang.ArrayUtils;
018: import org.apache.commons.logging.Log;
019: import org.apache.commons.logging.LogFactory;
020:
021: import com.opensymphony.webwork.ServletActionContext;
022: import com.opensymphony.webwork.WebWorkConstants;
023: import com.opensymphony.webwork.config.Configuration;
024: import com.opensymphony.xwork.ActionContext;
025: import com.opensymphony.xwork.util.OgnlValueStack;
026: import com.opensymphony.xwork.util.TextParseUtil;
027: import com.opensymphony.xwork.util.XWorkContinuationConfig;
028:
029: /**
030: * UrlHelper
031: *
032: * @author Jason Carreira Created Apr 19, 2003 9:32:19 PM
033: * @author tm_jee
034: */
035: public class UrlHelper {
036: private static final Log LOG = LogFactory.getLog(UrlHelper.class);
037:
038: /**
039: * Default HTTP port (80).
040: */
041: private static final int DEFAULT_HTTP_PORT = 80;
042:
043: /**
044: * Default HTTPS port (443).
045: */
046: private static final int DEFAULT_HTTPS_PORT = 443;
047:
048: /**
049: * Escaped Ampersand (&)
050: */
051: private static final String AMP = "&";
052:
053: /**
054: * Build url based on arguments supplied, will include context path but does
055: * not encode result (append jsessionid).
056: *
057: * @param action
058: * @param request
059: * @param response
060: * @param params
061: * @return the build url
062: */
063: public static String buildUrl(String action,
064: HttpServletRequest request, HttpServletResponse response,
065: Map params) {
066: return buildUrl(action, request, response, params, null, true,
067: true);
068: }
069:
070: /**
071: * Build url based on arguments supplied, will not include schema, host and
072: * port in the created url.
073: *
074: * @param action
075: * @param request
076: * @param response
077: * @param params
078: * @param scheme
079: * @param includeContext
080: * @param encodeResult
081: * @return the build url
082: */
083: public static String buildUrl(String action,
084: HttpServletRequest request, HttpServletResponse response,
085: Map params, String scheme, boolean includeContext,
086: boolean encodeResult) {
087: return buildUrl(action, request, response, params, scheme,
088: includeContext, encodeResult, false);
089: }
090:
091: /**
092: * Build url based on arguments supplied, will escape ampersand.
093: *
094: * @param action
095: * @param request
096: * @param response
097: * @param params
098: * @param scheme
099: * @param includeContext
100: * @param encodeResult
101: * @param forceAddSchemeHostAndPort
102: * @return the build url
103: */
104: public static String buildUrl(String action,
105: HttpServletRequest request, HttpServletResponse response,
106: Map params, String scheme, boolean includeContext,
107: boolean encodeResult, boolean forceAddSchemeHostAndPort) {
108: return buildUrl(action, request, response, params, scheme,
109: includeContext, encodeResult,
110: forceAddSchemeHostAndPort, true);
111: }
112:
113: /**
114: * Build url based on arguments supplied.
115: *
116: * @param action
117: * @param request
118: * @param response
119: * @param params
120: * @param scheme
121: * @param includeContext
122: * @param encodeResult
123: * @param forceAddSchemeHostAndPort
124: * @param escapeAmp
125: * @return the build url
126: */
127: public static String buildUrl(String action,
128: HttpServletRequest request, HttpServletResponse response,
129: Map params, String scheme, boolean includeContext,
130: boolean encodeResult, boolean forceAddSchemeHostAndPort,
131: boolean escapeAmp) {
132: StringBuffer link = new StringBuffer();
133:
134: boolean changedScheme = false;
135:
136: int httpPort = DEFAULT_HTTP_PORT;
137:
138: try {
139: httpPort = Integer.parseInt((String) Configuration
140: .get(WebWorkConstants.WEBWORK_URL_HTTP_PORT));
141: } catch (Exception ex) {
142: }
143:
144: int httpsPort = DEFAULT_HTTPS_PORT;
145:
146: try {
147: httpsPort = Integer.parseInt((String) Configuration
148: .get(WebWorkConstants.WEBWORK_URL_HTTPS_PORT));
149: } catch (Exception ex) {
150: }
151:
152: // only append scheme if it is different to the current scheme *OR*
153: // if we explicity want it to be appended by having forceAddSchemeHostAndPort = true
154: if (forceAddSchemeHostAndPort) {
155: String reqScheme = request.getScheme();
156: changedScheme = true;
157: link.append(scheme != null ? scheme : reqScheme);
158: link.append("://");
159: link.append(request.getServerName());
160: if (scheme != null) {
161: if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT))
162: || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT)) {
163: link.append(":");
164: link.append(scheme.equals("http") ? httpPort
165: : httpsPort);
166: }
167: }
168: } else if ((scheme != null)
169: && !scheme.equals(request.getScheme())) {
170: changedScheme = true;
171: link.append(scheme);
172: link.append("://");
173: link.append(request.getServerName());
174:
175: if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT))
176: || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT)) {
177: link.append(":");
178: link.append(scheme.equals("http") ? httpPort
179: : httpsPort);
180: }
181: }
182:
183: if (action != null) {
184: // Check if context path needs to be added
185: // Add path to absolute links
186: if (action.startsWith("/") && includeContext) {
187: String contextPath = request.getContextPath();
188: if (!contextPath.equals("/")) {
189: link.append(contextPath);
190: }
191: } else if (changedScheme) {
192: String uri = request.getRequestURI();
193: link.append(uri.substring(0, uri.lastIndexOf('/')));
194: }
195:
196: // Add page
197: link.append(action);
198: } else {
199: // Go to "same page"
200: String requestURI = (String) request
201: .getAttribute("webwork.request_uri");
202:
203: if (requestURI == null) {
204: requestURI = request.getRequestURI();
205: }
206:
207: link.append(requestURI);
208: }
209:
210: // tie in the continuation parameter
211: String continueId = (String) ActionContext.getContext().get(
212: XWorkContinuationConfig.CONTINUE_KEY);
213: if (continueId != null) {
214: if (params == null) {
215: params = Collections.singletonMap(
216: XWorkContinuationConfig.CONTINUE_PARAM,
217: continueId);
218: } else {
219: params.put(XWorkContinuationConfig.CONTINUE_PARAM,
220: continueId);
221: }
222: }
223:
224: if (escapeAmp) {
225: buildParametersString(params, link);
226: } else {
227: buildParametersString(params, link, "&");
228: }
229:
230: String result;
231:
232: try {
233: result = encodeResult ? response.encodeURL(link.toString())
234: : link.toString();
235: } catch (Exception ex) {
236: // Could not encode the URL for some reason
237: // Use it unchanged
238: result = link.toString();
239: }
240:
241: return result;
242: }
243:
244: public static void buildParametersString(Map params,
245: StringBuffer link) {
246: buildParametersString(params, link, AMP);
247: }
248:
249: public static void buildParametersString(Map params,
250: StringBuffer link, String paramSeparator) {
251: if ((params != null) && (params.size() > 0)) {
252: if (link.toString().indexOf("?") == -1) {
253: link.append("?");
254: } else {
255: link.append(paramSeparator);
256: }
257:
258: // Set params
259: Iterator iter = params.entrySet().iterator();
260:
261: String[] valueHolder = new String[1];
262:
263: while (iter.hasNext()) {
264: Map.Entry entry = (Map.Entry) iter.next();
265: String name = (String) entry.getKey();
266: Object value = entry.getValue();
267:
268: String[] values;
269:
270: if (value instanceof String[]) {
271: values = (String[]) value;
272: } else {
273: valueHolder[0] = value.toString();
274: values = valueHolder;
275: }
276:
277: for (int i = 0; i < values.length; i++) {
278: if (values[i] != null) {
279: link.append(name);
280: link.append('=');
281: link.append(translateAndEncode(values[i]));
282: }
283:
284: if (i < (values.length - 1)) {
285: link.append(paramSeparator);
286: }
287: }
288:
289: if (iter.hasNext()) {
290: link.append(paramSeparator);
291: }
292: }
293: }
294: }
295:
296: /**
297: * Translates any script expressions using {@link com.opensymphony.xwork.util.TextParseUtil#translateVariables} and
298: * encodes the URL using {@link java.net.URLEncoder#encode} with the encoding specified in the configuration.
299: *
300: * @param input
301: * @return the translated and encoded string
302: */
303: public static String translateAndEncode(String input) {
304: String translatedInput = translateVariable(input);
305: String encoding = getEncodingFromConfiguration();
306:
307: try {
308: return URLEncoder.encode(translatedInput, encoding);
309: } catch (UnsupportedEncodingException e) {
310: LOG.warn("Could not encode URL parameter '" + input
311: + "', returning value un-encoded");
312: return translatedInput;
313: }
314: }
315:
316: public static String translateAndDecode(String input) {
317: String translatedInput = translateVariable(input);
318: String encoding = getEncodingFromConfiguration();
319:
320: try {
321: return URLDecoder.decode(translatedInput, encoding);
322: } catch (UnsupportedEncodingException e) {
323: LOG.warn("Could not encode URL parameter '" + input
324: + "', returning value un-encoded");
325: return translatedInput;
326: }
327: }
328:
329: private static String translateVariable(String input) {
330: OgnlValueStack valueStack = ServletActionContext.getContext()
331: .getValueStack();
332: String output = TextParseUtil.translateVariables(input,
333: valueStack);
334: return output;
335: }
336:
337: private static String getEncodingFromConfiguration() {
338: final String encoding;
339:
340: if (Configuration.isSet(WebWorkConstants.WEBWORK_I18N_ENCODING)) {
341: encoding = Configuration
342: .getString(WebWorkConstants.WEBWORK_I18N_ENCODING);
343: } else {
344: encoding = "UTF-8";
345: }
346: return encoding;
347: }
348:
349: public static Map parseQueryString(String queryString) {
350: Map queryParams = new LinkedHashMap();
351: if (queryString != null) {
352: String[] params = queryString.split("&");
353: for (int a = 0; a < params.length; a++) {
354: if (params[a].trim().length() > 0) {
355: String[] tmpParams = params[a].split("=");
356: String paramName = null;
357: String paramValue = "";
358: if (tmpParams.length > 0) {
359: paramName = tmpParams[0];
360: }
361: if (tmpParams.length > 1) {
362: paramValue = tmpParams[1];
363: }
364: if (paramName != null) {
365: String translatedParamValue = translateAndDecode(paramValue);
366:
367: if (queryParams.containsKey(paramName)) {
368: // WW-1376 append new param value to existing value(s)
369: Object currentParam = queryParams
370: .get(paramName);
371: if (currentParam instanceof String) {
372: queryParams.put(paramName,
373: new String[] {
374: (String) currentParam,
375: translatedParamValue });
376: } else {
377: String currentParamValues[] = (String[]) currentParam;
378: List paramList = new ArrayList(Arrays
379: .asList(currentParamValues));
380: paramList.add(translatedParamValue);
381: String newParamValues[] = new String[paramList
382: .size()];
383: queryParams.put(paramName, paramList
384: .toArray(newParamValues));
385: }
386: } else {
387: queryParams.put(paramName,
388: translatedParamValue);
389: }
390: }
391: }
392: }
393: }
394: return queryParams;
395: }
396: }
|