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