Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/myfaces/portlet/MyFacesGenericPortlet.java


1   /*
2    * Copyright 2004 The Apache Software Foundation.
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  package org.apache.myfaces.portlet;
17  
18  import java.io.IOException;
19  import java.util.Enumeration;
20  
21  import javax.faces.FactoryFinder;
22  import javax.faces.application.Application;
23  import javax.faces.application.ApplicationFactory;
24  import javax.faces.application.ViewHandler;
25  import javax.faces.component.UIViewRoot;
26  import javax.faces.context.ExternalContext;
27  import javax.faces.context.FacesContext;
28  import javax.faces.context.FacesContextFactory;
29  import javax.faces.lifecycle.Lifecycle;
30  import javax.faces.lifecycle.LifecycleFactory;
31  import javax.faces.webapp.FacesServlet;
32  import javax.portlet.ActionRequest;
33  import javax.portlet.ActionResponse;
34  import javax.portlet.GenericPortlet;
35  import javax.portlet.PortletContext;
36  import javax.portlet.PortletException;
37  import javax.portlet.PortletRequest;
38  import javax.portlet.PortletResponse;
39  import javax.portlet.RenderRequest;
40  import javax.portlet.RenderResponse;
41  import javax.portlet.UnavailableException;
42  
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  import org.apache.myfaces.config.FacesConfigurator;
46  import org.apache.myfaces.context.ReleaseableExternalContext;
47  import org.apache.myfaces.context.portlet.PortletExternalContextImpl;
48  import org.apache.myfaces.context.servlet.ServletFacesContextImpl;
49  import org.apache.myfaces.webapp.webxml.WebXml;
50  
51  /**
52   * This portlet initializes MyFaces and converts portlet requests into
53   * JSF requests.
54   *
55   * @author  Stan Silvert (latest modification by $Author: ssilvert $)
56   * @version $Revision: 279594 $ $Date: 2005-09-08 13:52:24 -0400 (Thu, 08 Sep 2005) $
57   */
58  public class MyFacesGenericPortlet extends GenericPortlet
59  {
60      private static final Log log = LogFactory.getLog(MyFacesGenericPortlet.class);
61  
62      // PortletRequest parameter
63      public static final String VIEW_ID =
64          MyFacesGenericPortlet.class.getName() + ".VIEW_ID";
65  
66      // PortletSession attribute
67      protected static final String CURRENT_FACES_CONTEXT =
68          MyFacesGenericPortlet.class.getName() + ".CURRENT_FACES_CONTEXT";
69  
70      // portlet config parameter from portlet.xml
71      protected static final String DEFAULT_VIEW = "default-view";
72  
73      // portlet config parameter from portlet.xml
74      protected static final String DEFAULT_VIEW_SELECTOR = "default-view-selector";
75  
76      protected static final String FACES_INIT_DONE =
77          MyFacesGenericPortlet.class.getName() + ".FACES_INIT_DONE";
78  
79      protected PortletContext portletContext;
80  
81      protected FacesContextFactory facesContextFactory;
82      protected Lifecycle lifecycle;
83  
84      protected String defaultView;
85      protected DefaultViewSelector defaultViewSelector;
86  
87      /**
88       * Creates a new instance of MyFacesPortlet
89       */
90      public MyFacesGenericPortlet()
91      {
92      }
93  
94      /**
95       * Portlet lifecycle.
96       */
97      public void destroy()
98      {
99          super.destroy();
100         FactoryFinder.releaseFactories();
101     }
102 
103     /**
104      * Portlet lifecycle.
105      */
106     public void init() throws PortletException, UnavailableException
107     {
108         this.portletContext = getPortletContext();
109         setDefaultView();
110         setDefaultViewSelector();
111         initMyFaces();
112 
113         facesContextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
114 
115         // Javadoc says: Lifecycle instance is shared across multiple simultaneous requests, it must be
116         // implemented in a thread-safe manner.  So we can acquire it here once:
117         LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
118         lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
119     }
120 
121     protected void setDefaultView() throws UnavailableException
122     {
123         this.defaultView = getPortletConfig().getInitParameter(DEFAULT_VIEW);
124         if (defaultView == null)
125         {
126             String msg = "Fatal: must specify a JSF view id as the default view in portlet.xml";
127             throw new UnavailableException(msg);
128         }
129     }
130 
131     protected void setDefaultViewSelector() throws UnavailableException
132     {
133         String selectorClass = getPortletConfig().getInitParameter(DEFAULT_VIEW_SELECTOR);
134         if (selectorClass == null) return;
135 
136         try
137         {
138             this.defaultViewSelector = (DefaultViewSelector)Class.forName(selectorClass).newInstance();
139             this.defaultViewSelector.setPortletContext(getPortletContext());
140         }
141         catch (Exception e)
142         {
143             log.error("Failed to load " + DEFAULT_VIEW_SELECTOR, e);
144             throw new UnavailableException(e.getMessage());
145         }
146     }
147     
148     protected void setContentType(RenderRequest request, RenderResponse response)
149     {
150         
151         if (response.getContentType() == null) 
152         {
153             String portalPreferredContentType = request.getResponseContentType();
154             if (portalPreferredContentType != null) 
155             {
156                 response.setContentType(portalPreferredContentType);
157             }
158             else
159             {
160                 response.setContentType("text/html");
161             }
162         }
163     }
164 
165     protected String getLifecycleId()
166     {
167         String lifecycleId = getPortletConfig().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
168         return lifecycleId != null ? lifecycleId : LifecycleFactory.DEFAULT_LIFECYCLE;
169     }
170 
171     protected void initMyFaces()
172     {
173         try
174         {
175             Boolean b = (Boolean)portletContext.getAttribute(FACES_INIT_DONE);
176 
177             if (b == null || b.booleanValue() == false)
178             {
179                 log.trace("Initializing MyFaces");
180 
181                 //Load the configuration
182                 ExternalContext externalContext = new PortletExternalContextImpl(portletContext, null, null);
183 
184                 //And configure everything
185                 new FacesConfigurator(externalContext).configure();
186 
187                 // parse web.xml - not sure if this is needed for portlet
188                 WebXml.init(externalContext);
189 
190                 portletContext.setAttribute(FACES_INIT_DONE, Boolean.TRUE);
191             }
192             else
193             {
194                 log.info("MyFaces already initialized");
195             }
196         }
197         catch (Exception ex)
198         {
199             log.error("Error initializing MyFacesGenericPortlet", ex);
200         }
201 
202         log.info("PortletContext '" + portletContext.getRealPath("/") + "' initialized.");
203     }
204 
205     /**
206      * Called by the portlet container to allow the portlet to process an action request.
207      */
208     public void processAction(ActionRequest request, ActionResponse response)
209             throws PortletException, IOException
210     {
211         if (log.isTraceEnabled()) log.trace("called processAction");
212 
213         if (sessionTimedOut(request)) return;
214 
215         setPortletRequestFlag(request);
216 
217         FacesContext facesContext = facesContext(request, response);
218 
219         try
220         {
221             lifecycle.execute(facesContext);
222 
223             if (!facesContext.getResponseComplete())
224             {
225                 response.setRenderParameter(VIEW_ID, facesContext.getViewRoot().getViewId());
226             }
227 
228             request.getPortletSession().setAttribute(CURRENT_FACES_CONTEXT, facesContext);
229         }
230         catch (Throwable e)
231         {
232             facesContext.release();
233             handleExceptionFromLifecycle(e);
234         }
235     }
236 
237     protected void handleExceptionFromLifecycle(Throwable e)
238             throws PortletException, IOException
239     {
240         logException(e, null);
241 
242         if (e instanceof IOException)
243         {
244             throw (IOException)e;
245         }
246 
247         if (e instanceof PortletException)
248         {
249             throw (PortletException)e;
250         }
251 
252         if (e.getMessage() != null)
253         {
254             throw new PortletException(e.getMessage(), e);
255         }
256 
257         throw new PortletException(e);
258     }
259 
260     /**
261      * Helper method to serve up the view mode.
262      */
263     protected void doView(RenderRequest request, RenderResponse response)
264             throws PortletException, IOException
265     {
266         facesRender(request, response);
267     }
268 
269     /**
270      * Helper method to serve up the edit mode.  Can be overridden to add
271      * the edit mode concept to a JSF application.
272      */
273     protected void doEdit(RenderRequest request, RenderResponse response)
274             throws PortletException, IOException
275     {
276         facesRender(request, response);
277     }
278 
279     /**
280      * Helper method to serve up the edit mode.  Can be overridden to add
281      * the help mode concept to a JSF application.
282      */
283     protected void doHelp(RenderRequest request, RenderResponse response)
284             throws PortletException, IOException
285     {
286         facesRender(request, response);
287     }
288 
289     /**
290      * This method follows JSF Spec section 2.1.1.  It renders the default view from a non-faces
291      * request.
292      *
293      * @param request The portlet render request.
294      * @param response The portlet render response.
295      */
296     protected void nonFacesRequest(RenderRequest request, RenderResponse response) throws PortletException
297     {
298         nonFacesRequest(request, response, selectDefaultView(request, response));
299     }
300 
301     /**
302      * This method follows JSF Spec section 2.1.1.  It renders a view from a non-faces
303      * request.  This is useful for a default view as well as for views that need to
304      * be rendered from the portlet's edit and help buttons.
305      *
306      * @param request The portlet render request.
307      * @param response The portlet render response.
308      * @param view The name of the view that needs to be rendered.
309      */
310     protected void nonFacesRequest(RenderRequest request, RenderResponse response, String view)
311             throws PortletException
312     {
313         if (log.isTraceEnabled()) log.trace("Non-faces request: contextPath = " + request.getContextPath());
314         setContentType(request, response); // do this in case nonFacesRequest is called by a subclass
315         ApplicationFactory appFactory =
316             (ApplicationFactory)FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
317         Application application = appFactory.getApplication();
318         ViewHandler viewHandler = application.getViewHandler();
319         FacesContext facesContext = facesContext(request, response);
320         UIViewRoot viewRoot = viewHandler.createView(facesContext, view);
321         viewRoot.setViewId(view);
322         facesContext.setViewRoot(viewRoot);
323         lifecycle.render(facesContext);
324     }
325 
326     protected String selectDefaultView(RenderRequest request, RenderResponse response) throws PortletException
327     {
328         String view = this.defaultView;
329         if (this.defaultViewSelector != null)
330         {
331             String selectedView = this.defaultViewSelector.selectViewId(request, response);
332             if (selectedView != null)
333             {
334                 view = selectedView;
335             }
336         }
337 
338         return view;
339     }
340 
341     protected FacesContext facesContext(PortletRequest request,
342                                         PortletResponse response)
343     {
344         return facesContextFactory.getFacesContext(portletContext,
345                                                    request,
346                                                    response,
347                                                    lifecycle);
348     }
349 
350     protected ReleaseableExternalContext makeExternalContext(PortletRequest request,
351                                                              PortletResponse response)
352     {
353         return (ReleaseableExternalContext)new PortletExternalContextImpl(portletContext, request, response);
354     }
355 
356     protected boolean sessionTimedOut(PortletRequest request)
357     {
358         return request.getPortletSession(false) == null;
359     }
360 
361     protected void setPortletRequestFlag(PortletRequest request)
362     {
363         request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
364     }
365 
366     /**
367      * Render a JSF view.
368      */
369     protected void facesRender(RenderRequest request, RenderResponse response)
370             throws PortletException, java.io.IOException
371     {
372         if (log.isTraceEnabled()) log.trace("called facesRender");
373 
374         setContentType(request, response);
375 
376         String viewId = request.getParameter(VIEW_ID);
377         if ((viewId == null) || sessionTimedOut(request))
378         {
379             setPortletRequestFlag(request);
380             nonFacesRequest(request,  response);
381             return;
382         }
383 
384         setPortletRequestFlag(request);
385 
386         try
387         {
388             ServletFacesContextImpl facesContext = (ServletFacesContextImpl)request.
389                                                    getPortletSession().
390                                                    getAttribute(CURRENT_FACES_CONTEXT);
391 
392             // TODO: not sure if this can happen.  Also double check this against spec section 2.1.3
393             if (facesContext.getResponseComplete()) return;
394 
395             facesContext.setExternalContext(makeExternalContext(request, response));
396             lifecycle.render(facesContext);
397         }
398         catch (Throwable e)
399         {
400             handleExceptionFromLifecycle(e);
401         }
402     }
403 
404     protected void logException(Throwable e, String msgPrefix) {
405         String msg;
406         if (msgPrefix == null)
407         {
408             if (e.getMessage() == null)
409             {
410                 msg = "Exception in FacesServlet";
411             }
412             else
413             {
414                 msg = e.getMessage();
415             }
416         }
417         else
418         {
419             if (e.getMessage() == null)
420             {
421                 msg = msgPrefix;
422             }
423             else
424             {
425                 msg = msgPrefix + ": " + e.getMessage();
426             }
427         }
428 
429         portletContext.log(msg, e);
430 
431         Throwable cause = e.getCause();
432         if (cause != null && cause != e)
433         {
434             logException(cause, "Root cause");
435         }
436 
437         if(e instanceof PortletException)
438         {
439             cause = ((PortletException) e).getCause();
440 
441             if(cause != null && cause != e)
442             {
443                 logException(cause, "Root cause of PortletException");
444             }
445         }
446     }
447 
448 }