View Javadoc

1   /*
2    * $Id: UrlHelper.java 517363 2007-03-12 20:05:02Z husted $
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      @Inject(StrutsConstants.STRUTS_URL_HTTP_PORT)
71      public static void setHttpPort(String val) {
72          httpPort = Integer.parseInt(val);
73      }
74  
75      @Inject(StrutsConstants.STRUTS_URL_HTTPS_PORT)
76      public static void setHttpsPort(String val) {
77          httpsPort = Integer.parseInt(val);
78      }
79  
80      @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
81      public static void setCustomEncoding(String val) {
82          customEncoding = val;
83      }
84  
85      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params) {
86          return buildUrl(action, request, response, params, null, true, true);
87      }
88  
89      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult) {
90          return buildUrl(action, request, response, params, scheme, includeContext, encodeResult, false);
91      }
92  
93      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort) {
94          StringBuffer link = new StringBuffer();
95  
96          boolean changedScheme = false;
97  
98          // only append scheme if it is different to the current scheme *OR*
99          // if we explicity want it to be appended by having forceAddSchemeHostAndPort = true
100         if (forceAddSchemeHostAndPort) {
101             String reqScheme = request.getScheme();
102             changedScheme = true;
103             link.append(scheme != null ? scheme : reqScheme);
104             link.append("://");
105             link.append(request.getServerName());
106 
107             if (scheme != null) {
108                 if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT))
109                 {
110                     link.append(":");
111                     link.append(scheme.equals("http") ? httpPort : httpsPort);
112                 }
113             }
114         }
115         else if (
116            (scheme != null) && !scheme.equals(request.getScheme())) {
117             changedScheme = true;
118             link.append(scheme);
119             link.append("://");
120             link.append(request.getServerName());
121 
122             if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT))
123             {
124                 link.append(":");
125                 link.append(scheme.equals("http") ? httpPort : httpsPort);
126             }
127         }
128 
129         if (action != null) {
130             // Check if context path needs to be added
131             // Add path to absolute links
132             if (action.startsWith("/") && includeContext) {
133                 String contextPath = request.getContextPath();
134                 if (!contextPath.equals("/")) {
135                     link.append(contextPath);
136                 }
137             } else if (changedScheme) {
138 
139                 // (Applicable to Servlet 2.4 containers)
140                 // If the request was forwarded, the attribute below will be set with the original URL
141                 String uri = (String) request.getAttribute("javax.servlet.forward.request_uri");
142 
143                 // If the attribute wasn't found, default to the value in the request object
144                 if (uri == null) {
145                     uri = request.getRequestURI();
146                 }
147 
148                 link.append(uri.substring(0, uri.lastIndexOf('/') + 1));
149             }
150 
151             // Add page
152             link.append(action);
153         } else {
154             // Go to "same page"
155             String requestURI = (String) request.getAttribute("struts.request_uri");
156 
157             // (Applicable to Servlet 2.4 containers)
158             // If the request was forwarded, the attribute below will be set with the original URL
159             if (requestURI == null) {
160                 requestURI = (String) request.getAttribute("javax.servlet.forward.request_uri");
161             }
162 
163             // If neither request attributes were found, default to the value in the request object
164             if (requestURI == null) {
165                 requestURI = request.getRequestURI();
166             }
167 
168             link.append(requestURI);
169         }
170 
171         //if the action was not explicitly set grab the params from the request
172         buildParametersString(params, link);
173 
174         String result;
175 
176         try {
177             result = encodeResult ? response.encodeURL(link.toString()) : link.toString();
178         } catch (Exception ex) {
179             // Could not encode the URL for some reason
180             // Use it unchanged
181             result = link.toString();
182         }
183 
184         return result;
185     }
186 
187     public static void buildParametersString(Map params, StringBuffer link) {
188         buildParametersString(params, link, AMP);
189     }
190 
191     public static void buildParametersString(Map params, StringBuffer link, String paramSeparator) {
192         if ((params != null) && (params.size() > 0)) {
193             if (link.toString().indexOf("?") == -1) {
194                 link.append("?");
195             } else {
196                 link.append(paramSeparator);
197             }
198 
199             // Set params
200             Iterator iter = params.entrySet().iterator();
201 
202             String[] valueHolder = new String[1];
203 
204             while (iter.hasNext()) {
205                 Map.Entry entry = (Map.Entry) iter.next();
206                 String name = (String) entry.getKey();
207                 Object value = entry.getValue();
208 
209                 String[] values;
210 
211                 if (value instanceof String[]) {
212                     values = (String[]) value;
213                 } else {
214                     valueHolder[0] = value.toString();
215                     values = valueHolder;
216                 }
217 
218                 for (int i = 0; i < values.length; i++) {
219                     if (values[i] != null) {
220                         link.append(name);
221                         link.append('=');
222                         link.append(translateAndEncode(values[i]));
223                     }
224 
225                     if (i < (values.length - 1)) {
226                         link.append(paramSeparator);
227                     }
228                 }
229 
230                 if (iter.hasNext()) {
231                     link.append(paramSeparator);
232                 }
233             }
234         }
235     }
236 
237     /***
238      * Translates any script expressions using {@link com.opensymphony.xwork2.util.TextParseUtil#translateVariables} and
239      * encodes the URL using {@link java.net.URLEncoder#encode} with the encoding specified in the configuration.
240      *
241      * @param input
242      * @return the translated and encoded string
243      */
244     public static String translateAndEncode(String input) {
245         String translatedInput = translateVariable(input);
246         String encoding = getEncodingFromConfiguration();
247 
248         try {
249             return URLEncoder.encode(translatedInput, encoding);
250         } catch (UnsupportedEncodingException e) {
251             LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
252             return translatedInput;
253         }
254     }
255 
256     public static String translateAndDecode(String input) {
257         String translatedInput = translateVariable(input);
258         String encoding = getEncodingFromConfiguration();
259 
260         try {
261             return URLDecoder.decode(translatedInput, encoding);
262         } catch (UnsupportedEncodingException e) {
263             LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
264             return translatedInput;
265         }
266     }
267 
268     private static String translateVariable(String input) {
269         ValueStack valueStack = ServletActionContext.getContext().getValueStack();
270         String output = TextParseUtil.translateVariables(input, valueStack);
271         return output;
272     }
273 
274     private static String getEncodingFromConfiguration() {
275         final String encoding;
276         if (customEncoding != null) {
277             encoding = customEncoding;
278         } else {
279             encoding = "UTF-8";
280         }
281         return encoding;
282     }
283 
284     public static Map parseQueryString(String queryString) {
285         Map queryParams = new LinkedHashMap();
286         if (queryString != null) {
287             String[] params = queryString.split("&");
288             for (int a=0; a< params.length; a++) {
289                 if (params[a].trim().length() > 0) {
290                     String[] tmpParams = params[a].split("=");
291                     String paramName = null;
292                     String paramValue = "";
293                     if (tmpParams.length > 0) {
294                         paramName = tmpParams[0];
295                     }
296                     if (tmpParams.length > 1) {
297                         paramValue = tmpParams[1];
298                     }
299                     if (paramName != null) {
300                         String translatedParamValue = translateAndDecode(paramValue);
301 
302                         if(queryParams.containsKey(paramName)) {
303                             // WW-1619 append new param value to existing value(s)
304                             Object currentParam = queryParams.get(paramName);
305                             if(currentParam instanceof String) {
306                                 queryParams.put(paramName, new String[] {
307                                         (String) currentParam, translatedParamValue});
308                             } else {
309                                 String currentParamValues[] = (String[]) currentParam;
310                                 List paramList = new ArrayList(Arrays
311                                     .asList(currentParamValues));
312                                 paramList.add(translatedParamValue);
313                                 String newParamValues[] = new String[paramList
314                                     .size()];
315                                 queryParams.put(paramName, paramList
316                                     .toArray(newParamValues));
317                             }
318                         } else {
319                             queryParams.put(paramName, translatedParamValue);
320                         }
321                     }
322                 }
323             }
324         }
325         return queryParams;
326     }
327 }