1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 * <!--
99 * This example will inject cookies named either 'cookie1' or 'cookie2' whose
100 * value could be either 'cookie1value' or 'cookie2value' into Struts' action.
101 * -->
102 * <action ... >
103 * <interceptor-ref name="cookie">
104 * <param name="cookiesName">cookie1, cookie2</param>
105 * <param name="cookiesValue">cookie1value, cookie2value</param>
106 * </interceptor-ref>
107 * ....
108 * </action>
109 *
110 *
111 * <!--
112 * This example will inject cookies named either 'cookie1' or 'cookie2'
113 * regardless of their value into Struts' action.
114 * -->
115 * <action ... >
116 * <interceptor-ref name="cookie">
117 * <param name="cookiesName">cookie1, cookie2</param>
118 * <param name="cookiesValue">*</param>
119 * <interceptor-ref>
120 * ...
121 * </action>
122 *
123 *
124 * <!--
125 * This example will inject cookies named either 'cookie1' with value
126 * 'cookie1value' or 'cookie2' with value 'cookie2value' into Struts'
127 * action.
128 * -->
129 * <action ... >
130 * <interceptor-ref name="cookie">
131 * <param name="cookiesName">cookie1</param>
132 * <param name="cookiesValue">cookie1value</param>
133 * </interceptor-ref>
134 * <interceptor-ref name="cookie">
135 * <param name="cookiesName"<cookie2</param>
136 * <param name="cookiesValue">cookie2value</param>
137 * </interceptor-ref>
138 * ....
139 * </action>
140 *
141 * <!--
142 * This example will inject any cookies regardless of its value into
143 * Struts' action.
144 * -->
145 * <action ... >
146 * <interceptor-ref name="cookie">
147 * <param name="cookiesName">*</param>
148 * <param name="cookiesValue">*</param>
149 * </interceptor-ref>
150 * ...
151 * </action>
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
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
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
233
234
235
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
247
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 }