View Javadoc

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