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 }