1 /* 2 * $Id: FacesContext.java,v 1.76.2.2 2008/04/09 08:59:05 edburns Exp $ 3 */ 4 5 /* 6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 7 * 8 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. 9 * 10 * The contents of this file are subject to the terms of either the GNU 11 * General Public License Version 2 only ("GPL") or the Common Development 12 * and Distribution License("CDDL") (collectively, the "License"). You 13 * may not use this file except in compliance with the License. You can obtain 14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html 15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific 16 * language governing permissions and limitations under the License. 17 * 18 * When distributing the software, include this License Header Notice in each 19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. 20 * Sun designates this particular file as subject to the "Classpath" exception 21 * as provided by Sun in the GPL Version 2 section of the License file that 22 * accompanied this code. If applicable, add the following below the License 23 * Header, with the fields enclosed by brackets [] replaced by your own 24 * identifying information: "Portions Copyrighted [year] 25 * [name of copyright owner]" 26 * 27 * Contributor(s): 28 * 29 * If you wish your version of this file to be governed by only the CDDL or 30 * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 * elects to include this software in this distribution under the [CDDL or GPL 32 * Version 2] license." If you don't indicate a single choice of license, a 33 * recipient has the option to distribute your version of this file under 34 * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 * its licensees as provided above. However, if you add GPL Version 2 code 36 * and therefore, elected the GPL Version 2 license, then the option applies 37 * only if the new code is made subject to such option by the copyright 38 * holder. 39 */ 40 41 package javax.faces.context; 42 43 44 import java.util.Iterator; 45 import java.util.List; 46 import java.util.Map; 47 48 import javax.faces.application.Application; 49 import javax.faces.application.FacesMessage; 50 import javax.faces.application.ProjectStage; 51 import javax.faces.application.FacesMessage.Severity; 52 import javax.faces.component.UIComponent; 53 import javax.faces.component.UIViewRoot; 54 import javax.faces.render.RenderKit; 55 56 import javax.el.ELContext; 57 import javax.faces.event.PhaseId; 58 59 60 /** 61 * <p><strong class="changed_modified_2_0">FacesContext</strong> 62 * contains all of the per-request state information related to the 63 * processing of a single JavaServer Faces request, and the rendering of 64 * the corresponding response. It is passed to, and potentially 65 * modified by, each phase of the request processing lifecycle.</p> 66 * 67 * <p>A {@link FacesContext} instance is associated with a particular 68 * request at the beginning of request processing, by a call to the 69 * <code>getFacesContext()</code> method of the {@link FacesContextFactory} 70 * instance associated with the current web application. The instance 71 * remains active until its <code>release()</code> method is called, after 72 * which no further references to this instance are allowed. While a 73 * {@link FacesContext} instance is active, it must not be referenced 74 * from any thread other than the one upon which the servlet container 75 * executing this web application utilizes for the processing of this request. 76 * </p> 77 */ 78 79 public abstract class FacesContext { 80 81 82 @SuppressWarnings({"UnusedDeclaration"}) 83 private FacesContext defaultFacesContext; 84 private boolean processingEvents = true; 85 86 // -------------------------------------------------------------- Properties 87 88 89 /** 90 * <p><span class="changed_modified_2_0">Return</span> the {@link 91 * Application} instance associated with this web application.</p> 92 93 * <p class="changed_added_2_0">It is valid to call this method 94 * during application startup or shutdown. If called during application 95 * startup or shutdown, returns the correct current {@link 96 * javax.faces.application.Application} instance.</p> 97 98 * @throws IllegalStateException if this method is called after 99 * this instance has been released 100 */ 101 public abstract Application getApplication(); 102 103 104 /** 105 * <p class="changed_added_2_0">Return a mutable <code>Map</code> 106 * representing the attributes associated wth this 107 * <code>FacesContext</code> instance. This <code>Map</code> is 108 * useful to store attributes that you want to go out of scope when the 109 * Faces lifecycle for the current request ends, which is not always the same 110 * as the request ending, especially in the case of Servlet filters 111 * that are invoked <strong>after</strong> the Faces lifecycle for this 112 * request completes. Accessing this <code>Map</code> does not cause any 113 * events to fire, as is the case with the other maps: for request, session, and 114 * application scope. When {@link #release()} is invoked, the attributes 115 * must be cleared.</p> 116 * 117 * <div class="changed_added_2_0"> 118 * 119 * <p>The <code>Map</code> returned by this method is not associated with 120 * the request. If you would like to get or set request attributes, 121 * see {@link ExternalContext#getRequestMap}. 122 * 123 * <p>The default implementation throws 124 * <code>UnsupportedOperationException</code> and is provided 125 * for the sole purpose of not breaking existing applications that extend 126 * this class.</p> 127 * 128 * </div> 129 * 130 * @throws IllegalStateException if this method is called after 131 * this instance has been released 132 * 133 * @since 2.0 134 */ 135 136 public Map<Object, Object> getAttributes() { 137 138 if (defaultFacesContext != null) { 139 return defaultFacesContext.getAttributes(); 140 } 141 throw new UnsupportedOperationException(); 142 143 } 144 145 /** 146 * <p class="changed_added_2_0">Return the {@link PartialViewContext} 147 * for this request. The {@link PartialViewContext} is used to control 148 * the processing of specified components during the execute portion of 149 * the request processing lifecycle (known as partial processing) and 150 * the rendering of specified components (known as partial rendering). 151 * This method must return a new {@link PartialViewContext} if one 152 * does not already exist.</p> 153 * 154 * @throws IllegalStateException if this method is called after 155 * this instance has been released 156 * 157 * @since 2.0 158 */ 159 160 public PartialViewContext getPartialViewContext() { 161 162 if (defaultFacesContext != null) { 163 return defaultFacesContext.getPartialViewContext(); 164 } 165 throw new UnsupportedOperationException(); 166 167 } 168 169 170 /** 171 * <p>Return an <code>Iterator</code> over the client identifiers for 172 * which at least one {@link javax.faces.application.FacesMessage} has been queued. If there are no 173 * such client identifiers, an empty <code>Iterator</code> is returned. 174 * If any messages have been queued that were not associated with any 175 * specific client identifier, a <code>null</code> value will be included 176 * in the iterated values. The elements in the <code>Iterator</code> must 177 * be returned in the order in which they were added with {@link #addMessage}.</p> 178 * 179 * @throws IllegalStateException if this method is called after 180 * this instance has been released 181 */ 182 public abstract Iterator<String> getClientIdsWithMessages(); 183 184 /** 185 * <p>Return the <code>ELContext</code> instance for this 186 * <code>FacesContext</code> instance. This <code>ELContext</code> 187 * instance has the same lifetime and scope as the 188 * <code>FacesContext</code> instance with which it is associated, 189 * and may be created lazily the first time this method is called 190 * for a given <code>FacesContext</code> instance. Upon creation of 191 * the ELContext instance, the implementation must take the 192 * following action: </p> 193 * 194 * <ul> 195 * 196 * <li><p>Call the {@link ELContext#putContext} method on the 197 * instance, passing in <code>FacesContext.class</code> and the 198 * <code>this</code> reference for the <code>FacesContext</code> 199 * instance itself.</p></li> 200 * 201 * <li><p>If the <code>Collection</code> returned by {@link 202 * javax.faces.application.Application#getELContextListeners} is 203 * non-empty, create an instance of {@link 204 * javax.el.ELContextEvent} and pass it to each {@link 205 * javax.el.ELContextListener} instance in the 206 * <code>Collection</code> by calling the {@link 207 * javax.el.ELContextListener#contextCreated} method.</p></li> 208 * 209 * </ul> 210 * 211 * @throws IllegalStateException if this method is called after 212 * this instance has been released 213 * 214 * @since 1.2 215 */ 216 217 public ELContext getELContext() { 218 219 if (defaultFacesContext != null) { 220 return defaultFacesContext.getELContext(); 221 } 222 223 throw new UnsupportedOperationException(); 224 225 } 226 227 228 /** 229 * <p class="changed_added_2_0">Return the {@link ExceptionHandler} 230 * for this request.</p> 231 */ 232 public ExceptionHandler getExceptionHandler() { 233 234 if (defaultFacesContext != null) { 235 return defaultFacesContext.getExceptionHandler(); 236 } 237 238 throw new UnsupportedOperationException(); 239 240 } 241 242 243 /** 244 * <p class="changed_added_2_0">Set the {@link ExceptionHandler} for 245 * this request.</p> 246 * 247 * @param exceptionHandler the <code>ExceptionHandler</code> for 248 * this request. 249 */ 250 public void setExceptionHandler(ExceptionHandler exceptionHandler) { 251 252 if (defaultFacesContext != null) { 253 defaultFacesContext.setExceptionHandler(exceptionHandler); 254 } else { 255 throw new UnsupportedOperationException(); 256 } 257 258 } 259 260 261 /** 262 * <p><span class="changed_modified_2_0">Return</span> the {@link 263 * ExternalContext} instance for this <code>FacesContext</code> 264 * instance.</p> 265 266 * <p class="changed_added_2_0">It is valid to call this method 267 * during application startup or shutdown. If called during application 268 * startup or shutdown, this method returns an {@link ExternalContext} instance 269 * with the special behaviors indicated in the javadoc for that 270 * class. Methods document as being valid to call during 271 * application startup or shutdown must be supported.</p> 272 273 * @throws IllegalStateException if this method is called after 274 * this instance has been released 275 */ 276 public abstract ExternalContext getExternalContext(); 277 278 279 /** 280 * <p>Return the maximum severity level recorded on any 281 * {@link javax.faces.application.FacesMessage}s that has been queued, whether or not they are 282 * associated with any specific {@link UIComponent}. If no such messages 283 * have been queued, return <code>null</code>.</p> 284 * 285 * @throws IllegalStateException if this method is called after 286 * this instance has been released 287 */ 288 public abstract Severity getMaximumSeverity(); 289 290 291 /** 292 * <p>Return an <code>Iterator</code> over the {@link javax.faces.application.FacesMessage}s 293 * that have been queued, whether or not they are associated with any 294 * specific client identifier. If no such messages have been queued, 295 * return an empty <code>Iterator</code>. The elements of the <code>Iterator</code> 296 * must be returned in the order in which they were added with calls to {@link 297 * #addMessage}.</p> 298 * 299 * @throws IllegalStateException if this method is called after 300 * this instance has been released 301 */ 302 public abstract Iterator<FacesMessage> getMessages(); 303 304 /** 305 * <p class="changed_added_2_0">Like {@link #getMessages}, but 306 * returns a <code>List<FacesMessage></code>, 307 * enabling use from EL expressions.</p> 308 * 309 * <p>The default implementation throws 310 * <code>UnsupportedOperationException</code> and is provided 311 * for the sole purpose of not breaking existing applications that extend 312 * this class.</p> 313 * 314 * @return an immutable <code>List</code> which is effectively a snapshot 315 * of the messages present at the time of invocation. 316 * 317 * @throws IllegalStateException if this method is called after 318 * this instance has been released 319 * 320 * @since 2.0 321 */ 322 public List<FacesMessage> getMessageList() { 323 324 if (defaultFacesContext != null) { 325 return defaultFacesContext.getMessageList(); 326 } 327 throw new UnsupportedOperationException(); 328 329 } 330 331 332 /** 333 * <p class="changed_added_2_0">Like {@link 334 * #getMessages(java.lang.String)}, but returns a 335 * <code>List<FacesMessage></code> of messages for the 336 * component with client id matching argument 337 * <code>clientId</code>.</p> 338 * 339 * <p>The default implementation throws 340 * <code>UnsupportedOperationException</code> and is provided 341 * for the sole purpose of not breaking existing applications that extend 342 * this class.</p> 343 * 344 * @return an immutable <code>List</code> which is effectively a snapshot 345 * of the messages present at the time of invocation. 346 * 347 * @throws IllegalStateException if this method is called after 348 * this instance has been released 349 * 350 * @since 2.0 351 */ 352 353 public List<FacesMessage> getMessageList(String clientId) { 354 if (defaultFacesContext != null) { 355 return defaultFacesContext.getMessageList(clientId); 356 } 357 throw new UnsupportedOperationException(); 358 } 359 360 361 362 363 /** 364 * <p>Return an <code>Iterator</code> over the {@link javax.faces.application.FacesMessage}s that 365 * have been queued that are associated with the specified client identifier 366 * (if <code>clientId</code> is not <code>null</code>), or over the 367 * {@link javax.faces.application.FacesMessage}s that have been queued that are not associated with 368 * any specific client identifier (if <code>clientId</code> is 369 * <code>null</code>). If no such messages have been queued, return an 370 * empty <code>Iterator</code>. The elements of the <code>Iterator</code> 371 * must be returned in the order in which they were added with calls to {@link 372 * #addMessage}.</p> 373 * 374 * @param clientId The client identifier for which messages are 375 * requested, or <code>null</code> for messages not associated with 376 * any client identifier 377 * 378 * @throws IllegalStateException if this method is called after 379 * this instance has been released 380 */ 381 public abstract Iterator<FacesMessage> getMessages(String clientId); 382 383 384 /** 385 * <p>Return the {@link RenderKit} instance for the render kit identifier 386 * specified on our {@link UIViewRoot}, if there is one. If there is no 387 * current {@link UIViewRoot}, if the {@link UIViewRoot} does not have a 388 * specified <code>renderKitId</code>, or if there is no {@link RenderKit} 389 * for the specified identifier, return <code>null</code> instead.</p> 390 * 391 * @throws IllegalStateException if this method is called after 392 * this instance has been released 393 */ 394 public abstract RenderKit getRenderKit(); 395 396 397 /** 398 * <p>Return <code>true</code> if the <code>renderResponse()</code> 399 * method has been called for the current request.</p> 400 * 401 * @throws IllegalStateException if this method is called after 402 * this instance has been released 403 */ 404 public abstract boolean getRenderResponse(); 405 406 407 /** 408 * <p>Return <code>true</code> if the <code>responseComplete()</code> 409 * method has been called for the current request.</p> 410 * 411 * @throws IllegalStateException if this method is called after 412 * this instance has been released 413 */ 414 public abstract boolean getResponseComplete(); 415 416 /** 417 * <p class="changed_added_2_0">Return <code>true</code> if the <code>validationFailed()</code> 418 * method has been called for the current request.</p> 419 * 420 * @throws IllegalStateException if this method is called after 421 * this instance has been released 422 */ 423 public boolean isValidationFailed() { 424 if (defaultFacesContext != null) { 425 return defaultFacesContext.isValidationFailed(); 426 } 427 428 throw new UnsupportedOperationException(); 429 430 } 431 432 /** 433 * <p>Return the {@link ResponseStream} to which components should 434 * direct their binary output. Within a given response, components 435 * can use either the ResponseStream or the ResponseWriter, 436 * but not both. 437 * 438 * @throws IllegalStateException if this method is called after 439 * this instance has been released 440 */ 441 public abstract ResponseStream getResponseStream(); 442 443 444 /** 445 * <p>Set the {@link ResponseStream} to which components should 446 * direct their binary output. 447 * 448 * @param responseStream The new ResponseStream for this response 449 * 450 * @throws NullPointerException if <code>responseStream</code> 451 * is <code>null</code> 452 * 453 * @throws IllegalStateException if this method is called after 454 * this instance has been released 455 */ 456 public abstract void setResponseStream(ResponseStream responseStream); 457 458 459 /** 460 * <p>Return the {@link ResponseWriter} to which components should 461 * direct their character-based output. Within a given response, 462 * components can use either the ResponseStream or the ResponseWriter, 463 * but not both.</p> 464 * 465 * @throws IllegalStateException if this method is called after 466 * this instance has been released 467 */ 468 public abstract ResponseWriter getResponseWriter(); 469 470 471 /** 472 * <p>Set the {@link ResponseWriter} to which components should 473 * direct their character-based output. 474 * 475 * @param responseWriter The new ResponseWriter for this response 476 * 477 * @throws IllegalStateException if this method is called after 478 * this instance has been released 479 * @throws NullPointerException if <code>responseWriter</code> 480 * is <code>null</code> 481 */ 482 public abstract void setResponseWriter(ResponseWriter responseWriter); 483 484 485 /** 486 * <p><span class="changed_modified_2_0">Return</span> the root 487 * component that is associated with the this request. </p> 488 489 * <p class="changed_added_2_0">It is valid to call this method 490 * during application startup or shutdown. If called during application 491 * startup or shutdown, this method returns a new <code>UIViewRoot</code> with 492 * its locale set to <code>Locale.getDefault()</code>.</p> 493 494 * 495 * @throws IllegalStateException if this method is called after 496 * this instance has been released 497 */ 498 public abstract UIViewRoot getViewRoot(); 499 500 501 /** 502 * <p><span class="changed_modified_2_0">Set</span> the root 503 * component that is associated with this request. This method can 504 * only be called by the application handler (or a class that the 505 * handler calls), and only during the <em>Invoke Application</em> 506 * phase of the request processing lifecycle.</p> 507 508 * <p class="changed_added_2_0">If the current 509 * <code>UIViewRoot</code> is non-<code>null</code>, and calling 510 * <code>equals()</code> on the argument <code>root</code>, passing 511 * the current <code>UIViewRoot</code> returns <code>false</code>, 512 * the <code>clear</code> method must be called on the 513 * <code>Map</code> returned from {@link UIViewRoot#getViewMap}.</p> 514 * 515 * @param root The new component {@link UIViewRoot} component 516 * 517 * @throws IllegalStateException if this method is called after 518 * this instance has been released 519 * @throws NullPointerException if <code>root</code> 520 * is <code>null</code> 521 */ 522 public abstract void setViewRoot(UIViewRoot root); 523 524 525 // ---------------------------------------------------------- Public Methods 526 527 528 /** 529 * <p>Append a {@link javax.faces.application.FacesMessage} to the set of messages associated with 530 * the specified client identifier, if <code>clientId</code> is 531 * not <code>null</code>. If <code>clientId</code> is <code>null</code>, 532 * this {@link javax.faces.application.FacesMessage} is assumed to not be associated with any 533 * specific component instance.</p> 534 * 535 * @param clientId The client identifier with which this message is 536 * associated (if any) 537 * @param message The message to be appended 538 * 539 * @throws IllegalStateException if this method is called after 540 * this instance has been released 541 * @throws NullPointerException if <code>message</code> 542 * is <code>null</code> 543 */ 544 public abstract void addMessage(String clientId, FacesMessage message); 545 546 547 /** 548 * <p><span class="changed_modified_2_0">Release</span> any 549 * resources associated with this <code>FacesContext</code> 550 * instance. Faces implementations may choose to pool instances in 551 * the associated {@link FacesContextFactory} to avoid repeated 552 * object creation and garbage collection. After 553 * <code>release()</code> is called on a <code>FacesContext</code> 554 * instance (until the <code>FacesContext</code> instance has been 555 * recycled by the implementation for re-use), calling any other 556 * methods will cause an <code>IllegalStateException</code> to be 557 * thrown.</p> 558 559 * <p class="changed_added_2_0">If a call was made to {@link 560 * #getAttributes} during the processing for this request, the 561 * implementation must call <code>clear()</code> on the 562 * <code>Map</code> returned from <code>getAttributes()</code>, and 563 * then de-allocate the data-structure behind that 564 * <code>Map</code>.</p> 565 566 * <p>The implementation must call {@link #setCurrentInstance} 567 * passing <code>null</code> to remove the association between this 568 * thread and this dead <code>FacesContext</code> instance.</p> 569 * 570 * @throws IllegalStateException if this method is called after 571 * this instance has been released 572 */ 573 public abstract void release(); 574 575 576 /** 577 * <p>Signal the JavaServer faces implementation that, as soon as the 578 * current phase of the request processing lifecycle has been completed, 579 * control should be passed to the <em>Render Response</em> phase, 580 * bypassing any phases that have not been executed yet.</p> 581 * 582 * @throws IllegalStateException if this method is called after 583 * this instance has been released 584 */ 585 public abstract void renderResponse(); 586 587 /** 588 * <p class="changed_added_2_0"> 589 * This utility method simply returns the result of 590 * {@link javax.faces.render.ResponseStateManager#isPostback(FacesContext)}. 591 * </p> 592 * 593 * <p class="changed_added_2_0">The default implementation throws 594 * <code>UnsupportedOperationException</code> and is provided 595 * for the sole purpose of not breaking existing applications that extend 596 * this class.</p> 597 * 598 * @throws IllegalStateException if this method is called after 599 * this instance has been released 600 * 601 * @since 2.0 602 */ 603 public boolean isPostback() { 604 605 if (defaultFacesContext != null) { 606 return defaultFacesContext.isPostback(); 607 } 608 609 throw new UnsupportedOperationException(); 610 611 } 612 613 614 /** 615 * <p>Signal the JavaServer Faces implementation that the HTTP response 616 * for this request has already been generated (such as an HTTP redirect), 617 * and that the request processing lifecycle should be terminated as soon 618 * as the current phase is completed.</p> 619 * 620 * @throws IllegalStateException if this method is called after 621 * this instance has been released 622 */ 623 public abstract void responseComplete(); 624 625 /** 626 * <p class="changed_added_2_0">Sets a flag which indicates that a conversion or 627 * validation error occurred while processing the inputs. Inputs consist of 628 * either page parameters or form bindings. This flag can be read using 629 * {@link #isValidationFailed}.</p> 630 * 631 * @throws IllegalStateException if this method is called after 632 * this instance has been released 633 */ 634 public void validationFailed() { 635 636 if (defaultFacesContext != null) { 637 defaultFacesContext.validationFailed(); 638 } else { 639 throw new UnsupportedOperationException(); 640 } 641 642 } 643 644 /** 645 * <p class="changed_added_2_0">Return the value last set on this 646 * <code>FacesContext</code> instance when {@link #setCurrentPhaseId} 647 * was called.</p> 648 * 649 * @throws IllegalStateException if this method is called after 650 * this instance has been released 651 * 652 * @since 2.0 653 */ 654 public PhaseId getCurrentPhaseId() { 655 656 if (defaultFacesContext != null) { 657 return defaultFacesContext.getCurrentPhaseId(); 658 } 659 660 throw new UnsupportedOperationException(); 661 662 } 663 664 /** 665 * <p class="changed_added_2_0">The implementation must call this method 666 * at the earliest possble point in time after entering into a new phase 667 * in the request processing lifecycle.</p> 668 * 669 * @param currentPhaseId The {@link javax.faces.event.PhaseId} for the 670 * current phase. 671 * 672 * @throws IllegalStateException if this method is called after 673 * this instance has been released 674 * 675 * @since 2.0 676 */ 677 public void setCurrentPhaseId(PhaseId currentPhaseId) { 678 679 if (defaultFacesContext != null) { 680 defaultFacesContext.setCurrentPhaseId(currentPhaseId); 681 } else { 682 throw new UnsupportedOperationException(); 683 } 684 685 } 686 687 688 /** 689 * <p class="changed_added_2_0">Allows control of wheter or not the runtime 690 * will publish events when {@link Application#publishEvent(FacesContext, Class, Object)} or 691 * {@link Application#publishEvent(FacesContext, Class, Class, Object)} is called.</p> 692 * 693 * @param processingEvents flag indicating events should be processed or not 694 */ 695 public void setProcessingEvents(boolean processingEvents) { 696 this.processingEvents = processingEvents; 697 } 698 699 700 /** 701 * <p class="changed_added_2_0">Returns a flag indicating whether or 702 * not the runtime should publish events when asked to do so.</p> 703 * @return <code>true</code> if events should be published, otherwise 704 * <code>false</code> 705 */ 706 public boolean isProcessingEvents() { 707 return this.processingEvents; 708 } 709 710 711 /** 712 * <p class="changed_added_2_0">Return <code>true</code> if the 713 * current {@link ProjectStage} as returned by the {@link 714 * Application} instance is equal to <code>stage</code>, otherwise 715 * return <code>false</code></p> 716 717 * @param stage the {@link ProjectStage} to check 718 * 719 * @throws IllegalStateException if this method is called after 720 * this instance has been released 721 * @throws NullPointerException if <code>stage</code> is <code>null</code> 722 */ 723 public boolean isProjectStage(ProjectStage stage) { 724 725 if (stage == null) { 726 throw new NullPointerException(); 727 } 728 return (stage.equals(getApplication().getProjectStage())); 729 730 } 731 732 733 // ---------------------------------------------------------- Static Methods 734 735 736 /** 737 * <p>The <code>ThreadLocal</code> variable used to record the 738 * {@link FacesContext} instance for each processing thread.</p> 739 */ 740 private static ThreadLocal<FacesContext> instance = new ThreadLocal<FacesContext>() { 741 protected FacesContext initialValue() { return (null); } 742 }; 743 744 745 /** 746 * <p class="changed_modified_2_0">Return the {@link FacesContext} 747 * instance for the request that is being processed by the current 748 * thread. If called during application initialization or shutdown, 749 * any method documented as "valid to call this method during 750 * application startup or shutdown" must be supported during 751 * application startup or shutdown time. The result of calling a 752 * method during application startup or shutdown time that does not 753 * have this designation is undefined.</p> 754 */ 755 public static FacesContext getCurrentInstance() { 756 757 return (instance.get()); 758 759 } 760 761 762 /** 763 * <p>Set the {@link FacesContext} instance for the request that is 764 * being processed by the current thread.</p> 765 * 766 * @param context The {@link FacesContext} instance for the current 767 * thread, or <code>null</code> if this thread no longer has a 768 * <code>FacesContext</code> instance. 769 * 770 */ 771 protected static void setCurrentInstance(FacesContext context) { 772 773 if (context == null) { 774 instance.remove(); 775 } else { 776 instance.set(context); 777 } 778 779 } 780 781 782 }