001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
003     * agreements. See the NOTICE file distributed with this work for additional information regarding
004     * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
005     * "License"); you may not use this file except in compliance with the License. You may obtain a
006     * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
007     * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
008     * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
009     * for the specific language governing permissions and limitations under the License.
010     */
011    package javax.portlet.faces;
012    
013    import java.io.BufferedReader;
014    import java.io.IOException;
015    import java.io.InputStream;
016    import java.io.InputStreamReader;
017    import java.io.UnsupportedEncodingException;
018    
019    import java.util.ArrayList;
020    import java.util.Enumeration;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    import javax.portlet.ActionRequest;
026    import javax.portlet.ActionResponse;
027    import javax.portlet.EventRequest;
028    import javax.portlet.EventResponse;
029    import javax.portlet.GenericPortlet;
030    import javax.portlet.PortletConfig;
031    import javax.portlet.PortletContext;
032    import javax.portlet.PortletException;
033    import javax.portlet.PortletMode;
034    import javax.portlet.PortletRequest;
035    import javax.portlet.PortletRequestDispatcher;
036    import javax.portlet.PortletResponse;
037    import javax.portlet.RenderRequest;
038    import javax.portlet.RenderResponse;
039    import javax.portlet.ResourceRequest;
040    import javax.portlet.ResourceResponse;
041    import javax.portlet.WindowState;
042    
043    /**
044     * The <code>GenericFacesPortlet</code> is provided to simplify development of a portlet that in
045     * whole or part relies on the Faces bridge to process requests. If all requests are to be handled
046     * by the bridge, <code>GenericFacesPortlet</code> is a turnkey implementation. Developers do not
047     * need to subclass it. However, if there are some situations where the portlet doesn't require
048     * bridge services then <code>GenericFacesPortlet</code> can be subclassed and overriden.
049     * <p>
050     * Since <code>GenericFacesPortlet</code> subclasses <code>GenericPortlet</code> care is taken
051     * to all subclasses to override naturally. For example, though <code>doDispatch()</code> is
052     * overriden, requests are only dispatched to the bridge from here if the <code>PortletMode</code>
053     * isn't <code>VIEW</code>, <code>EDIT</code>, or <code>HELP</code>.
054     * <p>
055     * The <code>GenericFacesPortlet</code> recognizes the following portlet initialization
056     * parameters:
057     * <ul>
058     * <li><code>javax.portlet.faces.defaultViewId.[<i>mode</i>]</code>: specifies on a per mode
059     * basis the default viewId the Bridge executes when not already encoded in the incoming request. A
060     * value must be defined for each <code>PortletMode</code> the <code>Bridge</code> is expected
061     * to process. </li>
062     *  <li><code>javax.portlet.faces.excludedRequestAttributes</code>: specifies on a per portlet
063     * basis the set of request attributes the bridge is to exclude from its request scope.  The
064     * value of this parameter is a comma delimited list of either fully qualified attribute names or
065     * a partial attribute name of the form <i>packageName.*</i>.  In this later case all attributes
066     * exactly prefixed by <i>packageName</i> are excluded, non recursive.</li>
067     *  <li><code>javax.portlet.faces.preserveActionParams</code>: specifies on a per portlet
068     * basis whether the bridge should preserve parameters received in an action request
069     * and restore them for use during subsequent renders.</li>
070     *  <li><code>javax.portlet.faces.defaultContentType</code>: specifies on a per mode
071     * basis the content type the bridge should set for all render requests it processes. </li>
072     *  <li><code>javax.portlet.faces.defaultCharacterSetEncoding</code>: specifies on a per mode
073     * basis the default character set encoding the bridge should set for all render requests it
074     * processes</li>
075     * </ul>
076     * The <code>GenericFacesPortlet</code> recognizes the following application
077     * (<code>PortletContext</code>) initialization parameters:
078     * <ul>
079     * <li><code>javax.portlet.faces.BridgeImplClass</code>: specifies the <code>Bridge</code>implementation
080     * class used by this portlet. Typically this initialization parameter isn't set as the 
081     * <code>GenericFacesPortlet</code> defaults to finding the class name from the bridge
082     * configuration.  However if more then one bridge is configured in the environment such 
083     * per application configuration is necessary to force a specific bridge to be used.
084     * </li>
085     * </ul>
086     */
087    public class GenericFacesPortlet extends GenericPortlet
088    {
089      /** Application (PortletContext) init parameter that names the bridge class used
090       * by this application.  Typically not used unless more then 1 bridge is configured
091       * in an environment as its more usual to rely on the self detection.
092       */
093      public static final String BRIDGE_CLASS = Bridge.BRIDGE_PACKAGE_PREFIX + "BridgeClassName";
094      
095      
096      /** Portlet init parameter that defines the default ViewId that should be used
097       * when the request doesn't otherwise convery the target.  There must be one 
098       * initialization parameter for each supported mode.  Each parameter is named
099       * DEFAULT_VIEWID.<i>mode</i>, where <i>mode</i> is the name of the corresponding
100       * <code>PortletMode</code>
101       */
102      public static final String DEFAULT_VIEWID = Bridge.BRIDGE_PACKAGE_PREFIX + "defaultViewId";
103    
104    
105      /** Portlet init parameter that defines the render response ContentType the bridge 
106       * sets prior to rendering.  If not set the bridge uses the request's preferred
107       * content type.
108       */
109      public static final String DEFAULT_CONTENT_TYPE = 
110        Bridge.BRIDGE_PACKAGE_PREFIX + "defaultContentType";
111    
112      /** Portlet init parameter that defines the render response CharacterSetEncoding the bridge 
113       * sets prior to rendering.  Typcially only set when the jsp outputs an encoding other
114       * then the portlet container's and the portlet container supports response encoding
115       * transformation.
116       */
117      public static final String DEFAULT_CHARACTERSET_ENCODING = 
118        Bridge.BRIDGE_PACKAGE_PREFIX + "defaultCharacterSetEncoding";
119      
120        /** Portlet init parameter containing the setting for whether the <code>GenericFacesPortlet</code>
121         * overrides event processing by dispatching all events to the bridge or delegates
122         * all event processing to the <code>GenericPortlet</code>.  Default is <code>true</code>.
123         */
124      public static final String BRIDGE_AUTO_DISPATCH_EVENTS = Bridge.BRIDGE_PACKAGE_PREFIX + "autoDispatchEvents";
125    
126      /** Location of the services descriptor file in a brige installation that defines 
127       * the class name of the bridge implementation.
128       */
129      public static final String BRIDGE_SERVICE_CLASSPATH = 
130        "META-INF/services/javax.portlet.faces.Bridge";
131      
132      private static final String LOGGING_ENABLED = "org.apache.myfaces.portlet.faces.loggingEnabled";
133    
134      private Class<? extends Bridge> mFacesBridgeClass = null;
135      private Bridge mFacesBridge = null;
136      private HashMap<String, String> mDefaultViewIdMap = null;
137      private Object mLock = new Object();  // used to synchronize on when initializing the bridge.
138    
139      /**
140       * Initialize generic faces portlet from portlet.xml
141       */
142      @SuppressWarnings("unchecked")
143      @Override
144      public void init(PortletConfig portletConfig) throws PortletException
145      {
146        super.init(portletConfig);
147    
148        // Make sure the bridge impl class is defined -- if not then search for it
149        // using same search rules as Faces
150        String bridgeClassName = getBridgeClassName();
151    
152        if (bridgeClassName != null)
153        {
154          try
155          {
156            ClassLoader loader = Thread.currentThread().getContextClassLoader();
157            mFacesBridgeClass = (Class<? extends Bridge>) loader.loadClass(bridgeClassName);
158          } catch (ClassNotFoundException cnfe)
159          {
160            throw new PortletException("Unable to load configured bridge class: " + bridgeClassName);
161          }
162        }
163        else
164        {
165          throw new PortletException("Can't locate configuration parameter defining the bridge class to use for this portlet:" + getPortletName());
166        }
167    
168        // Get the other bridge configuration parameters and set as context attributes
169        List<String> excludedAttrs = getExcludedRequestAttributes();
170        if (excludedAttrs != null)
171        {
172          getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
173                                           Bridge.EXCLUDED_REQUEST_ATTRIBUTES, excludedAttrs);
174        }
175    
176        Boolean preserveActionParams = new Boolean(isPreserveActionParameters());
177        getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
178                                         Bridge.PRESERVE_ACTION_PARAMS, preserveActionParams);
179        
180        String defaultRenderKitId = getDefaultRenderKitId();
181        if (defaultRenderKitId != null)
182        {
183          getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
184                                         Bridge.DEFAULT_RENDERKIT_ID, defaultRenderKitId);
185        }
186    
187        Map defaultViewIdMap = getDefaultViewIdMap();
188        getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
189                                         Bridge.DEFAULT_VIEWID_MAP, defaultViewIdMap);
190        
191        BridgeEventHandler eventHandler = getBridgeEventHandler();
192        if (eventHandler != null)
193        {
194          getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
195                                           Bridge.BRIDGE_EVENT_HANDLER, eventHandler);
196        }
197        
198        BridgePublicRenderParameterHandler prpHandler = getBridgePublicRenderParameterHandler();
199        if (prpHandler != null)
200        {
201          getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
202                                           Bridge.BRIDGE_PUBLIC_RENDER_PARAMETER_HANDLER, prpHandler);
203        }
204        
205        // See if this portlet has enabled informational logging messages
206        String s = getPortletConfig().getInitParameter(LOGGING_ENABLED);
207        Boolean b = Boolean.valueOf(s);
208        getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
209                                           LOGGING_ENABLED, b);
210    
211        // Initialize the bridge as the double lock mechanism used for lazy instantiation doesn't (always) work in Java even if 
212        // declared a volitle -- and the bridge is likely to be used anyway -- so why worry about it
213        initBridge();
214      }
215    
216      /**
217       * Release resources, specifically it destroys the bridge.
218       */
219      @Override
220      public void destroy()
221      {
222        if (mFacesBridge != null)
223        {
224          mFacesBridge.destroy();
225          mFacesBridge = null;
226          mFacesBridgeClass = null;
227        }
228        mDefaultViewIdMap = null;
229        
230        super.destroy();
231      }
232    
233      /**
234       * If mode is VIEW, EDIT, or HELP -- defer to the doView, doEdit, doHelp so subclasses can
235       * override. Otherwise handle mode here if there is a defaultViewId mapping for it.
236       */
237      @Override
238      public void doDispatch(RenderRequest request, RenderResponse response) throws PortletException, 
239                                                                                    IOException
240      {
241        // Defer to helper methods for standard modes so subclasses can override
242        PortletMode mode = request.getPortletMode();
243        if (mode.equals(PortletMode.EDIT) || mode.equals(PortletMode.HELP) || mode.equals(PortletMode.VIEW))
244        {
245          super.doDispatch(request, response);
246        } else
247        {
248          // Bridge didn't process this one -- so forge ahead
249          if (!doRenderDispatchInternal(request, response))
250          {
251            super.doDispatch(request, response);
252          }
253        }
254      }
255    
256      @Override
257      protected void doEdit(RenderRequest request, RenderResponse response) throws PortletException, 
258                                                                                   java.io.IOException
259      {
260        doRenderDispatchInternal(request, response);
261      }
262    
263      @Override
264      protected void doHelp(RenderRequest request, RenderResponse response) throws PortletException, 
265                                                                                   java.io.IOException
266      {
267        doRenderDispatchInternal(request, response);
268      }
269    
270      @Override
271      protected void doView(RenderRequest request, RenderResponse response) throws PortletException, 
272                                                                                   java.io.IOException
273      {
274        doRenderDispatchInternal(request, response);
275      }
276    
277      @Override
278      public void processAction(ActionRequest request, 
279                                ActionResponse response) throws PortletException, IOException
280      {
281        doActionDispatchInternal(request, response);
282      }
283    
284      /**
285       * Handles resource requests and dispatches to the Bridge
286       */
287      @Override
288      public void serveResource(ResourceRequest request, 
289                                ResourceResponse response) throws PortletException, IOException
290      {
291        doBridgeDispatch(request, response);
292    
293      }
294    
295      /**
296       * Returns an instance of a BridgeEventHandler used to process portlet events
297       * in a JSF environment.
298       * This default implementation looks for a portlet initParameter that
299       * names the class used to instantiate the handler.
300       * @return an instance of BridgeEventHandler or null if there is none.
301       */
302      public BridgeEventHandler getBridgeEventHandler()
303      {
304        String eventHandlerClass = 
305          getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.BRIDGE_EVENT_HANDLER);
306        if (eventHandlerClass != null)
307        {
308          try
309          {
310            ClassLoader loader = Thread.currentThread().getContextClassLoader();
311            Class<? extends BridgeEventHandler> c = 
312              (Class<? extends BridgeEventHandler>) loader.loadClass(eventHandlerClass);
313            return c.newInstance();
314          } catch (ClassNotFoundException cnfe)
315          {
316            // Do nothing and fall through to null check
317            // TODO: log something
318          } catch (InstantiationException ie)
319          {
320            // Do nothing and fall through to null check
321            // TODO: log something
322          } catch (Exception e)
323          {
324            // Do nothing and fall through to null check
325            // TODO: log something
326          }
327        }
328    
329        return null;
330      }
331      
332      /**
333       * Returns an instance of a BridgePublicRenderParameterHandler used to post
334       * process public render parameter changes that the bridge
335       * has pushed into mapped models.
336       * This default implementation looks for a portlet initParameter that
337       * names the class used to instantiate the handler.
338       * @return an instance of BridgeRenderParameterHandler or null if there is none.
339       */
340      public BridgePublicRenderParameterHandler getBridgePublicRenderParameterHandler()
341      {
342        String prpHandlerClass = 
343          getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.BRIDGE_PUBLIC_RENDER_PARAMETER_HANDLER);
344        if (prpHandlerClass != null)
345        {
346          try
347          {
348            ClassLoader loader = Thread.currentThread().getContextClassLoader();
349            Class<? extends BridgePublicRenderParameterHandler> c = 
350              (Class<? extends BridgePublicRenderParameterHandler>) loader.loadClass(prpHandlerClass);
351            return c.newInstance();
352          } catch (ClassNotFoundException cnfe)
353          {
354            // Do nothing and fall through to null check
355            // TODO: log something
356          } catch (InstantiationException ie)
357          {
358            // Do nothing and fall through to null check
359            // TODO: log something
360          } catch (Exception e)
361          {
362            // Do nothing and fall through to null check
363            // TODO: log something
364          }
365        }
366    
367        return null;
368      }
369    
370    
371    
372      /**
373       * Returns the set of RequestAttribute names that the portlet wants the bridge to
374       * exclude from its managed request scope.  This default implementation picks up
375       * this list from the comma delimited init_param javax.portlet.faces.excludedRequestAttributes.
376       * 
377       * @return a List containing the names of the attributes to be excluded. null if it can't be
378       *         determined.
379       */
380      public List<String> getExcludedRequestAttributes()
381      {
382        String excludedAttrs = 
383          getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.EXCLUDED_REQUEST_ATTRIBUTES);
384        if (excludedAttrs == null)
385        {
386          return null;
387        }
388    
389        String[] attrArray = excludedAttrs.split(",");
390        // process comma delimited String into a List
391        ArrayList<String> list = new ArrayList(attrArray.length);
392        for (int i = 0; i < attrArray.length; i++)
393        {
394          list.add(attrArray[i].trim());
395        }
396        return list;
397      }
398    
399      /**
400       * Returns a boolean indicating whether or not the bridge should preserve all the
401       * action parameters in the subsequent renders that occur in the same scope.  This
402       * default implementation reads the values from the portlet init_param
403       * javax.portlet.faces.preserveActionParams.  If not present, false is returned.
404       * 
405       * @return a boolean indicating whether or not the bridge should preserve all the
406       * action parameters in the subsequent renders that occur in the same scope.
407       */
408      public boolean isPreserveActionParameters()
409      {
410        String preserveActionParams = 
411          getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + 
412                                              Bridge.PRESERVE_ACTION_PARAMS);
413        if (preserveActionParams == null)
414        {
415          return false;
416        } else
417        {
418          return Boolean.parseBoolean(preserveActionParams);
419        }
420      }
421      
422      /**
423       * Returns a String defining the default render kit id the bridge should ensure for this portlet.
424       * If non-null, this value is used to override any default render kit id set on an app wide basis 
425       * in the faces-config.xml. This
426       * default implementation reads the values from the portlet init_param
427       * javax.portlet.faces.defaultRenderKitId.  If not present, null is returned.
428       * 
429       * @return a boolean indicating whether or not the bridge should preserve all the
430       * action parameters in the subsequent renders that occur in the same scope.
431       */
432      public String getDefaultRenderKitId()
433      {
434        return 
435          getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + 
436                                              Bridge.DEFAULT_RENDERKIT_ID);
437      }   
438    
439      /**
440       * Returns the className of the bridge implementation this portlet uses. Subclasses override to
441       * alter the default behavior. Default implementation first checks for a portlet context init
442       * parameter: javax.portlet.faces.BridgeImplClass. If it doesn't exist then it looks for the
443       * resource file "META-INF/services/javax.portlet.faces.Bridge" using the current threads
444       * classloader and extracts the classname from the first line in that file.
445       * 
446       * @return the class name of the Bridge class the GenericFacesPortlet uses. null if it can't be
447       *         determined.
448       */
449      public String getBridgeClassName()
450      {
451        String bridgeClassName = getPortletConfig().getPortletContext().getInitParameter(BRIDGE_CLASS);
452    
453        if (bridgeClassName == null)
454        {
455          bridgeClassName = 
456              getFromServicesPath(getPortletConfig().getPortletContext(), BRIDGE_SERVICE_CLASSPATH);
457        }
458        return bridgeClassName;
459      }
460    
461      /**
462       * @deprecated -- no longer used or called by the <code>GenericFacesPortlet</code>
463       * but retained in case a subclass has called it. 
464       * 
465       * 
466       * @return request.getResponseContentType().
467       */
468      @Deprecated
469      public String getResponseContentType(PortletRequest request)
470      {
471        return request.getResponseContentType();
472      }
473      
474      private boolean isInRequestedContentTypes(PortletRequest request, String contentTypeToCheck)
475      {
476        Enumeration e = request.getResponseContentTypes();
477        while (e.hasMoreElements()) 
478        {
479          if (contentTypeToCheck.equalsIgnoreCase((String) e.nextElement()))
480          {
481            return true;
482          }
483        }
484        return false;
485      }
486    
487      /**
488       * @deprecated -- no longer used or called by the <code>GenericFacesPortlet</code>
489       * but retained in case a subclass has called it. 
490       * 
491       * 
492       * @return null.
493       */
494      @Deprecated
495      public String getResponseCharacterSetEncoding(PortletRequest request)
496      {
497        return null;
498      }
499    
500    
501      /**
502       * Returns the defaultViewIdMap the bridge should use when its unable to resolve to a specific
503       * target in the incoming request. There is one entry per support <code>PortletMode
504       * </code>.  The entry key is the name of the mode.  The entry value is the default viewId
505       * for that mode.
506       * 
507       * @return the defaultViewIdMap
508       */
509      public Map getDefaultViewIdMap()
510      {
511        if (mDefaultViewIdMap == null)
512        {
513          mDefaultViewIdMap = new HashMap<String, String>();
514          // loop through all portlet initialization parameters looking for those in the
515          // correct form
516          PortletConfig config = getPortletConfig();
517    
518          Enumeration<String> e = config.getInitParameterNames();
519          int len = DEFAULT_VIEWID.length();
520          while (e.hasMoreElements())
521          {
522            String s = e.nextElement();
523            if (s.startsWith(DEFAULT_VIEWID) && s.length() > DEFAULT_VIEWID.length())
524            {
525              String viewId = config.getInitParameter(s);
526              
527              // Don't add if there isn't a view
528              if (viewId == null || viewId.length() == 0) continue;
529              
530              // extract the mode
531              s = s.substring(len + 1);
532              mDefaultViewIdMap.put(s, viewId);
533            }
534          }
535        }
536    
537        return mDefaultViewIdMap;
538      }
539      
540      /**
541       * Returns the value of the portlet initialization parameter
542       * <code>javax.portlet.faces.autoDispatchEvents</code> if non-null or
543       * <code>true</code>, otherwise.
544       * 
545       * @return boolean indicating whether to auto-dispatch all events to the bridge 
546       * or not.
547       */
548      public boolean isAutoDispatchEvents()
549      {
550        String configParam = 
551          getPortletConfig().getInitParameter(BRIDGE_AUTO_DISPATCH_EVENTS);
552    
553        if (configParam != null)
554        {
555          return Boolean.parseBoolean(configParam);
556        }
557        else
558        {
559          return true;
560        }
561      }
562      
563      /**
564       * Returns an initialized bridge instance adequately prepared so the caller can
565       * call doFacesRequest directly without further initialization.
566       * 
567       * @return instance of the bridge.
568       * @throws PortletException exception acquiring or initializting the bridge.
569       */
570      public Bridge getFacesBridge(PortletRequest request, 
571                                   PortletResponse response) throws PortletException
572      {
573        initBridgeRequest(request, response);
574        return mFacesBridge;
575      }  
576      
577      public void processEvent(EventRequest request, EventResponse response)
578        throws PortletException, java.io.IOException
579      {
580        if (isAutoDispatchEvents())
581        {
582          try
583          {
584            getFacesBridge(request, response).doFacesRequest(request, response);
585          } catch (BridgeException e)
586          {
587            throw new PortletException("doBridgeDispatch failed:  error from Bridge in executing the request", 
588                                       e);
589          }
590        }
591        else
592        {
593          super.processEvent(request, response);
594        }
595      }
596    
597      private boolean isNonFacesRequest(PortletRequest request, PortletResponse response)
598      {
599        // Non Faces request is identified by either the presence of the _jsfBridgeNonFacesView
600        // parameter or the request being for a portlet mode which doesn't have a default
601        // Faces view configured for it.
602        if (request.getParameter(Bridge.NONFACES_TARGET_PATH_PARAMETER) != null)
603        {
604          return true;
605        }
606    
607        String modeDefaultViewId = mDefaultViewIdMap.get(request.getPortletMode().toString());
608        return modeDefaultViewId == null;
609      }
610    
611      private void doActionDispatchInternal(ActionRequest request, 
612                                            ActionResponse response) throws PortletException, 
613                                                                            IOException
614      {
615        // First determine whether this is a Faces or nonFaces request
616        if (isNonFacesRequest(request, response))
617        {
618          throw new PortletException("GenericFacesPortlet:  Action request is not for a Faces target.  Such nonFaces requests must be handled by a subclass.");
619        } else
620        {
621          doBridgeDispatch(request, response);
622        }
623      }
624    
625      private boolean doRenderDispatchInternal(RenderRequest request, 
626                                               RenderResponse response) throws PortletException, 
627                                                                               IOException
628      {
629        // First determine whether this is a Faces or nonFaces request
630        if (isNonFacesRequest(request, response))
631        {
632          return doNonFacesDispatch(request, response);
633        } else
634        {
635          WindowState state = request.getWindowState();
636          if (!state.equals(WindowState.MINIMIZED))
637          {
638            doBridgeDispatch(request, response);
639          }
640          return true;
641        }
642      }
643    
644      private boolean doNonFacesDispatch(RenderRequest request, 
645                                         RenderResponse response) throws PortletException
646      {
647        // Can only dispatch if the path is encoded in the request parameter
648        String targetPath = request.getParameter(Bridge.NONFACES_TARGET_PATH_PARAMETER);
649        if (targetPath == null)
650        {
651          // Didn't handle this request
652          return false;
653        }
654    
655        try
656        {
657          PortletRequestDispatcher dispatcher = 
658            this.getPortletContext().getRequestDispatcher(targetPath);
659          dispatcher.forward(request, response);
660          return true;
661        } catch (Exception e)
662        {
663          throw new PortletException("Unable to dispatch to: " + targetPath, e);
664        }
665      }
666    
667      private void doBridgeDispatch(RenderRequest request, 
668                                    RenderResponse response) throws PortletException
669      {
670        try
671        {
672          getFacesBridge(request, response).doFacesRequest(request, response);
673        } catch (BridgeException e)
674        {
675          throw new PortletException("doBridgeDispatch failed:  error from Bridge in executing the request", 
676                                     e);
677        }
678    
679      }
680    
681      private void doBridgeDispatch(ActionRequest request, 
682                                    ActionResponse response) throws PortletException
683      {
684        try
685        {
686          getFacesBridge(request, response).doFacesRequest(request, response);
687        } catch (BridgeException e)
688        {
689          throw new PortletException("doBridgeDispatch failed:  error from Bridge in executing the request", 
690                                     e);
691        }
692    
693      }
694    
695      private void doBridgeDispatch(ResourceRequest request, 
696                                    ResourceResponse response) throws PortletException
697      {
698        try
699        {
700          getFacesBridge(request, response).doFacesRequest(request, response);
701        } catch (BridgeException e)
702        {
703          throw new PortletException("doBridgeDispatch failed:  error from Bridge in executing the request", 
704                                     e);
705        }
706    
707      }
708    
709      private void initBridgeRequest(PortletRequest request, 
710                                     PortletResponse response) throws PortletException
711      {
712        // Now do any per request initialization
713        // In this case look to see if the request is encoded (usually 
714        // from a NonFaces view response) with the specific Faces
715        // view to execute.
716        String view = request.getParameter(Bridge.FACES_VIEW_ID_PARAMETER);
717        if (view != null)
718        {
719          request.setAttribute(Bridge.VIEW_ID, view);
720        } else
721        {
722          view = request.getParameter(Bridge.FACES_VIEW_PATH_PARAMETER);
723          if (view != null)
724          {
725            request.setAttribute(Bridge.VIEW_PATH, view);
726          }
727        }
728      }
729    
730      private void initBridge() throws PortletException
731      {
732        // Ensure te Bridge has been constrcuted and initialized
733        if (mFacesBridge == null)
734        {
735          try
736          {
737            // ensure we only ever create/init one bridge per portlet
738            if (mFacesBridge == null)
739            {
740              mFacesBridge = mFacesBridgeClass.newInstance();
741              mFacesBridge.init(getPortletConfig());
742            }
743          }
744          catch (Exception e)
745          {
746            throw new PortletException("doBridgeDisptach:  error instantiating the bridge class", e);
747          }
748        }
749      }
750    
751      private String getFromServicesPath(PortletContext context, String resourceName)
752      {
753        // Check for a services definition
754        String result = null;
755        BufferedReader reader = null;
756        InputStream stream = null;
757        try
758        {
759          ClassLoader cl = Thread.currentThread().getContextClassLoader();
760          if (cl == null)
761          {
762            return null;
763          }
764    
765          stream = cl.getResourceAsStream(resourceName);
766          if (stream != null)
767          {
768            // Deal with systems whose native encoding is possibly
769            // different from the way that the services entry was created
770            try
771            {
772              reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
773            } catch (UnsupportedEncodingException e)
774            {
775              reader = new BufferedReader(new InputStreamReader(stream));
776            }
777            result = reader.readLine();
778            if (result != null)
779            {
780              result = result.trim();
781            }
782            reader.close();
783            reader = null;
784            stream = null;
785          }
786        } catch (IOException e)
787        {
788        } catch (SecurityException e)
789        {
790        } finally
791        {
792          if (reader != null)
793          {
794            try
795            {
796              reader.close();
797              stream = null;
798            } catch (Throwable t)
799            {
800              ;
801            }
802            reader = null;
803          }
804          if (stream != null)
805          {
806            try
807            {
808              stream.close();
809            } catch (Throwable t)
810            {
811              ;
812            }
813            stream = null;
814          }
815        }
816        return result;
817      }
818    
819    }