001// Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 002// The Molly framework is freely distributable under the terms of an 003// MIT-style license. For details, see the molly pages web site at: 004// http://www.mollypages.org/. Use, modify, have fun ! 005 006package fc.web.servlet; 007 008import java.util.*; 009import java.util.logging.*; 010import java.io.*; 011import javax.servlet.*; 012import javax.servlet.http.*; 013import java.net.*; 014 015import fc.io.*; 016 017/** 018Misc web related utility functions 019 020@author hursh jain 021**/ 022public final class WebUtil 023{ 024final static Log log = Log.get("fc.web.servlet"); 025 026//--------------------- getParameters ---------------------- 027 028/** 029Gets the specified required initialization parameter from 030the servlet context. If this param is not found, throws a 031permanent {@link javax.servlet.UnavailableException}. 032**/ 033public static final String getRequiredParam 034 (ServletContext context, String name) 035throws ServletException 036 { 037 String param = context.getInitParameter(name); 038 039 if (param == null) { 040 String error = "Required Servlet Init Parameter: '" + name + "' was not found"; 041 log.error(error); 042 throw new UnavailableException(error); 043 } 044 045 return param; 046 } 047 048/** 049Gets the specified initialization parameter from the servlet context. If 050this param is not found, then the specified backup value is returned. 051**/ 052public static final String getParam( 053 ServletContext context, String name, String backup) 054 { 055 String param = context.getInitParameter(name); 056 if (param != null) 057 return param; 058 else 059 return backup; 060 } 061 062/** 063Gets the specified initialization parameter for the specified servlet 064(via it's ServletConfig). Note, servlet init parameters are servlet 065specific whereas context parameters are shared by all servlets within 066that context. If this param is not found, throws a permanent {@link 067javax.servlet.UnavailableException}. 068**/ 069public static final String getRequiredParam(Servlet servlet, String name) 070throws ServletException 071 { 072 ServletConfig config = servlet.getServletConfig(); 073 String param = config.getInitParameter(name); 074 075 if (param == null) { 076 String error = "Required Servlet Init Parameter: '" + name + "' for servlet '" + config.getServletName() + "' was not found"; 077 log.error(error); 078 throw new UnavailableException(error); 079 } 080 081 return param; 082 } 083 084/** 085Gets the specified initialization parameter for the specified servlet 086(via it's ServletConfig). Note, servlet init parameters are servlet 087specific whereas context parameters are shared by all servlets within 088that context. If this param is not found, then the specified backup value 089is returned. 090**/ 091public static final String getParam( 092 Servlet servlet, String name, String backup) 093 { 094 ServletConfig config = servlet.getServletConfig(); 095 String param = config.getInitParameter(name); 096 if (param != null) 097 return param; 098 else 099 return backup; 100 } 101 102/** 103Gets the specified required parameter from the request 104object. If this param is not found, throws a ServletException 105**/ 106public static final String getRequiredParam( 107 HttpServletRequest request, String name) 108throws ServletException 109 { 110 String param = request.getParameter(name); 111 112 if (param == null) { 113 String error = "Required Parameter: '" + name + "' was not found"; 114 log.error(error); 115 throw new ServletException(error); 116 } 117 118 return param; 119 } 120 121/** 122Gets the specified parameter from the request object. 123If this param is not found, returns the backup value. 124**/ 125public static final String getParam( 126 HttpServletRequest request, String name, String backup) 127 { 128 String param = request.getParameter(name); 129 if (param != null) 130 return param; 131 else 132 return backup; 133 } 134 135/** 136The returned value will be <tt>true</tt> if the specified parameter 137is present in the request and is a non-null non-empty string (<b>of 138any value</b>). This is useful for radioboxes and checkboxes. 139**/ 140public static final boolean isSelected( 141 HttpServletRequest request, String name) 142 { 143 String param = request.getParameter(name); 144 if (param == null || param.equals("")) 145 return false; 146 147 return true; 148 } 149 150/** 151Convenience method that returns the specified parameter as a boolean 152value. The returned value will be converted via the 153{@link Boolean#parseBoolean(String)} (for <tt>true</tt>, the 154value should be non-null and equal ignore case to "true"). 155**/ 156public static final boolean getBooleanParameter( 157 HttpServletRequest request, String name) 158 { 159 String param = request.getParameter(name); 160 return Boolean.parseBoolean(param); 161 } 162 163 164//--------------------- getAttributes ---------------------- 165 166/** 167Gets the specified required attribute from the servlet context. If 168this attribute is not found, throws a permanent 169{@link javax.servlet.UnavailableException}. 170**/ 171public static final Object getRequiredAttribute( 172 ServletContext context, String name) 173throws ServletException 174 { 175 Object param = context.getAttribute(name); 176 177 if (param == null) { 178 String error = "Required context attribute: '" + name + "' was not found"; 179 log.error(error); 180 throw new UnavailableException(error); 181 } 182 183 return param; 184 } 185 186/** 187Gets the specified attribute from the servlet context. If this attribute 188is not found, then the specified backup value is returned. 189**/ 190public static final Object getAttribute( 191 ServletContext context, String name, String backup) 192throws ServletException 193 { 194 Object param = context.getAttribute(name); 195 196 if (param != null) 197 return param; 198 else 199 return backup; 200 } 201 202/** 203Gets the specified required attribute from the request object. 204If this param is not found, throws a ServletException. 205**/ 206public static final Object getRequiredAttribute( 207 HttpServletRequest request, String name) 208throws ServletException 209 { 210 Object param = request.getAttribute(name); 211 212 if (param == null) { 213 String error = "Required Parameter: '" + name + "' was not found"; 214 log.error(error); 215 throw new ServletException(error); 216 } 217 218 return param; 219 } 220 221/** 222Gets the specified attribute from the request object. 223If this attribute is not found, returns the backup value. 224**/ 225public static final Object getAttribute( 226 HttpServletRequest request, String name, String backup) 227throws ServletException 228 { 229 Object param = request.getAttribute(name); 230 if (param != null) 231 return param; 232 else 233 return backup; 234 } 235 236//---------------------------------------------------------- 237 238/** 239Returns a HttpSession attribute as a String or null if the attribute 240was absent. 241 242@param name the name of the session attribute 243@throws ClassCastException if the attribute was not a String 244@throws NullPointerException if the specified session or name parameters 245 were null 246**/ 247public static final String getSessionString(HttpSession session, String name) 248 { 249 Object obj = session.getAttribute(name); 250 if (obj != null) 251 return (String) obj; 252 else 253 return null; 254 } 255 256/** 257Returns the cookie with the specified name or <tt>null</tt> if no cookie 258was found. 259*/ 260public static Cookie getCookie(HttpServletRequest req, String cookieName) 261 { 262 Cookie[] cookies = req.getCookies(); 263 264 if (cookies == null) 265 return null; 266 267 for (int n = 0; n < cookies.length; n++) 268 { 269 if (cookies[n].getName().equals(cookieName)) 270 { 271 return cookies[n]; 272 } 273 } 274 return null; 275 } 276 277/** 278Redirects the request (server side redirect) to the specified relative URL 279via the {@link javax.servlet.ServletRequest#getRequestDispatcher}. See 280{@link javax.servlet.RequestDispatcher#forward} for restrictions while 281forwarding to another page (in particular, the response must not have been 282committed before calling this method). 283<p> 284The calling code <b>must</b> have a <tt>return</tt> statement immediately 285after calling this method, otherwise RequestDispatching will probably not 286work as intended. 287 288@param req the current request 289@param res the current response 290@param URL The pathname specified may be relative, although it 291 cannot extend outside the current servlet context. If the 292 path begins with a "/" it is interpreted as starting from 293 the root of the current context. (i.e., the webapp context, 294 if present, does not need to be specified). 295**/ 296public static final void forward ( HttpServletRequest req, 297 HttpServletResponse res, 298 String URL) 299throws ServletException, IOException 300 { 301 RequestDispatcher rd = req.getRequestDispatcher(URL); 302 if (log.canLog(Log.DEBUG)) { 303 StringBuffer buf = getRequestURL(req); 304 log.bug(buf, "forwarding to page: ", URL); 305 } 306 rd.forward(req, res); 307 } 308 309/** 310Redirects the browser to the specified URL via a client side redirect URL. 311Automatically creates a full URL <u>(including the webapp context path)</u> 312suitable for this purpose. This method is a thin wrapper around {@link 313javax.servlet.http.HttpServletResponse#sendRedirect Response.sentRedirect} 314<p> 315Session information is preserved if using container provided URL-based sessions. 316<p> 317<u>If the response has already been committed, this method throws an 318<tt>IllegalStateException</tt></u>. After using this method, the response should be 319considered to be committed and should not be written to. 320 321@param req the current request 322@param res the current response 323@param location See 324 {@link javax.servlet.http.HttpResponse#sendRedirect}. 325 Essentially, the location can be relative to the 326 specified request's URI or relative to the 327 context root if it contains a leading '/' 328**/ 329public static final void clientRedirect( 330 HttpServletRequest req, HttpServletResponse res, String location) 331throws ServletException, IOException 332 { 333 String redirectURL = res.encodeRedirectURL( 334 absolutePath(req, location)); 335 if (log.canLog(Log.DEBUG)) { 336 StringBuffer buf = getRequestURL(req); 337 log.bug(buf, "redirecting to page: ", redirectURL); 338 } 339 res.sendRedirect(redirectURL); 340 } 341 342/** 343Creates an absolute path starting from the web document root directory. It 344does so by prepending the webapp context path (if any) of the specified 345request to the specified path. The path is <b>not</b> URL encoded with 346session informtion (see {@link #absoluteEncPath}). 347<p> 348This method should be used for all HTML links (in html pages and forms) 349and also for client side redirects. This ensures the ability to move the calling code 350to a different web app (other than the default root ("/") web app). If 351it's certain that there will always only be 1 web app (the default) 352then calling this method is not necessary. 353<p> 354Note also that server-side redirects and includes (with RequestDispatcher) 355should *not* use this method since all such server side redirects etc 356automatically work as expected inside the web app context and are always 357relative to the web app context itself. 358 359@param req the current HttpServletRequest 360@param path an absolute path starting from the root of 361 the context associated with the request. 362 If the current webapp (context) is <tt>/foo</tt> and 363 the specified path is <tt>/bar</tt>, then this 364 method will return <tt>/foo/bar</tt> 365**/ 366public static final String absolutePath(HttpServletRequest req, String path) 367 { 368 return req.getContextPath() + path; 369 } 370 371/** 372URL encodes and returns the path obtained via {@link #absolutePath}. 373**/ 374public static final String absoluteEncPath( 375 HttpServletRequest req, HttpServletResponse res, String path) 376 { 377 return res.encodeURL(absolutePath(req, path)); 378 } 379 380/** 381@return the full requested URL including any query parameters. 382 (the {@link 383 javax.servlet.Http.HttpServletRequest.getRequestURL() RequestURL} 384 method in HttpServletRequest does not return the query part of the URL) 385**/ 386public static final StringBuffer getRequestURL(HttpServletRequest req) 387 { 388 StringBuffer buf = req.getRequestURL(); 389 String qs = req.getQueryString(); 390 if (qs !=null) { 391 buf.append('?'); 392 buf.append(qs); 393 } 394 return buf; 395 } 396 397 398//== HTML Form related ========================== 399 400private static final String confirm = "confirm"; 401private static final String cancel = "cancel"; 402 403/** 404Returns <tt>true</tt> only if a request parameter with the 405name <tt>confirm</tt> is seen. Forms can set a submit button 406with this name to signal a confirm request. 407**/ 408public static final boolean requestCancelled(HttpServletRequest req) { 409 String str = req.getParameter(cancel); 410 return (str != null); //testing for key not value 411 } 412 413/** 414Returns <tt>true</tt> only if a request parameter with the 415name <tt>cancel</tt> is seen. Forms can set a submit button 416with this name to signal a cancel request. 417**/ 418public static final boolean requestConfirmed(HttpServletRequest req) { 419 String str = req.getParameter(confirm); 420 return (str != null); //testing for key not value 421 } 422 423/** 424writes all request params received in the specied request to 425<tt>System.out</tt>. Useful for debugging. 426**/ 427public static final void debugRequestParams(HttpServletRequest req) 428 { 429 debugRequestParams(req, System.out); 430 } 431 432 433/** 434writes all request params received in the specied request to 435the specified output stream. Useful for debugging. 436**/ 437public static final void debugRequestParams(HttpServletRequest req, OutputStream out) 438 { 439 System.out.print("Request params/"); 440 System.out.print(Thread.currentThread().getName()); 441 System.out.print(" "); 442 443 Iterator i = req.getParameterMap().entrySet().iterator(); 444 while (i.hasNext()) { 445 Map.Entry me = (Map.Entry) i.next(); 446 System.out.print(me.getKey()); 447 System.out.print(":"); 448 System.out.print(Arrays.toString((String[])me.getValue())); 449 450 if (i.hasNext()) 451 System.out.print(", "); 452 else 453 System.out.println(); 454 } 455 } 456 457 458/** 459set expire headers to cover all cases 460**/ 461public static final void setExpireHeaders(HttpServletResponse res) 462 { 463 // Set standard HTTP/1.1 no-cache headers. 464 res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); 465 // Set IE extended HTTP/1.1 no-cache headers (use addHeader). 466 res.addHeader("Cache-Control", "post-check=0, pre-check=0"); 467 // Set standard HTTP/1.0 no-cache header. 468 res.setHeader("Pragma", "no-cache"); 469 //expire in past 470 res.setHeader("Expires", "-1"); 471 } 472 473/* 474Parse a query parameter string (useful for things like websocket and custom 475servers. The query param should be url form encoded and is decoded using 476UTF-8 (via {@link java.net.URLDecoder}). Returns a map containing each 477<tt>name:value</tt> pair 478*/ 479public static Map parseQuery(String query) throws UnsupportedEncodingException 480 { 481 Map m = new HashMap(); 482 String[] params = query.split("&"); 483 for (int n = 0; n < params.length; n++) { 484 String param = params[n]; 485 int i = param.indexOf("="); 486 m.put( 487 URLDecoder.decode(param.substring(0, i), "UTF-8"), 488 URLDecoder.decode(param.substring(i + 1), "UTF-8")); 489 } 490 return m; 491 } 492 493/** 494Returns true if the client is a mobile device 495*/ 496public static boolean isMobileClient(HttpServletRequest req) 497 { 498 //https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent 499 500 //name is case insensitve (in servlet and http spec), different browsers send different cases so that's good 501 String user_agent = req.getHeader("user-agent"); 502 return user_agent != null && user_agent.indexOf("obile") > 0; //Mobile or mobile 503 } 504 505/** 506Returns true if the client is an iOS mobile device. 507*/ 508public static boolean isIOSClient(HttpServletRequest req) 509 { 510 //https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent 511 512 //name is case insensitve (in servlet and http spec), different browsers send different cases so that's good 513 String user_agent = req.getHeader("user-agent"); 514 return user_agent != null && user_agent.indexOf("obile") > 0 && user_agent.indexOf("afari") > 0; 515 } 516 517} //~class WebUtil 518