001: /* Charsets.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Wed Jan 5 13:55:30 2005, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2004 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.web.servlet;
020:
021: import java.util.Locale;
022:
023: import javax.servlet.ServletRequest;
024: import javax.servlet.ServletResponse;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpServletResponse;
027: import javax.servlet.http.HttpSession;
028:
029: import org.zkoss.lang.Exceptions;
030: import org.zkoss.lang.Objects;
031: import org.zkoss.lang.SystemException;
032: import org.zkoss.util.Locales;
033: import org.zkoss.util.logging.Log;
034:
035: import org.zkoss.web.Attributes;
036:
037: /**
038: * Utilities to handle characters
039: *
040: * @author tomyeh
041: */
042: public class Charsets {
043: private static final Log log = Log.lookup(Charsets.class);
044: private static final String ATTR_SETUP = "org.zkoss.web.charset.setup";
045:
046: private static final String _uriCharset;
047: static {
048: String cs = System.getProperty("org.zkoss.web.uri.charset",
049: null);
050: if (cs == null || cs.length() == 0)
051: cs = "UTF-8"; //Default: UTF-8
052: _uriCharset = cs;
053: }
054:
055: /** Returns the charset used to encode URI and query string.
056: */
057: public static final String getURICharset() {
058: return _uriCharset;
059: }
060:
061: /** Sets up the charset for the request and response based on
062: * {@link #getPreferredLocale}. After setting up, you shall invoke
063: * {@link #cleanup} before exiting.
064: *
065: * <pre><code> final Object old = setup(request, response, null);
066: * try {
067: * ....
068: * } finally {
069: * cleanup(request, old);
070: * }
071: *
072: * <p>It is OK to call this method multiple time, since it is smart
073: * enough to ignore redudant calls.
074: *
075: * <p>{@link CharsetFilter} actually use this method to setup
076: * the proper charset and locale. By mapping {@link CharsetFilter} to
077: * all servlets, the encoding charset could be prepared correctly.
078: * However, if you are writing libraries to be as independent of
079: * web.xml as possible, you might choose to invoke this method directly.
080: *
081: * @param charset the response's charset. If null or empty,
082: * response.setCharacterEncoding won't be called, i.e., the container's
083: * default is used.
084: * @return an object that must be passed to {@link #cleanup}
085: */
086: public static final Object setup(ServletRequest request,
087: ServletResponse response, String charset) {
088: if (hasSetup(request)) //processed before?
089: return Objects.UNKNOWN;
090:
091: final Locale locale = getPreferredLocale(request);
092: response.setLocale(locale);
093: if (Servlets.isServlet24() && charset != null
094: && charset.length() > 0) {
095: try {
096: response.setCharacterEncoding(charset);
097: //if null, the mapping defined in web.xml is used
098: } catch (Throwable ex) {
099: final String v = response.getCharacterEncoding();
100: if (!Objects.equals(v, charset))
101: log.warning("Unable to set response's charset: "
102: + charset + " (current=" + v + ')', ex);
103: }
104: }
105:
106: if (request.getCharacterEncoding() == null) {
107: charset = response.getCharacterEncoding();
108: try {
109: request.setCharacterEncoding(charset);
110: } catch (Throwable ex) {
111: final String v = request.getCharacterEncoding();
112: if (!Objects.equals(v, charset))
113: log.warning("Unable to set request's charset: "
114: + charset + " (current=" + v + "): "
115: + Exceptions.getMessage(ex));
116: }
117: }
118:
119: markSetup(request, true);
120: return Locales.setThreadLocal(locale);
121: }
122:
123: /** Cleans up what has been set in {@link #setup}.
124: * Some invocation are not undo-able, so this method only does the basic
125: * cleanups.
126: *
127: * @param old the value must be the one returned by the last call to
128: * {@link #setup}.
129: */
130: public static final void cleanup(ServletRequest request, Object old) {
131: if (old != Objects.UNKNOWN) {
132: Locales.setThreadLocal((Locale) old);
133: markSetup(request, false);
134: }
135: }
136:
137: /** Returns whether the specified request has been set up, i.e.,
138: * {@link #setup} is called
139: *
140: * <p>It is rarely needed to call this method, because it is called
141: * automatically by {@link #setup}.
142: */
143: public static final boolean hasSetup(ServletRequest request) {
144: return request.getAttribute(ATTR_SETUP) != null; //processed before?
145: }
146:
147: /** Marks the specified request whether it has been set up, i.e.,
148: * {@link #setup} is called.
149: *
150: * <p>It is rarely needed to call this method, because it is called
151: * automatically by {@link #setup}.
152: */
153: public static final void markSetup(ServletRequest request,
154: boolean setup) {
155: if (setup)
156: request.setAttribute(ATTR_SETUP, Boolean.TRUE);
157: else
158: request.removeAttribute(ATTR_SETUP);
159: }
160:
161: /** Returns the preferred locale of the specified request.
162: * You rarely need to invoke this method directly, because it is done
163: * automatically by {@link #setup}.
164: *
165: * <ol>
166: * <li>It checks whether any attribute stored in HttpSession called
167: * {@link Attributes#PREFERRED_LOCALE}. If so, return it.</li>
168: * <li>Otherwise, use ServletRequest.getLocale().</li>
169: * </ol>
170: */
171: public static final Locale getPreferredLocale(ServletRequest request) {
172: if (request instanceof HttpServletRequest) {
173: final HttpSession sess = ((HttpServletRequest) request)
174: .getSession(false);
175: if (sess != null) {
176: final Object v = sess
177: .getAttribute(Attributes.PREFERRED_LOCALE);
178: if (v != null) {
179: if (v instanceof Locale)
180: return (Locale) v;
181: log.warning(Attributes.PREFERRED_LOCALE
182: + " ignored. Locale is required, not "
183: + v.getClass());
184: }
185: }
186: }
187:
188: final Locale l = request.getLocale();
189: return l != null ? l : Locale.getDefault();
190: }
191:
192: /** Sets the preferred locale for the current session of the specified
193: * request.
194: * @param locale the preferred Locale. If null, it means no preferred
195: * locale (and then {@link #getPreferredLocale} use request.getLocale
196: * instead).
197: */
198: public static final void setPreferredLocale(ServletRequest request,
199: Locale locale) {
200: if (request instanceof HttpServletRequest) {
201: final HttpSession sess = ((HttpServletRequest) request)
202: .getSession(); //auto-create
203: if (locale != null)
204: sess.setAttribute(Attributes.PREFERRED_LOCALE, locale);
205: else
206: sess.removeAttribute(Attributes.PREFERRED_LOCALE);
207: }
208: }
209: }
|