View Javadoc

1   /*
2    * $Id: TokenSessionStoreInterceptor.java 517433 2007-03-12 22:34:58Z husted $
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.Map;
24  
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  
28  import org.apache.struts2.ServletActionContext;
29  import org.apache.struts2.util.InvocationSessionStore;
30  import org.apache.struts2.util.TokenHelper;
31  
32  import com.opensymphony.xwork2.ActionContext;
33  import com.opensymphony.xwork2.ActionInvocation;
34  import com.opensymphony.xwork2.Result;
35  import com.opensymphony.xwork2.util.ValueStack;
36  
37  
38  /***
39   * <!-- START SNIPPET: description -->
40   *
41   * This interceptor builds off of the {@link TokenInterceptor}, providing advanced logic for handling invalid tokens.
42   * Unlike the normal token interceptor, this interceptor will attempt to provide intelligent fail-over in the event of
43   * multiple requests using the same session. That is, it will block subsequent requests until the first request is
44   * complete, and then instead of returning the <i>invalid.token</i> code, it will attempt to display the same response
45   * that the original, valid action invocation would have displayed if no multiple requests were submitted in the first
46   * place.
47   *
48   * <p/>
49   *
50   * <b>NOTE:</b> As this method extends off MethodFilterInterceptor, it is capable of
51   * deciding if it is applicable only to selective methods in the action class. See
52   * <code>MethodFilterInterceptor</code> for more info.
53   *
54   * <!-- END SNIPPET: description -->
55   *
56   * <p/> <u>Interceptor parameters:</u>
57   *
58   * <!-- START SNIPPET: parameters -->
59   *
60   * <ul>
61   *
62   * <li>None</li>
63   *
64   * </ul>
65   *
66   * <!-- END SNIPPET: parameters -->
67   *
68   * <p/> <u>Extending the interceptor:</u>
69   *
70   * <p/>
71   *
72   * <!-- START SNIPPET: extending -->
73   *
74   * There are no known extension points for this interceptor.
75   *
76   * <!-- END SNIPPET: extending -->
77   *
78   * <p/> <u>Example code:</u>
79   *
80   * <pre>
81   * <!-- START SNIPPET: example -->
82   *
83   * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
84   *     &lt;interceptor-ref name="token-session/&gt;
85   *     &lt;interceptor-ref name="basicStack"/&gt;
86   *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
87   * &lt;/action&gt;
88   *
89   * &lt;-- In this case, myMethod of the action class will not
90   *        get checked for invalidity of token --&gt;
91   * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
92   *     &lt;interceptor-ref name="token-session&gt;
93   *         &lt;param name="excludeMethods"&gt;myMethod&lt;/param&gt;
94   *     &lt;/interceptor-ref name="token-session&gt;
95   *     &lt;interceptor-ref name="basicStack"/&gt;
96   *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
97   * &lt;/action&gt;
98   *
99   * <!-- END SNIPPET: example -->
100  * </pre>
101  *
102  */
103 public class TokenSessionStoreInterceptor extends TokenInterceptor {
104 
105     private static final long serialVersionUID = -9032347965469098195L;
106 
107     /* (non-Javadoc)
108      * @see org.apache.struts2.interceptor.TokenInterceptor#handleInvalidToken(com.opensymphony.xwork2.ActionInvocation)
109      */
110     protected String handleInvalidToken(ActionInvocation invocation) throws Exception {
111         ActionContext ac = invocation.getInvocationContext();
112 
113         HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
114         HttpServletResponse response = (HttpServletResponse) ac.get(ServletActionContext.HTTP_RESPONSE); 
115         String tokenName = TokenHelper.getTokenName();
116         String token = TokenHelper.getToken(tokenName);
117 
118         Map params = ac.getParameters();
119         params.remove(tokenName);
120         params.remove(TokenHelper.TOKEN_NAME_FIELD);
121 
122         if ((tokenName != null) && (token != null)) {
123             ActionInvocation savedInvocation = InvocationSessionStore.loadInvocation(tokenName, token);
124 
125             if (savedInvocation != null) {
126                 // set the valuestack to the request scope
127                 ValueStack stack = savedInvocation.getStack();
128                 Map context = stack.getContext();
129                 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
130 
131                 ActionContext savedContext = savedInvocation.getInvocationContext();
132                 savedContext.getContextMap().put(ServletActionContext.HTTP_REQUEST, request);
133                 savedContext.getContextMap().put(ServletActionContext.HTTP_RESPONSE, response);
134                 Result result = savedInvocation.getResult();
135 
136                 if ((result != null) && (savedInvocation.getProxy().getExecuteResult())) {
137                     synchronized (context) {
138                         result.execute(savedInvocation);
139                     }
140                 }
141 
142                 // turn off execution of this invocations result
143                 invocation.getProxy().setExecuteResult(false);
144 
145                 return savedInvocation.getResultCode();
146             }
147         }
148 
149         return INVALID_TOKEN_CODE;
150     }
151 
152     /* (non-Javadoc)
153      * @see org.apache.struts2.interceptor.TokenInterceptor#handleValidToken(com.opensymphony.xwork2.ActionInvocation)
154      */
155     protected String handleValidToken(ActionInvocation invocation) throws Exception {
156         // we know the token name and token must be there
157         String key = TokenHelper.getTokenName();
158         String token = TokenHelper.getToken(key);
159         InvocationSessionStore.storeInvocation(key, token, invocation);
160 
161         return invocation.invoke();
162     }
163 }