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