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.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 * <!--
102 * This example will inject cookies named either 'cookie1' or 'cookie2' whose
103 * value could be either 'cookie1value' or 'cookie2value' into Struts' action.
104 * -->
105 * <action ... >
106 * <interceptor-ref name="cookie">
107 * <param name="cookiesName">cookie1, cookie2</param>
108 * <param name="cookiesValue">cookie1value, cookie2value</param>
109 * </interceptor-ref>
110 * ....
111 * </action>
112 *
113 *
114 * <!--
115 * This example will inject cookies named either 'cookie1' or 'cookie2'
116 * regardless of their value into Struts' action.
117 * -->
118 * <action ... >
119 * <interceptor-ref name="cookie">
120 * <param name="cookiesName">cookie1, cookie2</param>
121 * <param name="cookiesValue">*</param>
122 * <interceptor-ref>
123 * ...
124 * </action>
125 *
126 *
127 * <!--
128 * This example will inject cookies named either 'cookie1' with value
129 * 'cookie1value' or 'cookie2' with value 'cookie2value' into Struts'
130 * action.
131 * -->
132 * <action ... >
133 * <interceptor-ref name="cookie">
134 * <param name="cookiesName">cookie1</param>
135 * <param name="cookiesValue">cookie1value</param>
136 * </interceptor-ref>
137 * <interceptor-ref name="cookie">
138 * <param name="cookiesName"<cookie2</param>
139 * <param name="cookiesValue">cookie2value</param>
140 * </interceptor-ref>
141 * ....
142 * </action>
143 *
144 * <!--
145 * This example will inject any cookies regardless of its value into
146 * Struts' action.
147 * -->
148 * <action ... >
149 * <interceptor-ref name="cookie">
150 * <param name="cookiesName">*</param>
151 * <param name="cookiesValue">*</param>
152 * </interceptor-ref>
153 * ...
154 * </action>
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
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
239
240
241
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
253
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 }