001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.acting;
018:
019: import org.apache.avalon.framework.configuration.Configurable;
020: import org.apache.avalon.framework.configuration.Configuration;
021: import org.apache.avalon.framework.configuration.ConfigurationException;
022: import org.apache.avalon.framework.parameters.Parameters;
023: import org.apache.avalon.framework.thread.ThreadSafe;
024:
025: import org.apache.cocoon.environment.Redirector;
026: import org.apache.cocoon.environment.SourceResolver;
027: import org.apache.cocoon.i18n.I18nUtils;
028:
029: import java.util.HashMap;
030: import java.util.Locale;
031: import java.util.Map;
032:
033: /**
034: * An action that locates and provides to the pipeline locale information
035: * looked up in a range of ways.
036: *
037: * <h1>Configuration</h1>
038: * <p>A sample configuration (given in the <map:matchers> section of the
039: * sitemap) is given below. This configuration shows default values.
040: * </p>
041: * <pre>
042: * <map:action name="locale" src="org.apache.cocoon.acting.LocaleAction">
043: * <locale-attribute>locale</locale-attribute>
044: * <use-locale>true</use-locale>
045: * <default-locale language="en" country="US"/>
046: * <store-in-request>false<store-in-request>
047: * <create-session>false<create-session>
048: * <store-in-session>false<store-in-session>
049: * <store-in-cookie>false<store-in-cookie>
050: * </map:action>
051: * </pre>
052: *
053: * <p>Above configuration parameters mean:
054: * <ul>
055: * <li><b>locale-attribute</b> specifies the name of the request
056: * parameter / session attribute / cookie that is to be used as a locale
057: * (defaults to <code>locale</code>)</li>
058: * <li><b>use-locale</b> specifies whether the primary locale provided
059: * by the user agent (or server default, is no locale passed by the agent)
060: * is to be used</li>
061: * <li><b>default-locale</b> specifies the default locale to be used when
062: * none found.</li>
063: * <li><b>store-in-request</b> specifies whether found locale should be
064: * stored as request attribute.</li>
065: * <li><b>create-session</b> specifies whether session should be created
066: * when storing found locale as session attribute.</li>
067: * <li><b>store-in-session</b> specifies whether found locale should be
068: * stored as session attribute.</li>
069: * <li><b>store-in-cookie</b> specifies whether found locale should be
070: * stored as cookie.</li>
071: * </ul>
072: * </p>
073: *
074: * <h1>Usage</h1>
075: * <p>This action will be used in a pipeline like so:</p>
076: * <pre>
077: * <map:act type="locale">
078: * <map:generate src="file_{language}_{country}_{variant}.xml"/>
079: * ...
080: * </map:match>
081: * </pre>
082: * <p>or</p>
083: * <pre>
084: * <map:act type="locale">
085: * <map:generate src="file_{locale}.xml"/>
086: * ...
087: * </map:match>
088: * </pre>
089: *
090: * <h1>Locale Identification</h1>
091: * <p>Locales will be tested in following order:</p>
092: * <ul>
093: * <li>Locale provided as a request parameter</li>
094: * <li>Locale provided as a session attribute</li>
095: * <li>Locale provided as a cookie</li>
096: * <li>Locale provided using a sitemap parameter<br>
097: * (<map:parameter name="locale" value="{1}"/> style parameter within
098: * the <map:match> node)</li>
099: * <li>Locale provided by the user agent, or server default,
100: * if <code>use-locale</code> is set to <code>true</code></li>
101: * <li>The default locale, if specified in the matcher's configuration</li>
102: * </ul>
103: * <p>First found locale will be returned.</p>
104: *
105: * <h1>Sitemap Variables</h1>
106: * <p>Once locale has been found, the following sitemap variables
107: * will be available to sitemap elements contained within the action:</p>
108: * <ul>
109: * <li>{locale}: The locale string</li>
110: * <li>{language}: The language of the found locale</li>
111: * <li>{country}: The country of the found locale</li>
112: * <li>{variant}: The variant of the found locale</li>
113: * </ul>
114: *
115: * @author <a href="mailto:Marcus.Crafter@osa.de">Marcus Crafter</a>
116: * @author <a href="mailto:kpiroumian@flagship.ru">Konstantin Piroumian</a>
117: * @author <a href="mailto:lassi.immonen@valkeus.com">Lassi Immonen</a>
118: * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
119: * @version CVS $Id: LocaleAction.java 433543 2006-08-22 06:22:54Z crossley $
120: */
121: public class LocaleAction extends ServiceableAction implements
122: ThreadSafe, Configurable {
123:
124: private static final String DEFAULT_DEFAULT_LANG = "en";
125: private static final String DEFAULT_DEFAULT_COUNTRY = "US";
126: private static final String DEFAULT_DEFAULT_VARIANT = "";
127:
128: /**
129: * Default locale attribute name.
130: */
131: public static final String LOCALE = "locale";
132:
133: /**
134: * Configuration element name for locale attribute name.
135: */
136: public static final String LOCALE_ATTR = "locale-attribute";
137:
138: /**
139: * Constant representing the request storage configuration attribute
140: */
141: public static final String STORE_REQUEST = "store-in-request";
142:
143: /**
144: * Constant representing the session creation configuration attribute
145: */
146: public static final String CREATE_SESSION = "create-session";
147:
148: /**
149: * Constant representing the session storage configuration attribute
150: */
151: public static final String STORE_SESSION = "store-in-session";
152:
153: /**
154: * Constant representing the cookie storage configuration attribute
155: */
156: public static final String STORE_COOKIE = "store-in-cookie";
157:
158: /**
159: * Name of the locale request parameter, session attribute, cookie.
160: */
161: private String localeAttribute;
162:
163: /**
164: * Whether to query locale provided by the user agent or not.
165: */
166: private boolean useLocale;
167:
168: /**
169: * Default locale if no other found and {@link #useLocale} is false.
170: */
171: private Locale defaultLocale;
172:
173: /**
174: * Store the locale in request. Default is not to do this.
175: */
176: private boolean storeInRequest;
177:
178: /**
179: * Store the locale in session, if available. Default is not to do this.
180: */
181: private boolean storeInSession;
182:
183: /**
184: * Should we create a session if needed. Default is not to do this.
185: */
186: private boolean createSession;
187:
188: /**
189: * Should we add a cookie with the locale. Default is not to do this.
190: */
191: private boolean storeInCookie;
192:
193: /**
194: * Configure this action.
195: *
196: * @param config configuration information (if any)
197: */
198: public void configure(Configuration config)
199: throws ConfigurationException {
200: this .storeInRequest = config.getChild(STORE_REQUEST)
201: .getValueAsBoolean(false);
202: this .createSession = config.getChild(CREATE_SESSION)
203: .getValueAsBoolean(false);
204: this .storeInSession = config.getChild(STORE_SESSION)
205: .getValueAsBoolean(false);
206: this .storeInCookie = config.getChild(STORE_COOKIE)
207: .getValueAsBoolean(false);
208: if (getLogger().isDebugEnabled()) {
209: getLogger().debug(
210: (this .storeInRequest ? "will" : "won't")
211: + " set values in request");
212: getLogger().debug(
213: (this .createSession ? "will" : "won't")
214: + " create session");
215: getLogger().debug(
216: (this .storeInSession ? "will" : "won't")
217: + " set values in session");
218: getLogger().debug(
219: (this .storeInCookie ? "will" : "won't")
220: + " set values in cookies");
221: }
222:
223: this .localeAttribute = config.getChild(LOCALE_ATTR).getValue(
224: LOCALE);
225: this .useLocale = config.getChild("use-locale")
226: .getValueAsBoolean(true);
227:
228: Configuration child = config.getChild("default-locale", false);
229: if (child != null) {
230: this .defaultLocale = new Locale(child.getAttribute(
231: "language", DEFAULT_DEFAULT_LANG), child
232: .getAttribute("country", DEFAULT_DEFAULT_COUNTRY),
233: child.getAttribute("variant",
234: DEFAULT_DEFAULT_VARIANT));
235: }
236:
237: if (getLogger().isDebugEnabled()) {
238: getLogger().debug(
239: "Locale attribute name is " + this .localeAttribute);
240: getLogger().debug(
241: (this .useLocale ? "will" : "won't")
242: + " use request locale");
243: getLogger().debug("default locale " + this .defaultLocale);
244: }
245: }
246:
247: /**
248: * Action which obtains the current environments locale information, and
249: * places it in the objectModel (and optionally in a session/cookie).
250: */
251: public Map act(Redirector redirector, SourceResolver resolver,
252: Map objectModel, String source, Parameters params)
253: throws Exception {
254: // Obtain locale information from request, session, cookies, or params
255: Locale locale = I18nUtils.findLocale(objectModel,
256: localeAttribute, params, defaultLocale, useLocale);
257:
258: if (locale == null) {
259: if (getLogger().isDebugEnabled()) {
260: getLogger().debug("No locale found.");
261: }
262:
263: return null;
264: }
265:
266: String localeStr = locale.toString();
267: if (getLogger().isDebugEnabled()) {
268: getLogger().debug("Found locale: " + localeStr);
269: }
270:
271: I18nUtils.storeLocale(objectModel, localeAttribute, localeStr,
272: storeInRequest, storeInSession, storeInCookie,
273: createSession);
274:
275: // Set up a map for sitemap parameters
276: Map map = new HashMap();
277: map.put("language", locale.getLanguage());
278: map.put("country", locale.getCountry());
279: map.put("variant", locale.getVariant());
280: map.put("locale", localeStr);
281: return map;
282: }
283:
284: /**
285: * Helper method to retreive the attribute value containing locale
286: * information. See class documentation for locale determination algorythm.
287: *
288: * @deprecated See I18nUtils.findLocale
289: * @param objectModel requesting object's environment
290: * @return locale value or <code>null</null> if no locale was found
291: */
292: public static String getLocaleAttribute(Map objectModel,
293: String localeAttrName) {
294: Locale locale = I18nUtils.findLocale(objectModel,
295: localeAttrName, null, null, true);
296: return locale.toString();
297: }
298: }
|