1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.portlet;
20
21 import java.io.IOException;
22
23 import javax.faces.FactoryFinder;
24 import javax.faces.application.Application;
25 import javax.faces.application.ApplicationFactory;
26 import javax.faces.application.ViewHandler;
27 import javax.faces.component.UIViewRoot;
28 import javax.faces.context.ExternalContext;
29 import javax.faces.context.FacesContext;
30 import javax.faces.context.FacesContextFactory;
31 import javax.faces.lifecycle.Lifecycle;
32 import javax.faces.lifecycle.LifecycleFactory;
33 import javax.faces.webapp.FacesServlet;
34 import javax.portlet.ActionRequest;
35 import javax.portlet.ActionResponse;
36 import javax.portlet.GenericPortlet;
37 import javax.portlet.PortletContext;
38 import javax.portlet.PortletException;
39 import javax.portlet.PortletRequest;
40 import javax.portlet.PortletResponse;
41 import javax.portlet.PortletSession;
42 import javax.portlet.RenderRequest;
43 import javax.portlet.RenderResponse;
44 import javax.portlet.UnavailableException;
45
46 import org.apache.commons.logging.Log;
47 import org.apache.commons.logging.LogFactory;
48 import org.apache.myfaces.config.FacesConfigurator;
49 import org.apache.myfaces.context.ReleaseableExternalContext;
50 import org.apache.myfaces.context.portlet.PortletExternalContextImpl;
51 import org.apache.myfaces.context.servlet.ServletFacesContextImpl;
52 import org.apache.myfaces.shared_impl.webapp.webxml.WebXml;
53
54
55
56
57
58
59
60
61 public class MyFacesGenericPortlet extends GenericPortlet
62 {
63 private static final Log log = LogFactory.getLog(MyFacesGenericPortlet.class);
64
65
66 public static final String VIEW_ID =
67 MyFacesGenericPortlet.class.getName() + ".VIEW_ID";
68
69
70 protected static final String CURRENT_FACES_CONTEXT =
71 MyFacesGenericPortlet.class.getName() + ".CURRENT_FACES_CONTEXT";
72
73
74 protected static final String DEFAULT_VIEW = "default-view";
75
76
77 protected static final String DEFAULT_VIEW_SELECTOR = "default-view-selector";
78
79
80
81
82 protected static final String REDEPLOY_FLAG =
83 MyFacesGenericPortlet.class.getName() + ".REDEPLOY_FLAG";
84
85 protected static final String FACES_INIT_DONE =
86 MyFacesGenericPortlet.class.getName() + ".FACES_INIT_DONE";
87
88 protected static final String SAVED_REQUEST_ATTRIBUTES =
89 MyFacesGenericPortlet.class.getName() + ".SAVED_REQUEST_ATTRIBUTES";
90
91 protected PortletContext portletContext;
92
93 protected FacesContextFactory facesContextFactory;
94 protected Lifecycle lifecycle;
95
96 protected String defaultView;
97 protected DefaultViewSelector defaultViewSelector;
98
99
100
101
102 public MyFacesGenericPortlet()
103 {
104 }
105
106
107
108
109 public void destroy()
110 {
111 super.destroy();
112 FactoryFinder.releaseFactories();
113 }
114
115
116
117
118 public void init() throws PortletException, UnavailableException
119 {
120 this.portletContext = getPortletContext();
121 setDefaultView();
122 setDefaultViewSelector();
123
124
125
126
127
128 initMyFaces();
129
130 facesContextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
131
132
133
134 LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
135 lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
136 }
137
138
139
140 protected void setDefaultView() throws UnavailableException
141 {
142 this.defaultView = getPortletConfig().getInitParameter(DEFAULT_VIEW);
143 if (defaultView == null)
144 {
145 String msg = "Fatal: must specify a JSF view id as the default view in portlet.xml";
146 throw new UnavailableException(msg);
147 }
148 }
149
150
151
152 protected void setDefaultViewSelector() throws UnavailableException
153 {
154 String selectorClass = getPortletConfig().getInitParameter(DEFAULT_VIEW_SELECTOR);
155 if (selectorClass == null) return;
156
157 try
158 {
159 this.defaultViewSelector = (DefaultViewSelector)Class.forName(selectorClass).newInstance();
160 this.defaultViewSelector.setPortletContext(getPortletContext());
161 }
162 catch (Exception e)
163 {
164 log.error("Failed to load " + DEFAULT_VIEW_SELECTOR, e);
165 throw new UnavailableException(e.getMessage());
166 }
167 }
168
169
170
171 protected void setContentType(RenderRequest request, RenderResponse response)
172 {
173
174 if (response.getContentType() == null)
175 {
176 String portalPreferredContentType = request.getResponseContentType();
177 if (portalPreferredContentType != null)
178 {
179 response.setContentType(portalPreferredContentType);
180 }
181 else
182 {
183 response.setContentType("text/html");
184 }
185 }
186 }
187
188
189
190 protected String getLifecycleId()
191 {
192 String lifecycleId = getPortletConfig().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
193 return lifecycleId != null ? lifecycleId : LifecycleFactory.DEFAULT_LIFECYCLE;
194 }
195
196 protected void initMyFaces()
197 {
198 try
199 {
200 Boolean b = (Boolean)portletContext.getAttribute(FACES_INIT_DONE);
201
202 if (b == null || b.booleanValue() == false)
203 {
204 log.trace("Initializing MyFaces");
205
206
207 ExternalContext externalContext = new PortletExternalContextImpl(portletContext, null, null);
208
209
210 new FacesConfigurator(externalContext).configure();
211
212
213 WebXml.init(externalContext);
214
215 portletContext.setAttribute(FACES_INIT_DONE, Boolean.TRUE);
216 }
217 else
218 {
219 log.info("MyFaces already initialized");
220 }
221 }
222 catch (Exception ex)
223 {
224 log.error("Error initializing MyFacesGenericPortlet", ex);
225 }
226
227 log.info("PortletContext '" + portletContext.getRealPath("/") + "' initialized.");
228 }
229
230
231
232
233 public void processAction(ActionRequest request, ActionResponse response)
234 throws PortletException, IOException
235 {
236 if (log.isTraceEnabled()) log.trace("called processAction");
237
238 if (sessionTimedOut(request)) return;
239
240 setPortletRequestFlag(request);
241
242 FacesContext facesContext = facesContext(request, response);
243
244 try
245 {
246 lifecycle.execute(facesContext);
247
248 if (!facesContext.getResponseComplete())
249 {
250 response.setRenderParameter(VIEW_ID, facesContext.getViewRoot().getViewId());
251 }
252
253 request.getPortletSession().setAttribute(CURRENT_FACES_CONTEXT, facesContext);
254 }
255 catch (Throwable e)
256 {
257 facesContext.release();
258 handleExceptionFromLifecycle(e);
259 }
260 finally
261 {
262 saveRequestAttributes(request);
263 }
264 }
265
266
267 protected void saveRequestAttributes(ActionRequest request)
268 {
269 PortletSession session = request.getPortletSession();
270 SavedRequestAttributes reqAttribs = null;
271 synchronized(session)
272 {
273 reqAttribs = (SavedRequestAttributes)session.getAttribute(SAVED_REQUEST_ATTRIBUTES);
274 if (reqAttribs == null)
275 {
276 reqAttribs = new SavedRequestAttributes();
277 session.setAttribute(SAVED_REQUEST_ATTRIBUTES, reqAttribs);
278 }
279 }
280
281 reqAttribs.saveRequestAttributes(request);
282 }
283
284
285 protected void restoreRequestAttributes(RenderRequest request)
286 {
287 PortletSession session = request.getPortletSession();
288 SavedRequestAttributes reqAttribs =
289 (SavedRequestAttributes)session.getAttribute(SAVED_REQUEST_ATTRIBUTES);
290 reqAttribs.resotreRequestAttributes(request);
291 }
292
293 protected void handleExceptionFromLifecycle(Throwable e)
294 throws PortletException, IOException
295 {
296 logException(e, null);
297
298 if (e instanceof IOException)
299 {
300 throw (IOException)e;
301 }
302
303 if (e instanceof PortletException)
304 {
305 throw (PortletException)e;
306 }
307
308 if (e.getMessage() != null)
309 {
310 throw new PortletException(e.getMessage(), e);
311 }
312
313 throw new PortletException(e);
314 }
315
316
317
318
319 protected void doView(RenderRequest request, RenderResponse response)
320 throws PortletException, IOException
321 {
322 try {
323 facesRender(request, response);
324 } finally {
325 renderCleanup(request);
326 }
327 }
328
329
330
331
332
333 protected void doEdit(RenderRequest request, RenderResponse response)
334 throws PortletException, IOException
335 {
336 try {
337 facesRender(request, response);
338 } finally {
339 renderCleanup(request);
340 }
341 }
342
343
344
345
346
347 protected void doHelp(RenderRequest request, RenderResponse response)
348 throws PortletException, IOException
349 {
350 try {
351 facesRender(request, response);
352 } finally {
353 renderCleanup(request);
354 }
355 }
356
357
358
359 protected void renderCleanup(RenderRequest request)
360 {
361 PortletSession session = request.getPortletSession();
362 session.setAttribute(REDEPLOY_FLAG, "portlet was not redeployed");
363 FacesContext context = FacesContext.getCurrentInstance();
364 if (context != null) context.release();
365 session.removeAttribute(this.CURRENT_FACES_CONTEXT);
366 }
367
368
369
370
371
372
373
374
375 protected void nonFacesRequest(RenderRequest request, RenderResponse response) throws PortletException
376 {
377 nonFacesRequest(request, response, selectDefaultView(request, response));
378 }
379
380
381
382
383
384
385
386
387
388
389 protected void nonFacesRequest(RenderRequest request, RenderResponse response, String view)
390 throws PortletException
391 {
392 if (log.isTraceEnabled()) log.trace("Non-faces request: contextPath = " + request.getContextPath());
393 setContentType(request, response);
394
395 FacesContext facesContext = facesContext(request, response);
396 setViewRootOnFacesContext(facesContext, view);
397 lifecycle.render(facesContext);
398 }
399
400
401 private void setViewRootOnFacesContext(FacesContext facesContext, String view)
402 {
403 ApplicationFactory appFactory =
404 (ApplicationFactory)FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
405 Application application = appFactory.getApplication();
406 ViewHandler viewHandler = application.getViewHandler();
407 UIViewRoot viewRoot = viewHandler.createView(facesContext, view);
408 viewRoot.setViewId(view);
409 facesContext.setViewRoot(viewRoot);
410 }
411
412 protected String selectDefaultView(RenderRequest request, RenderResponse response) throws PortletException
413 {
414 String view = this.defaultView;
415 if (this.defaultViewSelector != null)
416 {
417 String selectedView = this.defaultViewSelector.selectViewId(request, response);
418 if (selectedView != null)
419 {
420 view = selectedView;
421 }
422 }
423
424 return view;
425 }
426
427 protected FacesContext facesContext(PortletRequest request,
428 PortletResponse response)
429 {
430 return facesContextFactory.getFacesContext(portletContext,
431 request,
432 response,
433 lifecycle);
434 }
435
436 protected ReleaseableExternalContext makeExternalContext(PortletRequest request,
437 PortletResponse response)
438 {
439 return (ReleaseableExternalContext)new PortletExternalContextImpl(portletContext, request, response);
440 }
441
442 protected boolean sessionTimedOut(PortletRequest request)
443 {
444 return request.getPortletSession(false) == null;
445 }
446
447 protected boolean sessionInvalidated(PortletRequest request)
448 {
449 return sessionTimedOut(request) ||
450 (request.getPortletSession().getAttribute(REDEPLOY_FLAG) == null);
451 }
452
453 protected void setPortletRequestFlag(PortletRequest request)
454 {
455 request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
456 }
457
458
459
460
461 protected void facesRender(RenderRequest request, RenderResponse response)
462 throws PortletException, java.io.IOException
463 {
464 if (log.isTraceEnabled()) log.trace("called facesRender");
465
466 setContentType(request, response);
467
468
469
470 String viewId = request.getParameter(VIEW_ID);
471 if ((viewId == null) || sessionInvalidated(request))
472 {
473 setPortletRequestFlag(request);
474 nonFacesRequest(request, response);
475 return;
476 }
477
478 setPortletRequestFlag(request);
479
480 FacesContext facesContext = null;
481 try
482 {
483 facesContext = (FacesContext)request.
484 getPortletSession().
485 getAttribute(CURRENT_FACES_CONTEXT);
486
487 if (facesContext == null)
488 {
489 facesContext = (FacesContext)facesContext(request, response);
490 setViewRootOnFacesContext(facesContext, viewId);
491 }
492
493
494 if (facesContext.getResponseComplete()) return;
495
496 if (facesContext instanceof ServletFacesContextImpl){
497 ((ServletFacesContextImpl)facesContext).setExternalContext(makeExternalContext(request, response));
498 }
499 else
500 {
501 facesContext.getClass().getMethod("setExternalContext",
502 new Class[]{ExternalContext.class}).invoke(
503 facesContext,
504 new Object[]{makeExternalContext(request, response)});
505 }
506
507 restoreRequestAttributes(request);
508 lifecycle.render(facesContext);
509 }
510 catch (Throwable e)
511 {
512 handleExceptionFromLifecycle(e);
513 }
514 }
515
516 protected void logException(Throwable e, String msgPrefix) {
517 String msg;
518 if (msgPrefix == null)
519 {
520 if (e.getMessage() == null)
521 {
522 msg = "Exception in FacesServlet";
523 }
524 else
525 {
526 msg = e.getMessage();
527 }
528 }
529 else
530 {
531 if (e.getMessage() == null)
532 {
533 msg = msgPrefix;
534 }
535 else
536 {
537 msg = msgPrefix + ": " + e.getMessage();
538 }
539 }
540
541 portletContext.log(msg, e);
542
543 Throwable cause = e.getCause();
544 if (cause != null && cause != e)
545 {
546 logException(cause, "Root cause");
547 }
548
549 if(e instanceof PortletException)
550 {
551 cause = ((PortletException) e).getCause();
552
553 if(cause != null && cause != e)
554 {
555 logException(cause, "Root cause of PortletException");
556 }
557 }
558 }
559
560 }