1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.pipeline.valve.impl;
18
19 import java.io.IOException;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.Iterator;
23
24 import javax.portlet.PortletException;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.jetspeed.PortalReservedParameters;
31 import org.apache.jetspeed.cache.ContentCacheKey;
32 import org.apache.jetspeed.cache.JetspeedContentCache;
33 import org.apache.jetspeed.container.window.PortletWindowAccessor;
34 import org.apache.jetspeed.container.state.MutableNavigationalState;
35 import org.apache.jetspeed.exception.JetspeedException;
36 import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
37 import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
38 import org.apache.jetspeed.om.page.ContentFragment;
39 import org.apache.jetspeed.om.page.ContentFragmentImpl;
40 import org.apache.jetspeed.om.page.ContentPage;
41 import org.apache.jetspeed.om.page.Fragment;
42 import org.apache.jetspeed.om.page.Page;
43 import org.apache.jetspeed.pipeline.PipelineException;
44 import org.apache.jetspeed.pipeline.valve.AbstractValve;
45 import org.apache.jetspeed.pipeline.valve.ActionValve;
46 import org.apache.jetspeed.pipeline.valve.ValveContext;
47 import org.apache.jetspeed.request.RequestContext;
48 import org.apache.pluto.PortletContainer;
49 import org.apache.pluto.PortletContainerException;
50 import org.apache.pluto.om.entity.PortletEntity;
51 import org.apache.pluto.om.window.PortletWindow;
52
53 /***
54 * <p>
55 * ActionValveImpl
56 * </p>
57 *
58 * Default implementation of the ActionValve interface. Expects to be
59 * called after the ContainerValve has set up the appropriate action window
60 * within the request context. This should come before ANY rendering takes
61 * place.
62 *
63 * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
64 * @version $Id: ActionValveImpl.java 589933 2007-10-30 01:51:50Z woonsan $
65 *
66 */
67 public class ActionValveImpl extends AbstractValve implements ActionValve
68 {
69
70 private static final Log log = LogFactory.getLog(ActionValveImpl.class);
71 private PortletContainer container;
72 private PortletWindowAccessor windowAccessor;
73 private boolean patchResponseCommitted = false;
74 private JetspeedContentCache portletContentCache;
75
76 public ActionValveImpl(PortletContainer container, PortletWindowAccessor windowAccessor, JetspeedContentCache portletContentCache)
77 {
78 this.container = container;
79 this.windowAccessor = windowAccessor;
80 this.portletContentCache = portletContentCache;
81 }
82
83 public ActionValveImpl(PortletContainer container, PortletWindowAccessor windowAccessor, JetspeedContentCache portletContentCache, boolean patchResponseCommitted)
84 {
85 this.container = container;
86 this.windowAccessor = windowAccessor;
87 this.portletContentCache = portletContentCache;
88 this.patchResponseCommitted = patchResponseCommitted;
89 }
90
91 /***
92 * @see org.apache.jetspeed.pipeline.valve.Valve#invoke(org.apache.jetspeed.request.RequestContext, org.apache.jetspeed.pipeline.valve.ValveContext)
93 */
94 public void invoke(RequestContext request, ValveContext context) throws PipelineException
95 {
96 boolean responseCommitted = false;
97 try
98 {
99 PortletWindow actionWindow = request.getActionWindow();
100 if (actionWindow != null)
101 {
102
103
104 if (null == actionWindow.getPortletEntity())
105 {
106 try
107 {
108 Fragment fragment = request.getPage().getFragmentById(actionWindow.getId().toString());
109
110 if (fragment != null)
111 {
112 ContentFragment contentFragment = new ContentFragmentImpl(fragment, new HashMap());
113 actionWindow = this.windowAccessor.getPortletWindow(contentFragment);
114 }
115 }
116 catch (Exception e)
117 {
118 log.error("Failed to refresh action window.", e);
119 }
120 }
121
122 if (actionWindow.getPortletEntity() == null)
123 {
124
125
126 log.warn("Portlet action was canceled because the session was expired. The actionWindow's id is " + actionWindow.getId());
127
128 request.setActionWindow(null);
129 MutableNavigationalState state = (MutableNavigationalState) request.getPortalURL().getNavigationalState();
130
131 if (state != null)
132 {
133 state.removeState(actionWindow);
134 state.sync(request);
135 request.getResponse().sendRedirect(request.getPortalURL().getPortalURL());
136 return;
137 }
138 }
139
140 initWindow(actionWindow, request);
141 HttpServletResponse response = request.getResponseForWindow(actionWindow);
142 HttpServletRequest requestForWindow = request.getRequestForWindow(actionWindow);
143 requestForWindow.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE, request);
144
145
146
147 requestForWindow.setAttribute("JETSPEED_ACTION", request);
148 container.processPortletAction(
149 actionWindow,
150 requestForWindow,
151 response);
152
153
154
155
156
157
158 clearPortletCacheForPage(request, actionWindow);
159
160 if (patchResponseCommitted)
161 {
162 responseCommitted = true;
163 }
164 else
165 {
166 responseCommitted = response.isCommitted();
167 }
168 request.setAttribute(PortalReservedParameters.PIPELINE, null);
169 }
170 }
171 catch (PortletContainerException e)
172 {
173 log.fatal("Unable to retrieve portlet container!", e);
174 throw new PipelineException("Unable to retrieve portlet container!", e);
175 }
176 catch (PortletException e)
177 {
178 log.warn("Unexpected PortletException in ActionValveImpl", e);
179
180
181 }
182 catch (IOException e)
183 {
184 log.error("Unexpected IOException in ActionValveImpl", e);
185
186 }
187 catch (IllegalStateException e)
188 {
189 log.error("Illegal State Exception. Response was written to in Action Phase", e);
190 responseCommitted = true;
191 }
192 catch (Throwable t)
193 {
194 log.error("Unknown exception processing Action", t);
195 }
196 finally
197 {
198
199
200 if ( responseCommitted )
201 {
202 log.info("Action processed and response committed (pipeline processing stopped)");
203 }
204 else
205 {
206
207 context.invokeNext(request);
208 }
209 }
210
211 }
212
213 protected void clearPortletCacheForPage(RequestContext request, PortletWindow actionWindow)
214 throws JetspeedException
215 {
216 ContentPage page = request.getPage();
217 if (null == page)
218 {
219 throw new JetspeedException("Failed to find PSML Pin ContentPageAggregator.build");
220 }
221 ContentFragment root = page.getRootContentFragment();
222 if (root == null)
223 {
224 throw new JetspeedException("No root ContentFragment found in ContentPage");
225 }
226 if (!isNonStandardAction(actionWindow))
227 {
228 notifyFragments(root, request, page);
229
230
231
232 String fragmentId = actionWindow.getId().toString();
233 if (page.getFragmentById(fragmentId) == null)
234 {
235 clearTargetCache(fragmentId, request);
236 }
237 }
238 else
239 {
240 ContentFragment fragment = page.getContentFragmentById(actionWindow.getId().toString());
241
242 if (fragment != null)
243 {
244 clearTargetCache(fragment, request);
245 }
246 else
247 {
248 clearTargetCache(actionWindow.getId().toString(), request);
249 }
250 }
251 }
252
253 /***
254 * Actions can be marked as non-standard if they don't participate in
255 * JSR-168 standard action behavior. By default, actions are supposed
256 * to clear the cache of all other portlets on the page.
257 * By setting this parameter, we can ignore the standard behavior
258 * and not clear the cache on actions. This is useful for portlets
259 * which never participate with other portlets.
260 *
261 */
262 protected boolean isNonStandardAction(PortletWindow actionWindow)
263 {
264 PortletEntity entity = actionWindow.getPortletEntity();
265 if (entity != null)
266 {
267 PortletDefinitionComposite portletDefinition = (PortletDefinitionComposite)entity.getPortletDefinition();
268 if (portletDefinition != null)
269 {
270 Collection actionList = null;
271
272 if (portletDefinition != null)
273 {
274 actionList = portletDefinition.getMetadata().getFields(PortalReservedParameters.PORTLET_EXTENDED_DESCRIPTOR_NON_STANDARD_ACTION);
275 }
276 if (actionList != null)
277 {
278 if (!actionList.isEmpty())
279 return true;
280 }
281 }
282 }
283 return false;
284 }
285
286 protected void notifyFragments(ContentFragment f, RequestContext context, ContentPage page)
287 {
288 if (f.getContentFragments() != null && f.getContentFragments().size() > 0)
289 {
290 Iterator children = f.getContentFragments().iterator();
291 while (children.hasNext())
292 {
293 ContentFragment child = (ContentFragment) children.next();
294 if (!"hidden".equals(f.getState()))
295 {
296 notifyFragments(child, context, page);
297 }
298 }
299 }
300 ContentCacheKey cacheKey = portletContentCache.createCacheKey(context, f.getId());
301 if (portletContentCache.isKeyInCache(cacheKey))
302 {
303 portletContentCache.remove(cacheKey);
304 portletContentCache.invalidate(context);
305 }
306 }
307
308 protected void clearTargetCache(ContentFragment f, RequestContext context)
309 {
310 clearTargetCache(f.getId(), context);
311 }
312
313 protected void clearTargetCache(String fragmentId, RequestContext context)
314 {
315 ContentCacheKey cacheKey = portletContentCache.createCacheKey(context, fragmentId);
316
317 if (portletContentCache.isKeyInCache(cacheKey))
318 {
319 portletContentCache.remove(cacheKey);
320 portletContentCache.invalidate(context);
321 }
322 }
323
324 /***
325 * @see java.lang.Object#toString()
326 */
327 public String toString()
328 {
329
330 return "ActionValveImpl";
331 }
332
333 /***
334 * Makes sure that this PortletWindow's PortletEntity is set to have the
335 * current requests fragment.
336 * @param window
337 * @param request
338 */
339 protected void initWindow(PortletWindow window, RequestContext request)
340 {
341 Page page = request.getPage();
342 Fragment fragment = page.getFragmentById(window.getId().toString());
343
344 if (fragment != null)
345 {
346 ((MutablePortletEntity)window.getPortletEntity()).setFragment(fragment);
347 }
348 }
349
350 }