View Javadoc

1   /*
2    * $Id: UrlHelper.java 508879 2007-02-18 06:32:02Z tschneider $
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.Collections;
28  import java.util.Iterator;
29  import java.util.LinkedHashMap;
30  import java.util.Map;
31  
32  import javax.servlet.http.HttpServletRequest;
33  import javax.servlet.http.HttpServletResponse;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.struts2.ServletActionContext;
38  import org.apache.struts2.StrutsConstants;
39  
40  import com.opensymphony.xwork2.ActionContext;
41  import com.opensymphony.xwork2.inject.Inject;
42  import com.opensymphony.xwork2.util.TextParseUtil;
43  import com.opensymphony.xwork2.util.ValueStack;
44  
45  
46  /***
47   * UrlHelper
48   *
49   */
50  public class UrlHelper {
51      private static final Log LOG = LogFactory.getLog(UrlHelper.class);
52  
53      /***
54       * Default HTTP port (80).
55       */
56      private static final int DEFAULT_HTTP_PORT = 80;
57  
58      /***
59       * Default HTTPS port (443).
60       */
61      private static final int DEFAULT_HTTPS_PORT = 443;
62  
63      private static final String AMP = "&";
64      
65      private static int httpPort = DEFAULT_HTTP_PORT;
66      private static int httpsPort = DEFAULT_HTTPS_PORT;
67      private static String customEncoding;
68      
69      @Inject(StrutsConstants.STRUTS_URL_HTTP_PORT)
70      public static void setHttpPort(String val) {
71          httpPort = Integer.parseInt(val);
72      }
73      
74      @Inject(StrutsConstants.STRUTS_URL_HTTPS_PORT)
75      public static void setHttpsPort(String val) {
76          httpsPort = Integer.parseInt(val);
77      }
78      
79      @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
80      public static void setCustomEncoding(String val) {
81          customEncoding = val;
82      }
83  
84      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params) {
85          return buildUrl(action, request, response, params, null, true, true);
86      }
87  
88      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult) {
89          return buildUrl(action, request, response, params, scheme, includeContext, encodeResult, false);
90      }
91  
92      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort) {
93          StringBuffer link = new StringBuffer();
94  
95          boolean changedScheme = false;
96  
97          // only append scheme if it is different to the current scheme *OR*
98          // if we explicity want it to be appended by having forceAddSchemeHostAndPort = true
99          if (forceAddSchemeHostAndPort) {
100             String reqScheme = request.getScheme();
101             changedScheme = true;
102             link.append(scheme != null ? scheme : reqScheme);
103             link.append("://");
104             link.append(request.getServerName());
105 
106             if (scheme != null) {
107                 if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT))
108                 {
109                     link.append(":");
110                     link.append(scheme.equals("http") ? httpPort : httpsPort);
111                 }
112             }
113         }
114         else if (
115            (scheme != null) && !scheme.equals(request.getScheme())) {
116             changedScheme = true;
117             link.append(scheme);
118             link.append("://");
119             link.append(request.getServerName());
120 
121             if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT))
122             {
123                 link.append(":");
124                 link.append(scheme.equals("http") ? httpPort : httpsPort);
125             }
126         }
127 
128         if (action != null) {
129             // Check if context path needs to be added
130             // Add path to absolute links
131             if (action.startsWith("/") && includeContext) {
132                 String contextPath = request.getContextPath();
133                 if (!contextPath.equals("/")) {
134                     link.append(contextPath);
135                 }
136             } else if (changedScheme) {
137 
138                 // (Applicable to Servlet 2.4 containers)
139                 // If the request was forwarded, the attribute below will be set with the original URL
140                 String uri = (String) request.getAttribute("javax.servlet.forward.request_uri");
141 
142                 // If the attribute wasn't found, default to the value in the request object
143                 if (uri == null) {
144                     uri = request.getRequestURI();
145                 }
146 
147                 link.append(uri.substring(0, uri.lastIndexOf('/') + 1));
148             }
149 
150             // Add page
151             link.append(action);
152         } else {
153             // Go to "same page"
154             String requestURI = (String) request.getAttribute("struts.request_uri");
155 
156             // (Applicable to Servlet 2.4 containers)
157             // If the request was forwarded, the attribute below will be set with the original URL
158             if (requestURI == null) {
159                 requestURI = (String) request.getAttribute("javax.servlet.forward.request_uri");
160             }
161 
162             // If neither request attributes were found, default to the value in the request object
163             if (requestURI == null) {
164                 requestURI = request.getRequestURI();
165             }
166 
167             link.append(requestURI);
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 (customEncoding != null) {
276             encoding = customEncoding;
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 }