View Javadoc

1   /*
2    * $Id: CookieInterceptor.java 747075 2009-02-23 16:38:47Z rgielen $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts2.interceptor;
23  
24  import java.util.*;
25  
26  import javax.servlet.http.Cookie;
27  import javax.servlet.http.HttpServletRequest;
28  
29  import org.apache.struts2.ServletActionContext;
30  
31  import com.opensymphony.xwork2.ActionContext;
32  import com.opensymphony.xwork2.ActionInvocation;
33  import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
34  import com.opensymphony.xwork2.util.TextParseUtil;
35  import com.opensymphony.xwork2.util.ValueStack;
36  import com.opensymphony.xwork2.util.logging.Logger;
37  import com.opensymphony.xwork2.util.logging.LoggerFactory;
38  
39  /***
40   * <!-- START SNIPPET: description -->
41   *
42   * The aim of this intercepter is to set values in the stack/action based on cookie name/value
43   * of interest. <p/>
44   *
45   * If an asterisk is present in cookiesName parameter, it will be assume that
46   * all cookies name are to be injected into struts' action, even though
47   * cookiesName is comma-separated by other values, e.g. (cookie1,*,cookie2). <p/>
48   *
49   * If cookiesName is left empty it will assume that no cookie will be injected
50   * into Struts' action. <p/>
51   *
52   * If an asterisk is present in cookiesValue parameter, it will assume that all
53   * cookies name irrespective of its value will be injected into Struts' action so
54   * long as the cookie name matches those specified in cookiesName parameter.<p/>
55   *
56   * If cookiesValue is left empty it will assume that all cookie that match the cookieName
57   * parameter will be injected into Struts' action.<p/>
58   *
59   * The action could implements {@link CookiesAware} in order to have a {@link Map}
60   * of filtered cookies set into it. <p/>
61   *
62   * <!-- END SNIPPET: description -->
63   *
64   *
65   * <!-- START SNIPPET: parameters -->
66   *
67   * <ul>
68   *      <li>cookiesName (mandatory) - Name of cookies to be injected into the action. If more
69   *                                                                 than one cookie name is desired it could be comma-separated.
70   *                                                                 If all cookies name is desired, it could simply be *, an asterik.
71   *                                                                 When many cookies name are comma-separated either of the cookie
72   *                                                        that match the name in the comma-separated list will be qualified.</li>
73   *     <li>cookiesValue (mandatory) - Value of cookies that if its name matches cookieName attribute
74   *                                                         and its value matched this, will be injected into Struts'
75   *                                                         action. If more than one cookie name is desired it could be
76   *                                                         comma-separated. If left empty, it will assume any value would
77   *                                                         be ok. If more than one value is specified (comma-separated)
78   *                                                         it will assume a match if either value is matched.
79   * </ul>
80   *
81   * <!-- END SNIPPET: parameters -->
82   *
83   *
84   * <!-- START SNIPPET: extending -->
85   *
86   * <ul>
87   *      populateCookieValueIntoStack - this method will decide if this cookie value is qualified to be
88   *                                                                                                         populated into the value stack (hence into the action itself)
89   *      injectIntoCookiesAwareAction - this method will inject selected cookies (as a java.util.Map) into
90   *                                                                                                        action that implements {@link CookiesAware}.
91   * </ul>
92   *
93   * <!-- END SNIPPET: extending -->
94   *
95   * <pre>
96   * <!-- START SNIPPET: example -->
97   *
98   * &lt;!--
99   *   This example will inject cookies named either 'cookie1' or 'cookie2' whose
100  *   value could be either 'cookie1value' or 'cookie2value' into Struts' action.
101  * --&gt;
102  * &lt;action ... &gt;
103  *    &lt;interceptor-ref name="cookie"&gt;
104  *        &lt;param name="cookiesName"&gt;cookie1, cookie2&lt;/param&gt;
105  *        &lt;param name="cookiesValue"&gt;cookie1value, cookie2value&lt;/param&gt;
106  *    &lt;/interceptor-ref&gt;
107  *    ....
108  * &lt;/action&gt;
109  *
110  *
111  * &lt;!--
112  *      This example will inject cookies named either 'cookie1' or 'cookie2'
113  *     regardless of their value into Struts' action.
114  * --&gt;
115  * &lt;action ... &gt;
116  *   &lt;interceptor-ref name="cookie"&gt;
117  *      &lt;param name="cookiesName"&gt;cookie1, cookie2&lt;/param&gt;
118  *      &lt;param name="cookiesValue"&gt;*&lt;/param&gt;
119  *   &lt;interceptor-ref&gt;
120  *   ...
121  * &lt;/action&gt;
122  *
123  *
124  * &lt;!--
125  *      This example will inject cookies named either 'cookie1' with value
126  *      'cookie1value' or 'cookie2' with value 'cookie2value' into Struts'
127  *      action.
128  * --&gt;
129  * &lt;action ... &gt;
130  *   &lt;interceptor-ref name="cookie"&gt;
131  *      &lt;param name="cookiesName"&gt;cookie1&lt;/param&gt;
132  *      &lt;param name="cookiesValue"&gt;cookie1value&lt;/param&gt;
133  *   &lt;/interceptor-ref&gt;
134  *   &lt;interceptor-ref name="cookie"&gt;
135  *      &lt;param name="cookiesName"&lt;cookie2&lt;/param&gt;
136  *     &lt;param name="cookiesValue"&gt;cookie2value&lt;/param&gt;
137  *   &lt;/interceptor-ref&gt;
138  *   ....
139  * &lt;/action&gt;
140  *
141  * &lt;!--
142  *    This example will inject any cookies regardless of its value into
143  *    Struts' action.
144  *  --&gt;
145  * &lt;action ... &gt;
146  *   &lt;interceptor-ref name="cookie"&gt;
147  *      &lt;param name="cookiesName"&gt;*&lt;/param&gt;
148  *      &lt;param name="cookiesValue"&gt;*&lt;/param&gt;
149  *   &lt;/interceptor-ref&gt;
150  *    ...
151  * &lt;/action&gt;
152  *
153  * <!-- END SNIPPET: example -->
154  * </pre>
155  *
156  * @see CookiesAware
157  */
158 public class CookieInterceptor extends AbstractInterceptor {
159 
160     private static final long serialVersionUID = 4153142432948747305L;
161 
162     private static final Logger LOG = LoggerFactory.getLogger(CookieInterceptor.class);
163 
164     private Set<String> cookiesNameSet = Collections.emptySet();
165     private Set<String> cookiesValueSet = Collections.emptySet();
166 
167     /***
168      * Set the <code>cookiesName</code> which if matched will allow the cookie
169      * to be injected into action, could be comma-separated string.
170      *
171      * @param cookiesName
172      */
173     public void setCookiesName(String cookiesName) {
174         if (cookiesName != null)
175             this.cookiesNameSet = TextParseUtil.commaDelimitedStringToSet(cookiesName);
176     }
177 
178     /***
179      * Set the <code>cookiesValue</code> which if matched (together with matching
180      * cookiesName) will caused the cookie to be injected into action, could be
181      * comma-separated string.
182      *
183      * @param cookiesValue
184      */
185     public void setCookiesValue(String cookiesValue) {
186         if (cookiesValue != null)
187             this.cookiesValueSet = TextParseUtil.commaDelimitedStringToSet(cookiesValue);
188     }
189 
190     public String intercept(ActionInvocation invocation) throws Exception {
191         if (LOG.isDebugEnabled())
192             LOG.debug("start interception");
193 
194         // contains selected cookies
195         final Map<String, String> cookiesMap = new LinkedHashMap<String, String>();
196 
197         Cookie[] cookies = ServletActionContext.getRequest().getCookies();
198         if (cookies != null) {
199             final ValueStack stack = ActionContext.getContext().getValueStack();
200 
201             for (Cookie cookie : cookies) {
202                 String name = cookie.getName();
203                 String value = cookie.getValue();
204 
205                 if (cookiesNameSet.contains("*")) {
206                     if (LOG.isDebugEnabled())
207                         LOG.debug("contains cookie name [*] in configured cookies name set, cookie with name [" + name + "] with value [" + value + "] will be injected");
208                     populateCookieValueIntoStack(name, value, cookiesMap, stack);
209                 } else if (cookiesNameSet.contains(cookie.getName())) {
210                     populateCookieValueIntoStack(name, value, cookiesMap, stack);
211                 }
212             }
213         }
214 
215         // inject the cookiesMap, even if we don't have any cookies
216         injectIntoCookiesAwareAction(invocation.getAction(), cookiesMap);
217 
218         return invocation.invoke();
219     }
220 
221     /***
222      * Hook that populate cookie value into value stack (hence the action)
223      * if the criteria is satisfied (if the cookie value matches with those configured).
224      *
225      * @param cookieName
226      * @param cookieValue
227      * @param cookiesMap
228      * @param stack
229      */
230     protected void populateCookieValueIntoStack(String cookieName, String cookieValue, Map<String, String> cookiesMap, ValueStack stack) {
231         if (cookiesValueSet.isEmpty() || cookiesValueSet.contains("*")) {
232             // If the interceptor is configured to accept any cookie value
233             // OR
234             // no cookiesValue is defined, so as long as the cookie name match
235             // we'll inject it into Struts' action
236             if (LOG.isDebugEnabled()) {
237                 if (cookiesValueSet.isEmpty())
238                     LOG.debug("no cookie value is configured, cookie with name ["+cookieName+"] with value ["+cookieValue+"] will be injected");
239                 else if (cookiesValueSet.contains("*"))
240                     LOG.debug("interceptor is configured to accept any value, cookie with name ["+cookieName+"] with value ["+cookieValue+"] will be injected");
241             }
242             cookiesMap.put(cookieName, cookieValue);
243             stack.setValue(cookieName, cookieValue);
244         }
245         else {
246             // if cookiesValues is specified, the cookie's value must match before we
247             // inject them into Struts' action
248             if (cookiesValueSet.contains(cookieValue)) {
249                 if (LOG.isDebugEnabled())
250                     LOG.debug("both configured cookie name and value matched, cookie ["+cookieName+"] with value ["+cookieValue+"] will be injected");
251                 cookiesMap.put(cookieName, cookieValue);
252                 stack.setValue(cookieName, cookieValue);
253             }
254         }
255     }
256 
257     /***
258      * Hook that set the <code>cookiesMap</code> into action that implements
259      * {@link CookiesAware}.
260      *
261      * @param action
262      * @param cookiesMap
263      */
264     protected void injectIntoCookiesAwareAction(Object action, Map<String, String> cookiesMap) {
265         if (action instanceof CookiesAware) {
266             if (LOG.isDebugEnabled())
267                 LOG.debug("action ["+action+"] implements CookiesAware, injecting cookies map ["+cookiesMap+"]");
268             ((CookiesAware)action).setCookiesMap(cookiesMap);
269         }
270     }
271 }