KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > portlet > mvc > AbstractController


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.web.portlet.mvc;
18
19 import javax.portlet.ActionRequest;
20 import javax.portlet.ActionResponse;
21 import javax.portlet.PortletException;
22 import javax.portlet.PortletSession;
23 import javax.portlet.RenderRequest;
24 import javax.portlet.RenderResponse;
25 import javax.portlet.WindowState;
26
27 import org.springframework.web.portlet.ModelAndView;
28 import org.springframework.web.portlet.handler.PortletContentGenerator;
29 import org.springframework.web.portlet.util.PortletUtils;
30
31 /**
32  * Convenient superclass for controller implementations, using the Template
33  * Method design pattern.
34  *
35  * <p>As stated in the {@link Controller Controller}
36  * interface, a lot of functionality is already provided by certain abstract
37  * base controllers. The AbstractController is one of the most important
38  * abstract base controller providing basic features such controlling if a
39  * session is required and render caching.
40  *
41  * <p><b><a name="workflow">Workflow
42  * (<a HREF="Controller.html#workflow">and that defined by interface</a>):</b><br>
43  * <ol>
44  * <li>If this is an action request, {@link #handleActionRequest handleActionRequest}
45  * will be called by the DispatcherPortlet once to perform the action defined by this
46  * controller.</li>
47  * <li>If a session is required, try to get it (PortletException if not found).</li>
48  * <li>Call method {@link #handleActionRequestInternal handleActionRequestInternal},
49  * (optionally synchronizing around the call on the PortletSession),
50  * which should be overridden by extending classes to provide actual functionality to
51  * perform the desired action of the controller. This will be executed only once.</li>
52  * <li>For a straight render request, or the render phase of an action request (assuming the
53  * same controller is called for the render phase -- see tip below),
54  * {@link #handleRenderRequest handleRenderRequest} will be called by the DispatcherPortlet
55  * repeatedly to render the display defined by this controller.</li>
56  * <li>If a session is required, try to get it (PortletException if none found).</li>
57  * <li>It will control caching as defined by the cacheSeconds property.</li>
58  * <li>Call method {@link #handleRenderRequestInternal handleRenderRequestInternal},
59  * (optionally synchronizing around the call on the PortletSession),
60  * which should be overridden by extending classes to provide actual functionality to
61  * return {@link org.springframework.web.portlet.ModelAndView ModelAndView} objects.
62  * This will be executed repeatedly as the portal updates the current displayed page.</li>
63  * </ol>
64  *
65  * <p><b><a name="config">Exposed configuration properties</a>
66  * (<a HREF="Controller.html#config">and those defined by interface</a>):</b><br>
67  * <table border="1">
68  * <tr>
69  * <td><b>name</b></th>
70  * <td><b>default</b></td>
71  * <td><b>description</b></td>
72  * </tr>
73  * <tr>
74  * <td>requiresSession</td>
75  * <td>false</td>
76  * <td>whether a session should be required for requests to be able to
77  * be handled by this controller. This ensures, derived controller
78  * can - without fear of Nullpointers - call request.getSession() to
79  * retrieve a session. If no session can be found while processing
80  * the request, a PortletException will be thrown</td>
81  * </tr>
82  * <tr>
83  * <td>synchronizeOnSession</td>
84  * <td>false</td>
85  * <td>whether the calls to <code>handleRenderRequestInternal</code> and
86  * <code>handleRenderRequestInternal</code> should be
87  * synchronized around the PortletSession, to serialize invocations
88  * from the same client. No effect if there is no PortletSession.
89  * </td>
90  * </tr>
91  * <tr>
92  * <td>cacheSeconds</td>
93  * <td>-1</td>
94  * <td>indicates the amount of seconds to specify caching is allowed in
95  * the render response generatedby this request. 0 (zero) will indicate
96  * no caching is allowed at all, -1 (the default) will not override the
97  * portlet configuration and any positive number will cause the render
98  * response to declare the amount indicated as seconds to cache the content</td>
99  * </tr>
100  * <tr>
101  * <td>renderWhenMinimized</td>
102  * <td>false</td>
103  * <td>whether should be rendered when the portlet is in a minimized state --
104  * will return null for the ModelandView when the portlet is minimized
105  * and this is false</td>
106  * </tr>
107  * </table>
108  *
109  * <p><b>TIP:</b> The controller mapping will be run twice by the PortletDispatcher for
110  * action requests -- once for the action phase and again for the render phase. You can
111  * reach the render phase of a different controller by simply changing the values for the
112  * criteria your mapping is using, such as portlet mode or a request parameter, during the
113  * action phase of your controller. This is very handy since redirects within the portlet
114  * are apparently impossible. Before doing this, it is usually wise to call
115  * <code>clearAllRenderParameters</code> and then explicitly set all the parameters that
116  * you want the new controller to see. This avoids unexpected parameters from being passed
117  * to the render phase of the second controller, such as the parameter indicating a form
118  * submit ocurred in an <code>AbstractFormController</code>.
119  *
120  * @author John A. Lewis
121  * @author Rainer Schmitz
122  * @author Juergen Hoeller
123  * @since 2.0
124  */

