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