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