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 }