View Javadoc

1   /*
2    * $Id: UrlHelper.java 451544 2006-09-30 05:38:02Z mrdon $
3    *
4    * Copyright 2006 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts2.views.util;
19  
20  import java.io.UnsupportedEncodingException;
21  import java.net.URLDecoder;
22  import java.net.URLEncoder;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.LinkedHashMap;
26  import java.util.Map;
27  
28  import javax.servlet.http.HttpServletRequest;
29  import javax.servlet.http.HttpServletResponse;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.struts2.ServletActionContext;
34  import org.apache.struts2.StrutsConstants;
35  import org.apache.struts2.config.Settings;
36  
37  import com.opensymphony.xwork2.ActionContext;
38  import com.opensymphony.xwork2.util.TextParseUtil;
39  import com.opensymphony.xwork2.util.ValueStack;
40  import com.opensymphony.xwork2.util.XWorkContinuationConfig;
41  
42  
43  /***
44   * UrlHelper
45   *
46   */
47  public class UrlHelper {
48      private static final Log LOG = LogFactory.getLog(UrlHelper.class);
49  
50      /***
51       * Default HTTP port (80).
52       */
53      private static final int DEFAULT_HTTP_PORT = 80;
54  
55      /***
56       * Default HTTPS port (443).
57       */
58      private static final int DEFAULT_HTTPS_PORT = 443;
59  
60      private static final String AMP = "&";
61  
62      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params) {
63          return buildUrl(action, request, response, params, null, true, true);
64      }
65      
66      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult) {
67      	return buildUrl(action, request, response, params, scheme, includeContext, encodeResult, false);
68      }
69  
70      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort) {
71          StringBuffer link = new StringBuffer();
72  
73          boolean changedScheme = false;
74  
75          int httpPort = DEFAULT_HTTP_PORT;
76  
77          try {
78              httpPort = Integer.parseInt((String) Settings.get(StrutsConstants.STRUTS_URL_HTTP_PORT));
79          } catch (Exception ex) {
80          }
81  
82          int httpsPort = DEFAULT_HTTPS_PORT;
83  
84          try {
85              httpsPort = Integer.parseInt((String) Settings.get(StrutsConstants.STRUTS_URL_HTTPS_PORT));
86          } catch (Exception ex) {
87          }
88  
89          // only append scheme if it is different to the current scheme *OR*
90          // if we explicity want it to be appended by having forceAddSchemeHostAndPort = true
91          if (forceAddSchemeHostAndPort) {
92          	String reqScheme = request.getScheme();
93          	changedScheme = true;
94          	link.append(scheme != null ? scheme : reqScheme);
95          	link.append("://");
96          	link.append(request.getServerName());
97          	
98          	if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT))
99              {
100                 link.append(":");
101                 link.append(scheme.equals("http") ? httpPort : httpsPort);
102             }
103         }
104         else if (  
105            (scheme != null) && !scheme.equals(request.getScheme())) {
106             changedScheme = true;
107             link.append(scheme);
108             link.append("://");
109             link.append(request.getServerName());
110 
111             if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT))
112             {
113                 link.append(":");
114                 link.append(scheme.equals("http") ? httpPort : httpsPort);
115             }
116         }
117 
118         if (action != null) {
119             // Check if context path needs to be added
120             // Add path to absolute links
121             if (action.startsWith("/") && includeContext) {
122                 String contextPath = request.getContextPath();
123                 if (!contextPath.equals("/")) {
124                     link.append(contextPath);
125                 }
126             } else if (changedScheme) {
127                 
128                 // (Applicable to Servlet 2.4 containers)
129                 // If the request was forwarded, the attribute below will be set with the original URL
130                 String uri = (String) request.getAttribute("javax.servlet.forward.request_uri");
131                 
132                 // If the attribute wasn't found, default to the value in the request object
133                 if (uri == null) {
134                     uri = request.getRequestURI();
135                 }
136                 
137                 link.append(uri.substring(0, uri.lastIndexOf('/') + 1));
138             }
139 
140             // Add page
141             link.append(action);
142         } else {
143             // Go to "same page"
144             String requestURI = (String) request.getAttribute("struts.request_uri");
145 
146             // (Applicable to Servlet 2.4 containers)
147             // If the request was forwarded, the attribute below will be set with the original URL
148             if (requestURI == null) {
149                 requestURI = (String) request.getAttribute("javax.servlet.forward.request_uri");
150             }
151             
152             // If neither request attributes were found, default to the value in the request object
153             if (requestURI == null) {
154                 requestURI = request.getRequestURI();
155             }
156 
157             link.append(requestURI);
158         }
159 
160         // tie in the continuation parameter
161         String continueId = (String) ActionContext.getContext().get(XWorkContinuationConfig.CONTINUE_KEY);
162         if (continueId != null) {
163             if (params == null) {
164                 params = Collections.singletonMap(XWorkContinuationConfig.CONTINUE_PARAM, continueId);
165             } else {
166                 params.put(XWorkContinuationConfig.CONTINUE_PARAM, continueId);
167             }
168         }
169 
170         //if the action was not explicitly set grab the params from the request
171         buildParametersString(params, link);
172 
173         String result;
174 
175         try {
176             result = encodeResult ? response.encodeURL(link.toString()) : link.toString();
177         } catch (Exception ex) {
178             // Could not encode the URL for some reason
179             // Use it unchanged
180             result = link.toString();
181         }
182 
183         return result;
184     }
185 
186     public static void buildParametersString(Map params, StringBuffer link) {
187     	buildParametersString(params, link, AMP);
188     }
189     
190     public static void buildParametersString(Map params, StringBuffer link, String paramSeparator) {
191         if ((params != null) && (params.size() > 0)) {
192             if (link.toString().indexOf("?") == -1) {
193                 link.append("?");
194             } else {
195                 link.append(paramSeparator);
196             }
197 
198             // Set params
199             Iterator iter = params.entrySet().iterator();
200 
201             String[] valueHolder = new String[1];
202 
203             while (iter.hasNext()) {
204                 Map.Entry entry = (Map.Entry) iter.next();
205                 String name = (String) entry.getKey();
206                 Object value = entry.getValue();
207 
208                 String[] values;
209 
210                 if (value instanceof String[]) {
211                     values = (String[]) value;
212                 } else {
213                     valueHolder[0] = value.toString();
214                     values = valueHolder;
215                 }
216 
217                 for (int i = 0; i < values.length; i++) {
218                     if (values[i] != null) {
219                         link.append(name);
220                         link.append('=');
221                         link.append(translateAndEncode(values[i]));
222                     }
223 
224                     if (i < (values.length - 1)) {
225                         link.append(paramSeparator);
226                     }
227                 }
228 
229                 if (iter.hasNext()) {
230                     link.append(paramSeparator);
231                 }
232             }
233         }
234     }
235 
236     /***
237      * Translates any script expressions using {@link com.opensymphony.xwork2.util.TextParseUtil#translateVariables} and
238      * encodes the URL using {@link java.net.URLEncoder#encode} with the encoding specified in the configuration.
239      *
240      * @param input
241      * @return the translated and encoded string
242      */
243     public static String translateAndEncode(String input) {
244         String translatedInput = translateVariable(input);
245         String encoding = getEncodingFromConfiguration();
246 
247         try {
248             return URLEncoder.encode(translatedInput, encoding);
249         } catch (UnsupportedEncodingException e) {
250             LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
251             return translatedInput;
252         }
253     }
254     
255     public static String translateAndDecode(String input) {
256     	String translatedInput = translateVariable(input);
257     	String encoding = getEncodingFromConfiguration();
258 
259         try {
260             return URLDecoder.decode(translatedInput, encoding);
261         } catch (UnsupportedEncodingException e) {
262             LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
263             return translatedInput;
264         }
265     }
266     
267     private static String translateVariable(String input) {
268     	ValueStack valueStack = ServletActionContext.getContext().getValueStack();
269         String output = TextParseUtil.translateVariables(input, valueStack);
270         return output;
271     }
272     
273     private static String getEncodingFromConfiguration() {
274     	final String encoding;
275         if (Settings.isSet(StrutsConstants.STRUTS_I18N_ENCODING)) {
276             encoding = Settings.get(StrutsConstants.STRUTS_I18N_ENCODING);
277         } else {
278             encoding = "UTF-8";
279         }
280         return encoding;
281     }
282     
283     public static Map parseQueryString(String queryString) {
284     	Map queryParams = new LinkedHashMap();
285     	if (queryString != null) {
286     		String[] params = queryString.split("&");
287     		for (int a=0; a< params.length; a++) {
288     			if (params[a].trim().length() > 0) {
289     				String[] tmpParams = params[a].split("=");
290     				String paramName = null;
291     				String paramValue = "";
292     				if (tmpParams.length > 0) {
293     					paramName = tmpParams[0];
294     				}
295     				if (tmpParams.length > 1) {
296     					paramValue = tmpParams[1];
297     				}
298     				if (paramName != null) {
299     					String translatedParamValue = translateAndDecode(paramValue);
300     					queryParams.put(paramName, translatedParamValue);
301     				}
302     			}
303     		}
304     	}
305     	return queryParams;
306     }
307 }