📄 servlets.java
字号:
/* Servlets.java{{IS_NOTE Purpose: Description: History: 90/12/10 22:24:28, Create, Tom M. Yeh.}}IS_NOTECopyright (C) 2001 Potix Corporation. All Rights Reserved.{{IS_RIGHT This program is distributed under GPL Version 2.0 in the hope that it will be useful, but WITHOUT ANY WARRANTY.}}IS_RIGHT*/package org.zkoss.web.servlet;import java.util.List;import java.util.LinkedList;import java.util.ArrayList;import java.util.Iterator;import java.util.Map;import java.util.HashMap;import java.util.Collections;import java.util.Locale;import java.util.Properties;import java.io.InputStream;import java.io.IOException;import java.io.StringWriter;import java.io.PrintWriter;import java.io.UnsupportedEncodingException;import java.net.URL;import java.net.MalformedURLException;import javax.servlet.ServletContext;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.ServletException;import javax.servlet.RequestDispatcher;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpServletRequest;import org.zkoss.mesg.MCommon;import org.zkoss.lang.D;import org.zkoss.lang.Objects;import org.zkoss.lang.Classes;import org.zkoss.lang.Exceptions;import org.zkoss.lang.SystemException;import org.zkoss.util.Checksums;import org.zkoss.util.CacheMap;import org.zkoss.util.CollectionsX;import org.zkoss.util.Locales;import org.zkoss.util.logging.Log;import org.zkoss.util.resource.Locator;import org.zkoss.util.resource.Locators;import org.zkoss.util.resource.PropertyBundle;import org.zkoss.idom.Element;import org.zkoss.idom.input.SAXBuilder;import org.zkoss.web.Attributes;import org.zkoss.web.servlet.http.Encodes;import org.zkoss.web.util.resource.ExtendletContext;import org.zkoss.web.util.resource.ServletContextLocator;/** * The servlet relevant utilities. * * @author tomyeh * @see org.zkoss.web.servlet.http.Https * @see org.zkoss.web.servlet.Charsets */public class Servlets {// private static final Log log = Log.lookup(Servlets.class); private static final boolean _svl24, _svl23; static { boolean b = false; try { ServletResponse.class.getMethod("getContentType", new Class[0]); b = true; } catch (Throwable ex) { } _svl24 = b; if (!b) { try { HttpSession.class.getMethod("getServletContext", new Class[0]); b = true; } catch (Throwable ex) { } } _svl23 = b; } /** Utilities; no instantiation required. */ protected Servlets() {} /** Returns whether a URL starts with xxx://, mailto:, about:, * javascript: */ public static final boolean isUniversalURL(String uri) { if (uri == null || uri.length() == 0) return false; final char cc = uri.charAt(0); return cc >= 'a' && cc <= 'z' && (uri.indexOf("://") > 0 || uri.startsWith("mailto:") || uri.startsWith("javascript:") || uri.startsWith("about:")); } /** Returns whether the current Web server supports Servlet 2.4 or above. * * @since 3.0.0 */ public static final boolean isServlet24() { return _svl24; } /** Returns whether the current Web server supports Servlet 2.3 or above. * Thus, if {@link #isServlet24} returns true, {@link #isServlet23} * must return true, too. * * @since 3.0.0 */ public static final boolean isServlet23() { return _svl23; } //-- resource locator --// /** Locates a page based on the specified Locale. It never returns null. * * <p>If an URI contains "*", it will be replaced with a proper Locale. * For example, if the current Locale is zh_TW and the resource is * named "ab*.cd", then it searches "ab_zh_TW.cd", "ab_zh.cd" and * then "ab.cd", until any of them is found. * * <blockquote>Note: "*" must be right before ".", or the last character. * For example, "ab*.cd" and "ab*" are both correct, while * "ab*cd" and "ab*\/cd" are ignored.</blockquote> * * <p>If an URI contains two "*", the first "*" will be replaced with * a browser code and the second with a proper locale. * The browser code depends on what browser * the user are used to visit the web site. * Currently, the code for Internet Explorer is "ie", Safari is "saf", * Opera is "opr" and all others are "moz". * Thus, in the above example, if the resource is named "ab**.cd" * and Firefox is used, then it searches "abmoz_zh_TW.cd", "abmoz_zh.cd" * and then "abmoz.cd", until any of them is found. * * <p>Note: it assumes the path as name_lang_cn_var.ext where * ".ext" is optional. Example, my_zh_tw.html.jsp. * * <p>Note: unlike {@link Encodes#encodeURL(ServletContext, ServletRequest, ServletResponse, String)}, * it always locates the Locale, without handling "*". * * @param ctx the servlet context to locate pages * @param pgpath the page path excluding servlet name. It is OK to have * the query string. It might contain "*" for current browser code and Locale. * @param locator the locator used to locate resource. If null, ctx * is assumed. * @return pgpath if the original one matches; others if locale matches; * never null */ public static final String locate(ServletContext ctx, ServletRequest request, String pgpath, Locator locator) throws ServletException { if (isUniversalURL(pgpath)) return pgpath; final int jquest = pgpath.indexOf('?'); final int f = pgpath.indexOf('*'); if (f < 0 || (jquest >= 0 && f > jquest)) return pgpath; //optimize the case that no "*" at all final String qstr; if (jquest >= 0) { qstr = pgpath.substring(jquest); pgpath = pgpath.substring(0, jquest); } else { qstr = null; } //by browser? int l = pgpath.lastIndexOf('*'); if (l > f) { //two '*' final String bc = Servlets.isExplorer(request) ? "ie": Servlets.isSafari(request) ? "saf": Servlets.isOpera(request) ? "opr": "moz"; l += bc.length() - 1; pgpath = pgpath.substring(0, f) + bc + pgpath.substring(f + 1); } //remove "*" pgpath = pgpath.substring(0, l) + pgpath.substring(l + 1); //remove //by locale? 1) before the first dot, 2) the last char if no dot boolean byLocale = l == pgpath.length() || (pgpath.charAt(l) == '.' && pgpath.indexOf('/', l + 1) < 0); if (byLocale) { //make sure no dot before it for (int j = l; --j >= 0;) { final char cc = pgpath.charAt(j); if (cc == '.') { byLocale = false; break; } else if (cc == '/') { break; } } } if (!byLocale) return qstr != null ? pgpath + qstr: pgpath; //not by locale final String PGPATH_CACHE = "s_pgpath_cache"; Map map = (Map)ctx.getAttribute(PGPATH_CACHE); if (map == null) { map = Collections.synchronizedMap( //10 min new CacheMap(500, 10*60*1000)); ctx.setAttribute(PGPATH_CACHE, map); } final Locale locale = Locales.getCurrent(); final URIIndex index = new URIIndex(pgpath, locale); String uri = (String)map.get(index); if (uri == null) { final Locators.URLLocation loc = Locators.locate(pgpath, locale, locator != null ? locator: new ServletContextLocator(ctx)); uri = loc != null ? loc.file: pgpath; map.put(index, uri); } return qstr != null ? uri + qstr: uri; } private static class URIIndex { private final String _uri; private final Locale _locale; private URIIndex(String uri, Locale locale) { if (uri == null || locale == null) throw new IllegalArgumentException("null"); _uri = uri; _locale = locale; } public int hashCode() { return _uri.hashCode(); } public boolean equals(Object o) { //To speed up, don't check whether o is the right class final URIIndex idx = (URIIndex)o; return _uri.equals(idx._uri) && _locale.equals(idx._locale); } } /** Returns whether the client is a robot (such as Web crawlers). * * <p>Because there are too many robots, it returns true if the user-agent * is not recognized. */ public static final boolean isRobot(ServletRequest req) { String agt = req instanceof HttpServletRequest ? ((HttpServletRequest)req).getHeader("user-agent"): null; if (agt == null) return false; agt = agt.toLowerCase(); return agt.indexOf("msie") < 0 && agt.indexOf("opera") < 0 && agt.indexOf("gecko/") < 0 && agt.indexOf("safari") < 0; } /** Returns whether the browser is Internet Explorer. * If true, it also implies {@link #isExplorer7} is true. */ public static final boolean isExplorer(ServletRequest req) { String agt = req instanceof HttpServletRequest ? ((HttpServletRequest)req).getHeader("user-agent"): null; if (agt == null) return false; agt = agt.toLowerCase(); return agt.indexOf("msie") >= 0 && agt.indexOf("opera") < 0; } /** Returns whether the browser is Explorer 7 or later. */ public static final boolean isExplorer7(ServletRequest req) { String agt = req instanceof HttpServletRequest ? ((HttpServletRequest)req).getHeader("user-agent"): null; if (agt == null) return false; agt = agt.toLowerCase(); return agt.indexOf("msie 7") >= 0; } /** Returns whether the browser is Gecko based, such as Mozilla, Firefox and Camino */ public static final boolean isGecko(ServletRequest req) { String agt = req instanceof HttpServletRequest ? ((HttpServletRequest)req).getHeader("user-agent"): null; if (agt == null) return false; agt = agt.toLowerCase(); return agt.indexOf("gecko/") >= 0 && agt.indexOf("safari") < 0; } /** Returns whether the browser is Safari. */ public static final boolean isSafari(ServletRequest req) { String agt = req instanceof HttpServletRequest ? ((HttpServletRequest)req).getHeader("user-agent"): null; if (agt == null) return false; agt = agt.toLowerCase(); return agt.indexOf("safari") >= 0; } /** Returns whether the browser is Opera. */ public static final boolean isOpera(ServletRequest req) { String agt = req instanceof HttpServletRequest ? ((HttpServletRequest)req).getHeader("user-agent"): null; if (agt == null) return false; agt = agt.toLowerCase(); return agt.indexOf("opera") >= 0; } /** Returns whether the client is a mobile device supporting MIL * (Mobile Interactive Language). * @since 2.4.0 */ public static final boolean isMilDevice(ServletRequest req) { String agt = req instanceof HttpServletRequest ? ((HttpServletRequest)req).getHeader("user-agent"): null; if (agt == null) return false; agt = agt.toLowerCase(); return agt.indexOf("zk") >= 0 && agt.indexOf("mobile") >= 0 && agt.indexOf("rmil") >= 0; } /** * Tests whether this page is included by another page. */ public static final boolean isIncluded(ServletRequest request) { return request.getAttribute(Attributes.INCLUDE_CONTEXT_PATH) != null; } /** * Tests whether this page is forwarded by another page. */ public static final boolean isForwarded(ServletRequest request) { return request.getAttribute(Attributes.FORWARD_CONTEXT_PATH) != null; } /** * Forward to the specified URI. * It enhances RequestDispatcher in the following ways. * * <ul> * <li>It handles "~ctx"" where ctx is the context path of the * foreign context. It is called foriegn URI.</li> * <li>It detects whether the page calling this method * is included by another servlet/page. If so, it uses * RequestDispatcher.include() instead of RequestDispatcher.forward().</li> * <li>The forwarded page could accept additional parameters -- * acutually converting parameters to a query string * and appending it to uri.</li> * <li>In additions, it does HTTP encoding, i.e., converts '+' and other * characters to comply HTTP.</li> * </ul> * * <p>NOTE: don't include query parameters in uri. * * @param ctx the servlet context. If null, uri cannot be foreign URI. * It is ignored if URI is relevant (neither starts with '/' nor '~'). * @param uri the URI to include. It is OK to relevant (without leading * '/'). If starts with "/", the context path of request is assumed. * To reference to foreign context, use "~ctx" where ctx is the * context path of the foreign context (without leading '/'). * If it could be any context path recognized by the Web container or * any name registered with {@link #addExtendletContext}. * @param params the parameter map; null to ignore * @param mode one of {@link #OVERWRITE_URI}, {@link #IGNORE_PARAM}, * and {@link #APPEND_PARAM}. It defines how to handle if both uri * and params contains the same parameter. */ public static final void forward(ServletContext ctx, ServletRequest request, ServletResponse response, String uri, Map params, int mode) throws IOException, ServletException {// if (D.ON && log.debugable()) log.debug("Forwarding "+uri); //include or foward depending whether this page is included or not if (isIncluded(request)) { include(ctx, request, response, uri, params, mode); return; } final RequestDispatcher disp = getRequestDispatcher(ctx, request, uri, params, mode); if (disp == null) throw new ServletException("No dispatcher available to forward to "+uri); if (mode == PASS_THRU_ATTR && params != null && !params.isEmpty()) { final Map old = setPassThruAttr(request, params); try { disp.forward(request, response); } catch (ClassCastException ex) { //Tom M. Yeh, 2006/09/21: Bug 1548478 //Cause: http://issues.apache.org/bugzilla/show_bug.cgi?id=39417 //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -