001: /*
002: * $Id: $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts2.interceptor;
022:
023: import java.util.Collections;
024: import java.util.LinkedHashMap;
025: import java.util.Map;
026: import java.util.Set;
027:
028: import javax.servlet.http.Cookie;
029: import javax.servlet.http.HttpServletRequest;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033:
034: import org.apache.struts2.ServletActionContext;
035: import com.opensymphony.xwork2.ActionContext;
036: import com.opensymphony.xwork2.ActionInvocation;
037: import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
038: import com.opensymphony.xwork2.util.ValueStack;
039: import com.opensymphony.xwork2.util.TextParseUtil;
040:
041: /**
042: * <!-- START SNIPPET: description -->
043: *
044: * The aim of this interceptor is to set values in the stack/action based on cookie name/value
045: * of interest. <p/>
046: *
047: * If an asterik is present in cookiesName parameter, it will be assume that
048: * all cookies name are to be injected into struts' action, even though
049: * cookiesName is comma-separated by other values, eg (cookie1,*,cookie2). <p/>
050: *
051: * If cookiesName is left empty it will assume that no cookie will be injected
052: * into Struts' action. <p/>
053: *
054: * If an asterik is present in cookiesValue parameter, it will assume that all
055: * cookies name irrespective of its value will be injected into Struts' action so
056: * long as the cookie name matches those specified in cookiesName parameter.<p/>
057: *
058: * If cookiesValue is left empty it will assume that all cookie that match the cookieName
059: * parameter will be injected into Struts' action.<p/>
060: *
061: * The action could implements {@link CookiesAware} in order to have a {@link Map}
062: * of filtered cookies set into it. <p/>
063: *
064: * <!-- END SNIPPET: description -->
065: *
066: *
067: * <!-- START SNIPPET: parameters -->
068: *
069: * <ul>
070: * <li>cookiesName (mandatory) - Name of cookies to be injected into the action. If more
071: * than one cookie name is desired it could be comma-separated.
072: * If all cookies name is desired, it could simply be *, an asterik.
073: * When many cookies name are comma-separated either of the cookie
074: * that match the name in the comma-separated list will be qualified.</li>
075: * <li>cookiesValue (mandatory) - Value of cookies that if its name matches cookieName attribute
076: * and its value matched this, will be injected into Struts'
077: * action. If more than one cookie name is desired it could be
078: * comma-separated. If left empty, it will assume any value would
079: * be ok. If more than one value is specified (comma-separated)
080: * it will assume a match if either value is matched.
081: * </ul>
082: *
083: * <!-- END SNIPPET: parameters -->
084: *
085: *
086: * <!-- START SNIPPET: extending -->
087: *
088: * <ul>
089: * populateCookieValueIntoStack - this method will decide if this cookie value is qualified to be
090: * populated into the value stack (hence into the action itself)
091: * injectIntoCookiesAwareAction - this method will inject selected cookies (as a java.util.Map) into
092: * action that implements {@link CookiesAware}.
093: * </ul>
094: *
095: * <!-- END SNIPPET: extending -->
096: *
097: * <pre>
098: * <!-- START SNIPPET: example -->
099: *
100: * <!--
101: * This example will inject cookies named either 'cookie1' or 'cookie2' whose
102: * value could be either 'cookie1value' or 'cookie2value' into Struts' action.
103: * -->
104: * <action ... >
105: * <interceptor-ref name="cookie">
106: * <param name="cookiesName">cookie1, cookie2</param>
107: * <param name="cookiesValue">cookie1value, cookie2value</param>
108: * </interceptor-ref>
109: * ....
110: * </action>
111: *
112: *
113: * <!--
114: * This example will inject cookies named either 'cookie1' or 'cookie2'
115: * regardless of their value into Struts' action.
116: * -->
117: * <action ... >
118: * <interceptor-ref name="cookie">
119: * <param name="cookiesName">cookie1, cookie2</param>
120: * <param name="cookiesValue">*</param>
121: * <interceptor-ref>
122: * ...
123: * </action>
124: *
125: *
126: * <!--
127: * This example will inject cookies named either 'cookie1' with value
128: * 'cookie1value' or 'cookie2' with value 'cookie2value' into Struts'
129: * action.
130: * -->
131: * <action ... >
132: * <interceptor-ref name="cookie">
133: * <param name="cookiesName">cookie1</param>
134: * <param name="cookiesValue">cookie1value</param>
135: * </interceptor-ref>
136: * <interceptor-ref name="cookie">
137: * <param name="cookiesName"<cookie2</param>
138: * <param name="cookiesValue">cookie2value</param>
139: * </interceptor-ref>
140: * ....
141: * </action>
142: *
143: * <!--
144: * This example will inject any cookies regardless of its value into
145: * Struts' action.
146: * -->
147: * <action ... >
148: * <interceptor-ref name="cookie">
149: * <param name="cookiesName">*</param>
150: * <param name="cookiesValue">*</param>
151: * </interceptor-ref>
152: * ...
153: * </action>
154: *
155: * <!-- END SNIPPET: example -->
156: * </pre>
157: *
158: * @see CookiesAware
159: */
160: public class CookieInterceptor extends AbstractInterceptor {
161:
162: private static final long serialVersionUID = 4153142432948747305L;
163:
164: private static final Log LOG = LogFactory
165: .getLog(CookieInterceptor.class);
166:
167: private Set cookiesNameSet = Collections.EMPTY_SET;
168: private Set cookiesValueSet = Collections.EMPTY_SET;
169:
170: /**
171: * Set the <code>cookiesName</code> which if matche will allow the cookie
172: * to be injected into action, could be comma-separated string.
173: *
174: * @param cookiesName
175: */
176: public void setCookiesName(String cookiesName) {
177: if (cookiesName != null)
178: this .cookiesNameSet = TextParseUtil
179: .commaDelimitedStringToSet(cookiesName);
180: }
181:
182: /**
183: * Set the <code>cookiesValue</code> which if matched (together with matching
184: * cookiesName) will caused the cookie to be injected into action, could be
185: * comma-separated string.
186: *
187: * @param cookiesValue
188: */
189: public void setCookiesValue(String cookiesValue) {
190: if (cookiesValue != null)
191: this .cookiesValueSet = TextParseUtil
192: .commaDelimitedStringToSet(cookiesValue);
193: }
194:
195: public String intercept(ActionInvocation invocation)
196: throws Exception {
197:
198: if (LOG.isDebugEnabled())
199: LOG.debug("start interception");
200:
201: final ValueStack stack = ActionContext.getContext()
202: .getValueStack();
203: HttpServletRequest request = ServletActionContext.getRequest();
204:
205: // contains selected cookies
206: Map cookiesMap = new LinkedHashMap();
207:
208: Cookie cookies[] = request.getCookies();
209: if (cookies != null) {
210: for (int a = 0; a < cookies.length; a++) {
211: String name = cookies[a].getName();
212: String value = cookies[a].getValue();
213:
214: if (cookiesNameSet.contains("*")) {
215: if (LOG.isDebugEnabled())
216: LOG
217: .debug("contains cookie name [*] in configured cookies name set, cookie with name ["
218: + name
219: + "] with value ["
220: + value + "] will be injected");
221: populateCookieValueIntoStack(name, value,
222: cookiesMap, stack);
223: } else if (cookiesNameSet
224: .contains(cookies[a].getName())) {
225: populateCookieValueIntoStack(name, value,
226: cookiesMap, stack);
227: }
228: }
229: }
230:
231: injectIntoCookiesAwareAction(invocation.getAction(), cookiesMap);
232:
233: return invocation.invoke();
234: }
235:
236: /**
237: * Hook that populate cookie value into value stack (hence the action)
238: * if the criteria is satisfied (if the cookie value matches with those configured).
239: *
240: * @param cookieName
241: * @param cookieValue
242: * @param cookiesMap
243: * @param stack
244: */
245: protected void populateCookieValueIntoStack(String cookieName,
246: String cookieValue, Map cookiesMap, ValueStack stack) {
247: if (cookiesValueSet.isEmpty() || cookiesValueSet.contains("*")) {
248: // If the interceptor is configured to accept any cookie value
249: // OR
250: // no cookiesValue is defined, so as long as the cookie name match
251: // we'll inject it into Struts' action
252: if (LOG.isDebugEnabled()) {
253: if (cookiesValueSet.isEmpty())
254: LOG
255: .debug("no cookie value is configured, cookie with name ["
256: + cookieName
257: + "] with value ["
258: + cookieValue
259: + "] will be injected");
260: else if (cookiesValueSet.contains("*"))
261: LOG
262: .debug("interceptor is configured to accept any value, cookie with name ["
263: + cookieName
264: + "] with value ["
265: + cookieValue
266: + "] will be injected");
267: }
268: cookiesMap.put(cookieName, cookieValue);
269: stack.setValue(cookieName, cookieValue);
270: } else {
271: // if cookiesValues is specified, the cookie's value must match before we
272: // inject them into Struts' action
273: if (cookiesValueSet.contains(cookieValue)) {
274: if (LOG.isDebugEnabled())
275: LOG
276: .debug("both configured cookie name and value matched, cookie ["
277: + cookieName
278: + "] with value ["
279: + cookieValue
280: + "] will be injected");
281: cookiesMap.put(cookieName, cookieValue);
282: stack.setValue(cookieName, cookieValue);
283: }
284: }
285: }
286:
287: /**
288: * Hook that set the <code>cookiesMap</code> into action that implements
289: * {@link CookiesAware}.
290: *
291: * @param action
292: * @param cookiesMap
293: */
294: protected void injectIntoCookiesAwareAction(Object action,
295: Map cookiesMap) {
296: if (action instanceof CookiesAware) {
297: if (LOG.isDebugEnabled())
298: LOG
299: .debug("action ["
300: + action
301: + "] implements CookiesAware, injecting cookies map ["
302: + cookiesMap + "]");
303: ((CookiesAware) action).setCookiesMap(cookiesMap);
304: }
305: }
306:
307: }
|