View Javadoc

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