1 /*
2 * Copyright (c) 2002-2006 by OpenSymphony
3 * All rights reserved.
4 */
5
6 package com.opensymphony.xwork2.interceptor;
7
8 import com.opensymphony.xwork2.ActionInvocation;
9 import com.opensymphony.xwork2.util.LocalizedTextUtil;
10 import com.opensymphony.xwork2.util.logging.Logger;
11 import com.opensymphony.xwork2.util.logging.LoggerFactory;
12
13 import java.util.Locale;
14 import java.util.Map;
15
16 /**
17 * <!-- START SNIPPET: description -->
18 *
19 * An interceptor that handles setting the locale specified in a session as the locale for the current action request.
20 * In addition, this interceptor will look for a specific HTTP request parameter and set the locale to whatever value is
21 * provided. This means that this interceptor can be used to allow for your application to dynamically change the locale
22 * for the user's session or, alternatively, only for the current request (since XWork 2.1.3).
23 * This is very useful for applications that require multi-lingual support and want the user to
24 * be able to set his or her language preference at any point. The locale parameter is removed during the execution of
25 * this interceptor, ensuring that properties aren't set on an action (such as request_locale) that have no typical
26 * corresponding setter in your action.
27 *
28 * <p/>For example, using the default parameter name, a request to <b>foo.action?request_locale=en_US</b>, then the
29 * locale for US English is saved in the user's session and will be used for all future requests.
30 *
31 * <!-- END SNIPPET: description -->
32 *
33 * <p/> <u>Interceptor parameters:</u>
34 *
35 * <!-- START SNIPPET: parameters -->
36 *
37 * <ul>
38 *
39 * <li>parameterName (optional) - the name of the HTTP request parameter that dictates the locale to switch to and save
40 * in the session. By default this is <b>request_locale</b></li>
41 *
42 * <li>requestOnlyParameterName (optional) - the name of the HTTP request parameter that dictates the locale to switch to
43 * for the current request only, without saving it in the session. By default this is <b>request_only_locale</b></li>
44 *
45 * <li>attributeName (optional) - the name of the session key to store the selected locale. By default this is
46 * <b>WW_TRANS_I18N_LOCALE</b></li>
47 *
48 * </ul>
49 *
50 * <!-- END SNIPPET: parameters -->
51 *
52 * <p/> <u>Extending the interceptor:</u>
53 *
54 * <p/>
55 *
56 * <!-- START SNIPPET: extending -->
57 *
58 * There are no known extensions points for this interceptor.
59 *
60 * <!-- END SNIPPET: extending -->
61 *
62 * <p/> <u>Example code:</u>
63 *
64 * <pre>
65 * <!-- START SNIPPET: example -->
66 * <action name="someAction" class="com.examples.SomeAction">
67 * <interceptor-ref name="i18n"/>
68 * <interceptor-ref name="basicStack"/>
69 * <result name="success">good_result.ftl</result>
70 * </action>
71 * <!-- END SNIPPET: example -->
72 * </pre>
73 *
74 * @author Aleksei Gopachenko
75 */
76 public class I18nInterceptor extends AbstractInterceptor {
77 protected static final Logger LOG = LoggerFactory.getLogger(I18nInterceptor.class);
78
79 public static final String DEFAULT_SESSION_ATTRIBUTE = "WW_TRANS_I18N_LOCALE";
80 public static final String DEFAULT_PARAMETER = "request_locale";
81 public static final String DEFAULT_REQUESTONLY_PARAMETER = "request_only_locale";
82
83 protected String parameterName = DEFAULT_PARAMETER;
84 protected String requestOnlyParameterName = DEFAULT_REQUESTONLY_PARAMETER;
85 protected String attributeName = DEFAULT_SESSION_ATTRIBUTE;
86
87 public I18nInterceptor() {
88 if (LOG.isDebugEnabled()) {
89 LOG.debug("new I18nInterceptor()");
90 }
91 }
92
93 public void setParameterName(String parameterName) {
94 this.parameterName = parameterName;
95 }
96
97 public void setRequestOnlyParameterName( String requestOnlyParameterName ) {
98 this.requestOnlyParameterName = requestOnlyParameterName;
99 }
100
101 public void setAttributeName(String attributeName) {
102 this.attributeName = attributeName;
103 }
104
105 @Override
106 public String intercept(ActionInvocation invocation) throws Exception {
107 if (LOG.isDebugEnabled()) {
108 LOG.debug("intercept '"
109 + invocation.getProxy().getNamespace() + "/"
110 + invocation.getProxy().getActionName() + "' { ");
111 }
112 //get requested locale
113 Map<String, Object> params = invocation.getInvocationContext().getParameters();
114
115 boolean storeInSession = true;
116 Object requested_locale = findLocaleParameter(params, parameterName);
117 if (requested_locale == null) {
118 requested_locale = findLocaleParameter(params, requestOnlyParameterName);
119 if (requested_locale != null) {
120 storeInSession = false;
121 }
122 }
123
124 //save it in session
125 Map<String, Object> session = invocation.getInvocationContext().getSession();
126
127 Locale locale = null;
128 if (requested_locale != null) {
129 locale = (requested_locale instanceof Locale) ?
130 (Locale) requested_locale : LocalizedTextUtil.localeFromString(requested_locale.toString(), null);
131 if (locale != null && LOG.isDebugEnabled()) {
132 LOG.debug("applied request locale=" + locale);
133 }
134 }
135 if (session != null) {
136 synchronized (session) {
137 if (locale == null) {
138 // check session for saved locale
139 Object sessionLocale = session.get(attributeName);
140 if (sessionLocale != null && sessionLocale instanceof Locale) {
141 locale = (Locale) sessionLocale;
142 if (LOG.isDebugEnabled()) {
143 LOG.debug("applied session locale=" + locale);
144 }
145 } else {
146 // no overriding locale definition found, stay with current invokation (=browser) locale
147 locale = invocation.getInvocationContext().getLocale();
148 if (locale != null && LOG.isDebugEnabled()) {
149 LOG.debug("applied invocation context locale=" + locale);
150 }
151 }
152 }
153 if (storeInSession) {
154 session.put(attributeName, locale);
155 }
156 }
157 }
158 saveLocale(invocation, locale);
159
160 if (LOG.isDebugEnabled()) {
161 LOG.debug("before Locale=" + invocation.getStack().findValue("locale"));
162 }
163
164 final String result = invocation.invoke();
165 if (LOG.isDebugEnabled()) {
166 LOG.debug("after Locale=" + invocation.getStack().findValue("locale"));
167 }
168
169 if (LOG.isDebugEnabled()) {
170 LOG.debug("intercept } ");
171 }
172
173 return result;
174 }
175
176 private Object findLocaleParameter( Map<String, Object> params, String parameterName ) {
177 Object requested_locale = params.remove(parameterName);
178 if (requested_locale != null && requested_locale.getClass().isArray()
179 && ((Object[]) requested_locale).length == 1) {
180 requested_locale = ((Object[]) requested_locale)[0];
181
182 if (LOG.isDebugEnabled()) {
183 LOG.debug("requested_locale=" + requested_locale);
184 }
185 }
186 return requested_locale;
187 }
188
189 /**
190 * Save the given locale to the ActionInvocation.
191 *
192 * @param invocation The ActionInvocation.
193 * @param locale The locale to save.
194 */
195 protected void saveLocale(ActionInvocation invocation, Locale locale) {
196 invocation.getInvocationContext().setLocale(locale);
197 }
198
199 }