View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.context;
20  
21  import java.awt.Color;
22  
23  import java.io.IOException;
24  
25  import java.math.RoundingMode;
26  
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.Map;
33  import java.util.Set;
34  import java.util.TimeZone;
35  import java.util.concurrent.ConcurrentHashMap;
36  import java.util.concurrent.ConcurrentMap;
37  
38  import javax.faces.component.UIComponent;
39  import javax.faces.component.UIViewRoot;
40  import javax.faces.component.visit.VisitContext;
41  import javax.faces.component.visit.VisitHint;
42  import javax.faces.context.ExternalContext;
43  import javax.faces.context.FacesContext;
44  import javax.faces.event.PhaseId;
45  
46  import org.apache.myfaces.trinidad.change.ChangeManager;
47  import org.apache.myfaces.trinidad.config.RegionManager;
48  import org.apache.myfaces.trinidad.event.WindowLifecycleListener;
49  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
50  import org.apache.myfaces.trinidad.util.ArrayMap;
51  import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
52  import org.apache.myfaces.trinidad.webapp.UploadedFileProcessor;
53  
54  
55  /**
56   * Context class for all per-request and per-webapp information
57   * required by Trinidad.  A <code>RequestContext</code> object can be
58   * retrieved with the static {@link #getCurrentInstance} method.
59   * There is one and only one <code>RequestContext</code> object
60   * active in any one thread.
61   * <p>
62   * This class does not extend <code>FacesContext</code>;  this is intentional,
63   * as extending <code>FacesContext</code> requires taking over the
64   * <code>FacesContextFactory</code>.
65   * <p>
66   */
67  // TODO Refactor this class after everything gets added to it.
68  // TODO There's some values in here that seem to affect only output (e.g.,
69  //  right-to-left); that's not great, since ideally that detail would be
70  //  buried in something more renderer-specific.
71  abstract public class RequestContext
72  {
73    /**
74     * Name of the EL implicit variable ("requestContext") that is used to
75     * expose this context object.
76     */
77    static public final String VARIABLE_NAME =
78      "requestContext";
79  
80    // Omitted APIs:
81    //
82    // LocaleContext
83    // =============
84    // Locale getTranslationLocale
85    //
86    // DateFormatContext:
87    // =================
88    // int getTwoDigitYearStart
89    // boolean isLenient (very lame API, definitely gone)
90  
91  
92    /**
93     * Retrieves the RequestContext active for the current thread.
94     */
95    static public RequestContext getCurrentInstance()
96    {
97      return _CURRENT_CONTEXT.get();
98    }
99  
100   /**
101    * Creates an RequestContext.  RequestContext is abstract
102    * and may not be instantiated directly.
103    * @see RequestContextFactory
104    */
105   protected RequestContext()
106   {
107   }
108 
109   //
110   // State related APIs
111   //
112 
113   /**
114    * Returns a Map of objects at "pageFlow" scope.
115    */
116   public abstract Map<String, Object> getPageFlowScope();
117 
118   /**
119    * @deprecated use getPageFlowScope()
120    */
121   @Deprecated
122   final public Map<String, Object> getProcessScope()
123   {
124     return getPageFlowScope();
125   }
126 
127   /**
128    * Method to obtain a Map stored on the view.
129    * <p>This calls {@link #getViewMap(boolean)} with a true value for create.</p>
130    * <p>This is a pre-cursor implementation to the JSF 2.0 UIViewRoot.getViewMap() function.
131    * The implementation is taken from the initial UIViewRoot implementation in JSF but without
132    * the event notification support.</p>
133    */
134   public abstract Map<String, Object> getViewMap();
135 
136   /**
137    * Method to obtain a Map stored on the view.
138    * <p>This is a pre-cursor implementation to the JSF 2.0 UIViewRoot.getViewMap() function.
139    * The implementation is taken from the initial UIViewRoot implementation in JSF but without
140    * the event notification support.</p>
141    *
142    * @param create if the map should be created if it already does not exist.
143    */
144   public abstract Map<String, Object> getViewMap(boolean create);
145 
146   /**
147    * Returns a Map of objects associated with the current window if any.  If there is no
148    * current window, the Session Map is returned.
149    * @return Map for storing objects associated with the current window.
150    * @see org.apache.myfaces.trinidad.context.Window#getWindowMap
151    */
152   public Map<String, Object> getWindowMap()
153   {
154     WindowManager wm = getWindowManager();
155 
156     ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext();
157 
158     Window window = wm.getCurrentWindow(extContext);
159 
160     if (window != null)
161     {
162 
163       return window.getWindowMap();
164     }
165     else
166     {
167       return extContext.getSessionMap();
168     }
169   }
170 
171   //
172   // Dialog APIs
173   //
174 
175   /**
176    * Returns from a dialog raised by a
177    * {@link org.apache.myfaces.trinidad.component.UIXCommand UIXCommand} component,
178    * or any component implementing
179    * {@link org.apache.myfaces.trinidad.component.DialogSource DialogSource},
180    * or any direct calls to {@link #launchDialog launchDialog()}.
181    * <p>
182    * @see org.apache.myfaces.trinidad.event.ReturnEvent
183    * @param returnValue the value to be delivered in the the ReturnEvent
184    */
185   // TODO Do we need an explicit "cancelled" concept, or
186   // is a null returnValue good enough?
187   public abstract void returnFromDialog(
188     Object returnValue,
189     Map<Object, Object> returnParameters);
190 
191 
192   /**
193    * Returns an DialogService, which exposes a number
194    * of APIs needed by component and framework developers.  This
195    * will only rarely be needed by page authors.
196    */
197   public abstract DialogService getDialogService();
198 
199   /**
200    * Launch a dialog, optionally raising it in a new dialog window.
201    * <p>
202    * The dialog will receive a new <code>pageFlowScope</code> map,
203    * which includes all the values of the currently available pageFlowScope
204    * as well as a set of properties passed to this function in
205    * the <code>dialogParameters</code> map.  Changes to this newly
206    * created scope will not be visible once the dialog returns.
207    * <p>
208    * @param dialogRoot the UIViewRoot for the page being launched
209    * @param dialogParameters a set of parameters to populate the
210    *   newly created pageFlowScope
211    * @param source the UIComponent that launched the dialog and
212    *   should receive the {@link org.apache.myfaces.trinidad.event.ReturnEvent}
213    *   when the dialog is complete.
214    * @param useWindow if true, use a popup window for the dialog
215    *    if available on the current user agent device
216    * @param windowProperties the set of UI parameters used to
217    *   modify the window, if one is used.  The set of properties that\
218    *   are supported will depend on the <code>RenderKit</code>, but
219    *   common examples include "width", "height", "top" and "left".
220    */
221   public abstract void launchDialog(
222     UIViewRoot  dialogRoot,
223     Map<String, Object> dialogParameters,
224     UIComponent source,
225     boolean     useWindow,
226     Map<String, Object> windowProperties);
227 
228   //
229   // General Apache Trinidad
230   //
231 
232   /**
233    * Returns true if JSF is currently processing a postback request.
234    * <code>isPostback()</code> will return false if this is a request
235    * for an initial render of a page (that is, if Apply Request Values
236    * never executes), or if during the request the user is navigated
237    * to a different page (because of a navigation rule, etc).  For
238    * example, during a request that results in a navigation to a new
239    * page, <code>isPostback()</code> will return true from Apply
240    * Request Values to Invoke Application, then false afterwards;
241    * whereas if there was no navigation, it would return true
242    * <p>
243    * The value of this method is undefined during (or before)
244    * the Restore View phase, but can be used in the afterPhase()
245    * method of a PhaseListener for Restore View.
246    * </p>
247    */
248   public abstract boolean isPostback();
249 
250   /**
251    * Method to indicate if this current HTTP request is a
252    * partial page rendering request.
253    *
254    * @param context the <code>FacesContext</code> object for
255    * the request we are processing
256    * @return is this request a PPR request?
257    */
258   public abstract boolean isPartialRequest(FacesContext context);
259 
260   /**
261    * Returns true if output should contain debugging information.
262    */
263   public abstract boolean isDebugOutput();
264 
265   /**
266    * Returns true if client-side validation should be disabled.
267    */
268   public abstract boolean isClientValidationDisabled();
269 
270   /**
271    * Returns the "output mode" - printable, etc.
272    */
273   public abstract String getOutputMode();
274 
275   /**
276    * Returns the OutputMode enumeration
277    * @return OutputMode
278    */
279   public OutputMode getOutputModeEnum()
280   {
281     return OutputMode.fromId(getOutputMode());
282   }
283 
284   /**
285    * Returns the name of the preferred skin family.
286    */
287   public abstract String getSkinFamily();
288 
289   /**
290    * Returns the name of the skin version that goes with the skin-family.
291    */
292   public String getSkinVersion()
293   {
294     return null;
295   }
296 
297   /**
298    * Determines whether the current View Root is an internal view
299    * @param context Faces context
300    * @return true if the current View Root is an internal view, false otherwise
301    */
302   public abstract boolean isInternalViewRequest(FacesContext context);
303 
304   /**
305    * Enumeration representing OutputModes
306    */
307   public enum OutputMode
308   {
309     DEFAULT("default"), PORTLET("portlet"), PRINTABLE("printable"), EMAIL("email"),
310     ATTACHMENT("attachment"), WEB_CRAWLER("webcrawler");
311 
312     private OutputMode(String id)
313     {
314       if (id == null) throw new NullPointerException();
315 
316       _id = id;
317     }
318 
319     /**
320      * @return the id of this OutputMode.
321      */
322     public String id()
323     {
324       return _id;
325     }
326 
327     @Override
328     public String toString()
329     {
330       return _id;
331     }
332 
333     /**
334      * Returns the OutputMode isntance of <code>null</code> if no id matches.
335      * @param id of OutputMode to return
336      * @return The OutputMode with the specified id
337      * @throws NullPointerException if <code>id</code> is null.
338      * @throws IllegalArgumentException if there is no enum with the specified name.
339      */
340     public static OutputMode fromId(String id)
341     {
342       if (id == null)
343         throw new NullPointerException();
344 
345       OutputMode outputMode = ID_TO_OUTPUT_MODE.get(id);
346 
347       if (outputMode == null)
348         throw new IllegalArgumentException();
349 
350       return outputMode;
351     }
352 
353     private static final Map<String, OutputMode> ID_TO_OUTPUT_MODE = new HashMap<String, OutputMode>();
354 
355     static
356     {
357       OutputMode[] instances = OutputMode.class.getEnumConstants();
358 
359       for (int i = 0; i < instances.length; i++)
360       {
361         ID_TO_OUTPUT_MODE.put(instances[i].toString(), instances[i]);
362       }
363     }
364 
365     private final String _id;
366   }
367 
368   public enum Accessibility
369   {
370     /**
371      * Output supports accessibility features
372      */
373     DEFAULT("default"),
374 
375     /**
376      * Accessibility-specific constructs are stripped out to optimize output size
377      */
378     INACCESSIBLE("inaccessible"),
379 
380     /**
381      * Accessibility-specific constructs are added to improve behavior under a screen reader
382      * (but may affect other users negatively)
383      */
384     SCREEN_READER("screenReader");
385 
386     /**
387      * Creates an Accessibility constant.
388      * @param displayName a user-friendly display name for the constant.
389      */
390     Accessibility(String displayName)
391     {
392       _displayName = displayName;
393     }
394 
395     @Override
396     public String toString()
397     {
398       return displayName();
399     }
400 
401     /**
402      * Returns the display name for this enum constant.
403      */
404     public String displayName()
405     {
406       return _displayName;
407     }
408 
409     /**
410      * Performs a reverse lookup of an Accessibilty constant based on
411      * its display name.
412      *
413      * @param displayName the display name of the Accessibility constant to return.
414      * @return the non-null Accessibility constant associated with the display name.
415      * @throws IllegalArgumentException if displayName does not correspond
416      *   to some Accessibility constant.
417      * @throws NullPointerException if displayName is null.
418      */
419     public static Accessibility valueOfDisplayName(String displayName)
420     {
421       if (displayName == null)
422       {
423         throw new NullPointerException();
424       }
425 
426       Accessibility accessibility = _displayNameMap.get(displayName);
427 
428       if (accessibility == null)
429       {
430         String message = _LOG.getMessage("ILLEGAL_ENUM_VALUE",
431                            new Object[] { Accessibility.class.getName(), displayName });
432         throw new IllegalArgumentException(message);
433       }
434 
435       return accessibility;
436     }
437 
438     private final String _displayName;
439 
440     private static final Map<String, Accessibility> _displayNameMap;
441 
442     static
443     {
444       Map<String, Accessibility> displayNameMap = new ArrayMap<String, Accessibility>(3);
445       for (Accessibility accessibility : Accessibility.values())
446       {
447         displayNameMap.put(accessibility.displayName(), accessibility);
448       }
449 
450       _displayNameMap = Collections.unmodifiableMap(displayNameMap);
451     }
452   };
453 
454   public enum ClientValidation
455   {
456     ALERT("alert"),
457     INLINE("inline"),
458     DISABLED("disabled");
459 
460     ClientValidation(String name)
461     {
462       _name = name;
463     }
464 
465     @Override
466     public String toString()
467     {
468       return _name;
469     }
470 
471     private final String _name;
472   };
473 
474   /**
475    * Returns the name of the current accessibility mode.
476    */
477   public abstract Accessibility getAccessibilityMode();
478 
479   /**
480    * Returns the accessibility profile for the current request.
481    */
482   public abstract AccessibilityProfile getAccessibilityProfile();
483 
484   /**
485    * Returns the name of the current client validation mode.
486    */
487   public abstract ClientValidation getClientValidation();
488 
489   /**
490    * Returns the system wide setting to turn animation on/off.
491    */
492   public abstract boolean isAnimationEnabled();
493 
494   //
495   //  General localization
496   //
497 
498   /**
499    * Returns true if the user should be shown output in right-to-left.
500    */
501   public abstract boolean isRightToLeft();
502 
503   /**
504    * Returns the formatting locale.  Converters without an explicit locale
505    * should use this to format values.  If not set, converters should
506    * default to the value of FacesContext.getViewRoot().getLocale().
507    * This will, by default, simply return null.
508    */
509   public abstract Locale getFormattingLocale();
510 
511   //
512   //  Number formatting
513   //
514 
515   /**
516    * Return the separator used for groups of numbers.  If NUL (zero),
517    * use the default separator for the current language.
518    */
519   public abstract char getNumberGroupingSeparator();
520 
521   /**
522    * Return the separator used as the decimal point.  If NUL (zero),
523    * use the default separator for the current language.
524    */
525   public abstract char getDecimalSeparator();
526 
527   /**
528    * Return the ISO 4217 currency code used by default for formatting
529    * currency fields when those fields do not specify an explicit
530    * currency field via their converter.  If this returns null, the default
531    * code for the current locale will be used.
532    */
533   // TODO do we need to provide getCurrencySymbol() as well?
534   public abstract String getCurrencyCode();
535 
536   /**
537    * Notify Trinidad that tag execution will not be performed during this request. Functionality in
538    * Trinidad assumes that tags will be executed as part of the render response phase. If 3rd party
539    * libraries are used that cause the tags to not be executed, Trinidad must be notified to avoid
540    * errors.
541    */
542   public void tagExecutionSkipped()
543   {
544     _tagExecution = TagExecution.NONE;
545   }
546 
547   /**
548    * Checks if the tags will be executed during this request.
549    * @see #tagExecutionSkipped()
550    * @return an enumeration indicating the status of the tag execution
551    */
552   public TagExecution getTagExecutionStatus()
553   {
554     return _tagExecution;
555   }
556 
557   /**
558    * @see #isTagExecutionSkipped()
559    */
560   public enum TagExecution
561   {
562     /** Tag execution will be run normally during this request */
563     FULL,
564 
565     /** Tag execution will not be run during this request */
566     NONE
567   }
568 
569   //
570   // DateFormating API
571   //
572   /**
573    * Returns the year offset for parsing years with only two digits.
574    * If not set this is defaulted to <code>1950</code>
575    * This is used by @link{org.apache.myfaces.trinidad.faces.view.converter.DateTimeConverter}
576    * while converting strings to Date object.
577    */
578   public abstract int getTwoDigitYearStart();
579 
580   //
581   // Help APIs
582   //
583 
584   /**
585    * Return the URL to an Oracle Help for the Web servlet.
586    */
587   // TODO Add support for non-OHW help systems
588   public abstract String getOracleHelpServletUrl();
589 
590   /**
591    * Returns a Map that will accept topic names as keys, and return
592    * an URL as a result.
593    */
594   public abstract Map<String, Object> getHelpTopic();
595 
596   /**
597    * Returns a Map that will accept help system properties as keys, and return
598    * an URL as a result.
599    */
600   public abstract Map<String, Object> getHelpSystem();
601 
602   //
603   // Date formatting
604   //
605 
606   /**
607    * Returns the default TimeZone used for interpreting and formatting
608    * date values.
609    */
610   public abstract TimeZone getTimeZone();
611 
612   /**
613    * Gets the ChangeManager for the current application.
614    */
615   public abstract ChangeManager getChangeManager();
616 
617   /**
618    * Gets a per application concurrent map. There is no synchronization
619    * with ServletContext attributes.
620    */
621    public ConcurrentMap<String, Object> getApplicationScopedConcurrentMap()
622    {
623      ClassLoader cl = _getClassLoader();
624 
625      ConcurrentMap<String, Object> classMap = _APPLICATION_MAPS.get(cl);
626 
627      if (classMap == null)
628      {
629        ConcurrentMap<String, Object> newClassMap = new ConcurrentHashMap<String, Object>();
630        ConcurrentMap<String, Object> oldClassMap = _APPLICATION_MAPS.putIfAbsent(cl, newClassMap);
631 
632        classMap = ((oldClassMap != null)? oldClassMap : newClassMap);
633 
634        assert(classMap != null);
635      }
636 
637      return classMap;
638    }
639 
640   /**
641    * Gets the PageFlowScopeProvider for the current application.
642    */
643   public abstract PageFlowScopeProvider getPageFlowScopeProvider();
644 
645   /**
646    * Gets the PageResolver for the current application.
647    */
648   public abstract PageResolver getPageResolver();
649 
650   /**
651    * Gets the RegionManager for the current application.
652    */
653   public abstract RegionManager getRegionManager();
654 
655   /**
656    * Gets the RoundingMode used by NumberConverter instances for the current application.
657    */
658   public  RoundingMode getRoundingMode()
659   {
660     return null;
661   }
662 
663   //
664   // Partial Page Rendering support
665   //
666   /**
667    * Add a component as a partial target. In response to a partial event, only
668    * components registered as partial targets are re-rendered.  For
669    * a component to be successfully re-rendered when it is manually
670    * added with this API, it should have an explictly set "id".  If
671    * not, partial re-rendering may or may not work depending on the
672    * component.
673    */
674   public abstract void addPartialTarget(UIComponent newTarget);
675 
676   /**
677    * Add components relative to the given component as partial targets.
678    * <p>
679    * See {@link #addPartialTarget(UIComponent)} for more information.
680    * </p>
681    * @param from the component to use as a relative reference for any
682    * relative IDs in the list of targets
683    * @param targets array of targets relative to the from component that
684    * should be added as targets.
685    * @see ComponentUtils#findRelativeComponent(UIComponent, String)
686    */
687   public abstract void addPartialTargets(UIComponent from, String... targets);
688 
689   /**
690    * Returns the set of partial targets related to a given UIComponent.
691    */
692   public abstract Set<UIComponent> getPartialTargets(UIComponent newTarget);
693 
694   /**
695    * Adds a listener on a set of particular triggering components. If one of
696    * the named components gets updated in response to a partial event, then
697    * this listener component will be rerendered during the render phase (i.e.
698    * it will be added as a partialTarget). The list should consist of names
699    * suitable for use with the findComponent method on UIComponent.
700    */
701   public abstract void addPartialTriggerListeners(UIComponent listener,
702                                                   String[] trigger);
703 
704   /**
705    * Called when any component gets updated. Any partial target components
706    * listening on this component will be added to the partialTargets list in
707    * the render phase.
708    */
709   public abstract void partialUpdateNotify(UIComponent updated);
710 
711   /**
712    * Starts a new component binding context. Typically called from tag handlers when component
713    * bindings in its subtree needs to be cleared, forcing the creation of new components.
714    *
715    * @param context FacesContext instance
716    * @see RequestContext#popComponentBindingContext
717    * @see RequestContext#isInComponentBindingContext
718    */
719   public static void pushComponentBindingContext(FacesContext context)
720   {
721     ExternalContext ec = context.getExternalContext();
722     if (null != ec)
723     {
724       // Use a counter on the request map to generate the IDs.
725       Map<String, Object> reqMap = ec.getRequestMap();
726       Integer value = (Integer)reqMap.get(_CURRENT_COMPONENT_BINDING_CONTEXT_KEY);
727       int val = 0;
728       if (value == null)
729       {
730         val = 1;
731       }
732       else
733       {
734         val = value + 1;
735       }
736 
737       reqMap.put(_CURRENT_COMPONENT_BINDING_CONTEXT_KEY, val);
738     }
739   }
740 
741   /**
742    * Pops out of the last pushed component binding context. Component binding instances will not be
743    * cleared after popping out the outermost context.
744    *
745    * @param context FacesContext instance
746    * @see RequestContext#pushComponentBindingContext
747    * @see RequestContext#isInComponentBindingContext
748    */
749   public static void popComponentBindingContext(FacesContext context)
750   {
751     ExternalContext ec = context.getExternalContext();
752     if (null != ec)
753     {
754       Map<String, Object> reqMap = ec.getRequestMap();
755       Integer value = (Integer)reqMap.get(_CURRENT_COMPONENT_BINDING_CONTEXT_KEY);
756       int val = 0;
757       if (value == null)
758       {
759         _LOG.warning("POP_COMPONENT_BINDING_CONTEXT_FAILED");
760       }
761       else
762       {
763         val = value - 1;
764       }
765 
766       if (val > 0)
767         reqMap.put(_CURRENT_COMPONENT_BINDING_CONTEXT_KEY, val);
768       else
769         reqMap.put(_CURRENT_COMPONENT_BINDING_CONTEXT_KEY, null);
770     }
771   }
772 
773   /**
774    * Returns true if we are currently within a component binding context.
775    *
776    * @see RequestContext#pushComponentBindingContext
777    * @see RequestContext#popComponentBindingContext
778    */
779   public static boolean isInComponentBindingContext(FacesContext context)
780   {
781     ExternalContext ec = context.getExternalContext();
782     if (null != ec)
783     {
784       Map<String, Object> reqMap = ec.getRequestMap();
785       Integer value = (Integer)reqMap.get(_CURRENT_COMPONENT_BINDING_CONTEXT_KEY);
786 
787       if (value != null && value > 0)
788         return true;
789     }
790 
791     return false;
792   }
793 
794   //
795   // Miscellaneous functionality
796   //
797 
798   /**
799    * <p>Creates a VisitContext instance for use with
800    * {@link UIComponent#visitTree}.</p>
801    *
802    * @param context the FacesContext for the current request
803    * @param ids the client ids of the components to visit.  If null,
804    *   all components will be visited.
805    * @param hints the VisitHints to apply to the visit
806    * @param phaseId.  ignored.
807    * @return a VisitContext instance that is initialized with the
808    *   specified ids and hints.
809    * @deprecated use {@link VisitContext#createVisitContext(FacesContext, Collection<String>, Set<VisitHint>)} instead
810    */
811   public final VisitContext createVisitContext(
812     FacesContext context,
813     Collection<String> ids,
814     Set<VisitHint> hints,
815     PhaseId phaseId)
816   {
817     return VisitContext.createVisitContext(context, ids, hints);
818   }
819 
820   public abstract UploadedFileProcessor getUploadedFileProcessor();
821 
822   public abstract Long getUploadedFileMaxMemory();
823 
824   public abstract Long getUploadedFileMaxDiskSpace();
825 
826   public Long getUploadedFileMaxFileSize()
827   {
828     // default of unlimited file size
829     return -1L;
830   }
831 
832   public Long getUploadedFileMaxChunkSize()
833   {
834     // default of 2GB which is the maximum allowed chunk size
835     return 2000000000L;
836   }
837 
838   public abstract String getUploadedFileTempDir();
839 
840   /**
841    * Returns a Map that takes color palette names as keys, and returns
842    * the color palette as a result.
843    */
844   public abstract Map<String, List<Color>> getColorPalette();
845 
846   /**
847    * Returns a Map that performs message formatting with a recursive Map
848    * structure.  The first key must be the message formatting mask, and the
849    * second the first parameter into the message. (The formatter Map supports
850    * only a single parameter at this time.)
851    */
852   public abstract Map<Object, Map<Object,String>> getFormatter();
853 
854   /**
855    * Returns the Agent information for the current context
856    */
857   public abstract Agent getAgent();
858 
859   /**
860    * Saves the state of a UIComponent tree into an Object.  The
861    * Object will be serializable, unless a UIComponent
862    * in this tree contains a non-serializable property.  This
863    * method does not check that condition.
864    * @param component the component
865    * @return an Object that can be passed to restoreComponent()
866    *  to reinstantiate the state
867    */
868   public abstract Object saveComponent(UIComponent component);
869 
870   /**
871    * Restores the state of a component.
872    * @param state an Object created by a prior call to saveComponent().
873    * @return the component
874    */
875   public abstract UIComponent restoreComponent(Object state)
876                             throws ClassNotFoundException,
877                                    InstantiationException,
878                                    IllegalAccessException;
879 
880   /**
881    * <p>
882    * Returns the WindowManager for this request.  A non-null WindowManager
883    * will always be returned.
884    * </p><p>
885    * The default implementation uses the first WindowManagerFactory specified
886    * implementation class in a file named
887    * <code>org.apache.myfaces.trinidad.context.WindowManagerFactory</code>
888    * in the <code>META-INF/services</code> directory and uses the WindowManagerFactory
889    * to create the WindowManager for this Session.  If no WindowManagerFactory is
890    * found, a default WindowManager that never returns any Windows is used.
891    * </p>
892    * @return the WindowManager used for this Session.
893    */
894   public WindowManager getWindowManager()
895   {
896     // implement getWindowManager() in RequestContext for backwards compatibility
897 
898     // check if we have cached it for the request
899     WindowManager windowManager = _windowManager;
900 
901     // get instance using the WindowManagerFactory
902     if (windowManager == null)
903     {
904       FacesContext context = FacesContext.getCurrentInstance();
905 
906       // just in case we're called before the real JSF lifecycle starts
907       if (context != null)
908       {
909         // check if we have cached it per session
910         ExternalContext extContext = context.getExternalContext();
911 
912         // create a new instance using the WindowManagerFactory
913         ConcurrentMap<String, Object> concurrentAppMap = getApplicationScopedConcurrentMap();
914 
915         WindowManagerFactory windowManagerFactory = (WindowManagerFactory)concurrentAppMap.get(
916                                                               _WINDOW_MANAGER_FACTORY_CLASS_NAME);
917 
918         if (windowManagerFactory == null)
919         {
920           // we haven't registered a WindowManagerFactory yet, so use the services api to see
921           // if a factory has been registered
922           List<WindowManagerFactory> windowManagerFactories =
923                                   ClassLoaderUtils.getServices(_WINDOW_MANAGER_FACTORY_CLASS_NAME);
924 
925           if (windowManagerFactories.isEmpty())
926           {
927             // no factory registered so use the factory that returns dummy stub WindowManagers
928             windowManagerFactory = _STUB_WINDOW_MANAGER_FACTORY;
929           }
930           else
931           {
932             // only one WindowManager is allowed, use it
933             windowManagerFactory = windowManagerFactories.get(0);
934           }
935 
936           // save the WindowManagerFactory to the application if it hasn't already been saved
937           // if it has been saved, use the previously registered WindowManagerFactory
938           WindowManagerFactory oldWindowManagerFactory = (WindowManagerFactory)
939                               concurrentAppMap.putIfAbsent(_WINDOW_MANAGER_FACTORY_CLASS_NAME,
940                                                            windowManagerFactory);
941 
942           if (oldWindowManagerFactory != null)
943             windowManagerFactory = oldWindowManagerFactory;
944         } // create WindowManagerFactory
945 
946         // get the WindowManager from the factory.  The factory will create a new instance
947         // for this session if necessary
948         windowManager = windowManagerFactory.getWindowManager(extContext);
949 
950         // remember for the next call on this thread
951         _windowManager = windowManager;
952       }
953     }
954 
955     return windowManager;
956   }
957 
958   /**
959    * Get the component context manager.
960    * @return The manager of component context changes to be used to suspend and resume
961    * component specific context changes.
962    */
963    public ComponentContextManager getComponentContextManager()
964    {
965      if (_componentContextManager == null)
966      {
967        _componentContextManager = new ComponentContextManagerImpl();
968      }
969 
970      return _componentContextManager;
971   }
972 
973   /**
974    * Push the component onto the stack so we know the current component being processed.
975    * @param context the FacesContext for the current request
976    * @param component an UIComponent object to be pushed as current component.
977    * @exception NullPointerException if <code>component</code> is null.
978    * @see popCurrentComponent(FacesContext, UIComponent) and getCurrentComponent()
979    */
980   public void pushCurrentComponent(FacesContext context, UIComponent component)
981   {
982     return;
983   }
984 
985   /**
986    * Pop the component out from the stack.
987    * @param context the FacesContext for the current request
988    * @param component an UIComponent object to be poped.
989    * @exception IllegalStateException if <code>component</code> is not the same
990    * as the current top component in the component stack.
991    * @see pushCurrentComponent(FacesContext, UIComponent) and getCurrentComponent()   */
992   public void popCurrentComponent(FacesContext context, UIComponent component)
993   {
994     return;
995   }
996 
997   /**
998    * Returns the current component being processed.
999    * @see pushCurrentComponent(FacesContext, UIComponent) and popCurrentComponent(FacesContext, UIComponent)
1000    */
1001   public UIComponent getCurrentComponent()
1002   {
1003     return null;
1004   }
1005 
1006   /**
1007    * Releases the RequestContext object.  This method must only
1008    * be called by the code that created the RequestContext.
1009    * @exception IllegalStateException if no RequestContext is attached
1010    * to the thread, or the attached context is not this object
1011    */
1012   public void release()
1013   {
1014     if (_LOG.isFinest())
1015     {
1016       _LOG.finest("RequestContext released.",
1017                   new RuntimeException("This is not an error. This trace is for debugging."));
1018     }
1019 
1020     Object o = _CURRENT_CONTEXT.get();
1021     if (o == null)
1022       throw new IllegalStateException(
1023               _addHelp("RequestContext was already released or " +
1024                        "had never been attached."));
1025     if (o != this)
1026       throw new IllegalStateException(_LOG.getMessage(
1027         "RELEASE_DIFFERENT_REQUESTCONTEXT_THAN_CURRENT_ONE"));
1028 
1029     _CURRENT_CONTEXT.remove();
1030   }
1031 
1032   /**
1033    * Release any state maintained at the application level. Called when the servlet context is
1034    * being destroyed.
1035    */
1036   public static void releaseApplicationState()
1037   {
1038     _APPLICATION_MAPS.remove(_getClassLoader());
1039   }
1040 
1041   /**
1042    * Attaches a RequestContext to the current thread.  This method
1043    * should only be called by a RequestContext object itself.
1044    * @exception IllegalStateException if an RequestContext is already
1045    * attached to the thread
1046    */
1047   public void attach()
1048   {
1049     if (_LOG.isFinest())
1050     {
1051       _LOG.finest("RequestContext attached.",
1052                   new RuntimeException(_LOG.getMessage(
1053                     "DEBUGGING_TRACE_NOT_ERROR")));
1054     }
1055 
1056     Object o = _CURRENT_CONTEXT.get();
1057     if (o != null)
1058     {
1059       throw new IllegalStateException(
1060               _addHelp("Trying to attach RequestContext to a " +
1061                        "thread that already had one."));
1062     }
1063     _CURRENT_CONTEXT.set(this);
1064   }
1065 
1066   private static String _addHelp(String error)
1067   {
1068     if (!_LOG.isFinest())
1069     {
1070       error += " To enable stack traces of each RequestContext attach/release call," +
1071         " enable Level.FINEST logging for the "+RequestContext.class;
1072     }
1073     return error;
1074   }
1075 
1076   //
1077   // Pick a ClassLoader
1078   //
1079   private static ClassLoader _getClassLoader()
1080   {
1081     return Thread.currentThread().getContextClassLoader();
1082   }
1083 
1084   /**
1085    * Default WindowManagerFactory implementation that returns the StubWindowManager
1086    */
1087   private static final class StubWindowManagerFactory extends WindowManagerFactory
1088   {
1089     public WindowManager getWindowManager(ExternalContext extContext)
1090     {
1091       return _STUB_WINDOW_MANAGER;
1092     }
1093 
1094     private static final WindowManager _STUB_WINDOW_MANAGER = new StubWindowManager();
1095   }
1096 
1097   /**
1098    * Default WindowManager implementation that returns no Windows
1099    */
1100   private static final class StubWindowManager extends WindowManager
1101   {
1102     @Override
1103     public Window getCurrentWindow(ExternalContext extContext)
1104     {
1105       return null;
1106     }
1107 
1108     @Override
1109     public Map<String, Window> getWindows(ExternalContext extContext)
1110     {
1111       return Collections.emptyMap();
1112     }
1113 
1114     @Override
1115     public void addWindowLifecycleListener(
1116       ExternalContext extContext,
1117       WindowLifecycleListener windowListener)
1118     {
1119       // do nothing
1120     }
1121 
1122     @Override
1123     public void removeWindowLifecycleListener(
1124       ExternalContext extContext,
1125       WindowLifecycleListener windowListener)
1126     {
1127       // do nothing
1128     }
1129 
1130     @Override
1131     public void writeState(FacesContext context) throws IOException
1132     {
1133       // do nothing
1134     }
1135   }
1136 
1137   /* singleton for WindowManagerFactory that returns WindowManagers that don't do anything */
1138   private static final WindowManagerFactory _STUB_WINDOW_MANAGER_FACTORY =
1139                                                                     new StubWindowManagerFactory();
1140 
1141   private static final String _WINDOW_MANAGER_FACTORY_CLASS_NAME =
1142                                                               WindowManagerFactory.class.getName();
1143 
1144   @SuppressWarnings({"CollectionWithoutInitialCapacity"})
1145   private static final ConcurrentMap<ClassLoader, ConcurrentMap<String, Object>> _APPLICATION_MAPS =
1146        new ConcurrentHashMap<ClassLoader, ConcurrentMap<String, Object>>();
1147   static private final ThreadLocal<RequestContext> _CURRENT_CONTEXT =
1148     new ThreadLocal<RequestContext>();
1149   static private final String _CURRENT_COMPONENT_BINDING_CONTEXT_KEY =
1150     RequestContext.class.getName() + ".CCBCK";
1151   static private final TrinidadLogger _LOG =
1152     TrinidadLogger.createTrinidadLogger(RequestContext.class);
1153 
1154   private ComponentContextManager _componentContextManager;
1155   private TagExecution _tagExecution = TagExecution.FULL;
1156 
1157   // window manager for this request
1158   private WindowManager _windowManager;
1159 }