1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 * <!--
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.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
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
238
239
240
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
252
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 }