View Javadoc

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