View Javadoc

1   /*
2    * $Id: UrlHelper.java 486508 2006-12-13 06:19:43Z mrdon $
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.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT))
107             {
108                 link.append(":");
109                 link.append(scheme.equals("http") ? httpPort : httpsPort);
110             }
111         }
112         else if (
113            (scheme != null) && !scheme.equals(request.getScheme())) {
114             changedScheme = true;
115             link.append(scheme);
116             link.append("://");
117             link.append(request.getServerName());
118 
119             if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT))
120             {
121                 link.append(":");
122                 link.append(scheme.equals("http") ? httpPort : httpsPort);
123             }
124         }
125 
126         if (action != null) {
127             // Check if context path needs to be added
128             // Add path to absolute links
129             if (action.startsWith("/") && includeContext) {
130                 String contextPath = request.getContextPath();
131                 if (!contextPath.equals("/")) {
132                     link.append(contextPath);
133                 }
134             } else if (changedScheme) {
135 
136                 // (Applicable to Servlet 2.4 containers)
137                 // If the request was forwarded, the attribute below will be set with the original URL
138                 String uri = (String) request.getAttribute("javax.servlet.forward.request_uri");
139 
140                 // If the attribute wasn't found, default to the value in the request object
141                 if (uri == null) {
142                     uri = request.getRequestURI();
143                 }
144 
145                 link.append(uri.substring(0, uri.lastIndexOf('/') + 1));
146             }
147 
148             // Add page
149             link.append(action);
150         } else {
151             // Go to "same page"
152             String requestURI = (String) request.getAttribute("struts.request_uri");
153 
154             // (Applicable to Servlet 2.4 containers)
155             // If the request was forwarded, the attribute below will be set with the original URL
156             if (requestURI == null) {
157                 requestURI = (String) request.getAttribute("javax.servlet.forward.request_uri");
158             }
159 
160             // If neither request attributes were found, default to the value in the request object
161             if (requestURI == null) {
162                 requestURI = request.getRequestURI();
163             }
164 
165             link.append(requestURI);
166         }
167 
168         //if the action was not explicitly set grab the params from the request
169         buildParametersString(params, link);
170 
171         String result;
172 
173         try {
174             result = encodeResult ? response.encodeURL(link.toString()) : link.toString();
175         } catch (Exception ex) {
176             // Could not encode the URL for some reason
177             // Use it unchanged
178             result = link.toString();
179         }
180 
181         return result;
182     }
183 
184     public static void buildParametersString(Map params, StringBuffer link) {
185         buildParametersString(params, link, AMP);
186     }
187 
188     public static void buildParametersString(Map params, StringBuffer link, String paramSeparator) {
189         if ((params != null) && (params.size() > 0)) {
190             if (link.toString().indexOf("?") == -1) {
191                 link.append("?");
192             } else {
193                 link.append(paramSeparator);
194             }
195 
196             // Set params
197             Iterator iter = params.entrySet().iterator();
198 
199             String[] valueHolder = new String[1];
200 
201             while (iter.hasNext()) {
202                 Map.Entry entry = (Map.Entry) iter.next();
203                 String name = (String) entry.getKey();
204                 Object value = entry.getValue();
205 
206                 String[] values;
207 
208                 if (value instanceof String[]) {
209                     values = (String[]) value;
210                 } else {
211                     valueHolder[0] = value.toString();
212                     values = valueHolder;
213                 }
214 
215                 for (int i = 0; i < values.length; i++) {
216                     if (values[i] != null) {
217                         link.append(name);
218                         link.append('=');
219                         link.append(translateAndEncode(values[i]));
220                     }
221 
222                     if (i < (values.length - 1)) {
223                         link.append(paramSeparator);
224                     }
225                 }
226 
227                 if (iter.hasNext()) {
228                     link.append(paramSeparator);
229                 }
230             }
231         }
232     }
233 
234     /***
235      * Translates any script expressions using {@link com.opensymphony.xwork2.util.TextParseUtil#translateVariables} and
236      * encodes the URL using {@link java.net.URLEncoder#encode} with the encoding specified in the configuration.
237      *
238      * @param input
239      * @return the translated and encoded string
240      */
241     public static String translateAndEncode(String input) {
242         String translatedInput = translateVariable(input);
243         String encoding = getEncodingFromConfiguration();
244 
245         try {
246             return URLEncoder.encode(translatedInput, encoding);
247         } catch (UnsupportedEncodingException e) {
248             LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
249             return translatedInput;
250         }
251     }
252 
253     public static String translateAndDecode(String input) {
254         String translatedInput = translateVariable(input);
255         String encoding = getEncodingFromConfiguration();
256 
257         try {
258             return URLDecoder.decode(translatedInput, encoding);
259         } catch (UnsupportedEncodingException e) {
260             LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
261             return translatedInput;
262         }
263     }
264 
265     private static String translateVariable(String input) {
266         ValueStack valueStack = ServletActionContext.getContext().getValueStack();
267         String output = TextParseUtil.translateVariables(input, valueStack);
268         return output;
269     }
270 
271     private static String getEncodingFromConfiguration() {
272         final String encoding;
273         if (customEncoding != null) {
274             encoding = customEncoding;
275         } else {
276             encoding = "UTF-8";
277         }
278         return encoding;
279     }
280 
281     public static Map parseQueryString(String queryString) {
282         Map queryParams = new LinkedHashMap();
283         if (queryString != null) {
284             String[] params = queryString.split("&");
285             for (int a=0; a< params.length; a++) {
286                 if (params[a].trim().length() > 0) {
287                     String[] tmpParams = params[a].split("=");
288                     String paramName = null;
289                     String paramValue = "";
290                     if (tmpParams.length > 0) {
291                         paramName = tmpParams[0];
292                     }
293                     if (tmpParams.length > 1) {
294                         paramValue = tmpParams[1];
295                     }
296                     if (paramName != null) {
297                         String translatedParamValue = translateAndDecode(paramValue);
298                         queryParams.put(paramName, translatedParamValue);
299                     }
300                 }
301             }
302         }
303         return queryParams;
304     }
305 }