125 public abstract class AbstractController extends PortletContentGenerator implements Controller {
126
127     private boolean synchronizeOnSession = false;
128
129     private boolean renderWhenMinimized = false;
130
131
132     /**
133      * Set if controller execution should be synchronized on the session,
134      * to serialize parallel invocations from the same client.
135      * <p>More specifically, the execution of the <code>handleActionRequestInternal</code>
136      * method will get synchronized if this flag is "true". The best available
137      * session mutex will be used for the synchronization; ideally, this will
138      * be a mutex exposed by HttpSessionMutexListener.
139      * <p>The session mutex is guaranteed to be the same object during
140      * the entire lifetime of the session, available under the key defined
141      * by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a
142      * safe reference to synchronize on for locking on the current session.
143      * <p>In many cases, the PortletSession reference itself is a safe mutex
144      * as well, since it will always be the same object reference for the
145      * same active logical session. However, this is not guaranteed across
146      * different servlet containers; the only 100% safe way is a session mutex.
147      * @see #handleActionRequestInternal
148      * @see org.springframework.web.util.HttpSessionMutexListener
149      * @see org.springframework.web.portlet.util.PortletUtils#getSessionMutex(javax.portlet.PortletSession)
150      */

151     public final void setSynchronizeOnSession(boolean synchronizeOnSession) {
152         this.synchronizeOnSession = synchronizeOnSession;
153     }
154
155     /**
156      * Return whether controller execution should be synchronized on the session.
157      */

158     public final boolean isSynchronizeOnSession() {
159         return synchronizeOnSession;
160     }
161
162     /**
163      * Set if the controller should render an view when the portlet is in
164      * a minimized window. The default is false.
165      * @see javax.portlet.RenderRequest#getWindowState
166      * @see javax.portlet.WindowState#MINIMIZED
167      */

168     public void setRenderWhenMinimized(boolean renderWhenMinimized) {
169         this.renderWhenMinimized = renderWhenMinimized;
170     }
171
172     /**
173      * Return whether controller will render when portlet is minimized.
174      */

175     public boolean isRenderWhenMinimized() {
176         return renderWhenMinimized;
177     }
178
179
180     public final void handleActionRequest(ActionRequest request, ActionResponse response)
181             throws Exception JavaDoc {
182
183         // Delegate to PortletContentGenerator for checking and preparing.
184
check(request, response);
185
186         // Execute in synchronized block if required.
187
if (this.synchronizeOnSession) {
188             PortletSession session = request.getPortletSession(false);
189             if (session != null) {
190                 synchronized (session) {
191                     handleActionRequestInternal(request, response);
192                     return;
193                 }
194             }
195         }
196
197         handleActionRequestInternal(request, response);
198     }
199
200     public final ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response)
201             throws Exception JavaDoc {
202
203         // If the portlet is minimized and we don't want to render then return null.
204
if (WindowState.MINIMIZED.equals(request.getWindowState()) && !this.renderWhenMinimized) {
205             return null;
206         }
207         
208         // Delegate to PortletContentGenerator for checking and preparing.
209
checkAndPrepare(request, response);
210
211         // Execute in synchronized block if required.
212
if (this.synchronizeOnSession) {
213             PortletSession session = request.getPortletSession(false);
214             if (session != null) {
215                 Object JavaDoc mutex = PortletUtils.getSessionMutex(session);
216                 synchronized (mutex) {
217                     return handleRenderRequestInternal(request, response);
218                 }
219             }
220         }
221
222         return handleRenderRequestInternal(request, response);
223     }
224
225
226     /**
227      * Subclasses are meant to override this method if the controller
228      * is expected to handle action requests. The contract is the same as
229      * for <code>handleActionRequest</code>.
230      * <p>The default implementation throws a PortletException.
231      * @see #handleActionRequest
232      * @see #handleRenderRequestInternal
233      */

234     protected void handleActionRequestInternal(ActionRequest request, ActionResponse response)
235             throws Exception JavaDoc {
236
237         throw new PortletException("[" + getClass().getName() + "] does not handle action requests");
238     }
239
240     /**
241      * Subclasses are meant to override this method if the controller
242      * is expected to handle render requests. The contract is the same as
243      * for <code>handleRenderRequest</code>.
244      * <p>The default implementation throws a PortletException.
245      * @see #handleRenderRequest
246      * @see #handleActionRequestInternal
247      */

248     protected ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response)
249             throws Exception JavaDoc {
250
251         throw new PortletException("[" + getClass().getName() + "] does not handle render requests");
252     }
253
254 }
255
Popular Tags