View Javadoc

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