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.view.facelets;
20  
21  import java.beans.BeanDescriptor;
22  import java.beans.BeanInfo;
23  import java.beans.PropertyDescriptor;
24  import java.io.FileNotFoundException;
25  import java.io.IOException;
26  import java.io.Writer;
27  import java.util.ArrayList;
28  import java.util.Collections;
29  import java.util.EnumSet;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Set;
35  import java.util.logging.Level;
36  import java.util.logging.Logger;
37  
38  import javax.el.ELContext;
39  import javax.el.ELException;
40  import javax.el.MethodExpression;
41  import javax.el.ValueExpression;
42  import javax.el.VariableMapper;
43  import javax.faces.FacesException;
44  import javax.faces.FacesWrapper;
45  import javax.faces.FactoryFinder;
46  import javax.faces.application.Application;
47  import javax.faces.application.ProjectStage;
48  import javax.faces.application.Resource;
49  import javax.faces.application.StateManager;
50  import javax.faces.application.ViewHandler;
51  import javax.faces.component.ActionSource2;
52  import javax.faces.component.EditableValueHolder;
53  import javax.faces.component.UIComponent;
54  import javax.faces.component.UINamingContainer;
55  import javax.faces.component.UIPanel;
56  import javax.faces.component.UIViewRoot;
57  import javax.faces.component.visit.VisitContext;
58  import javax.faces.component.visit.VisitHint;
59  import javax.faces.context.ExternalContext;
60  import javax.faces.context.FacesContext;
61  import javax.faces.context.ResponseWriter;
62  import javax.faces.event.ActionEvent;
63  import javax.faces.event.ActionListener;
64  import javax.faces.event.MethodExpressionActionListener;
65  import javax.faces.event.MethodExpressionValueChangeListener;
66  import javax.faces.event.PhaseId;
67  import javax.faces.event.PostAddToViewEvent;
68  import javax.faces.event.PostRestoreStateEvent;
69  import javax.faces.event.ValueChangeEvent;
70  import javax.faces.event.ValueChangeListener;
71  import javax.faces.render.RenderKit;
72  import javax.faces.render.RenderKitFactory;
73  import javax.faces.render.ResponseStateManager;
74  import javax.faces.validator.MethodExpressionValidator;
75  import javax.faces.validator.Validator;
76  import javax.faces.view.ActionSource2AttachedObjectHandler;
77  import javax.faces.view.ActionSource2AttachedObjectTarget;
78  import javax.faces.view.AttachedObjectHandler;
79  import javax.faces.view.AttachedObjectTarget;
80  import javax.faces.view.BehaviorHolderAttachedObjectHandler;
81  import javax.faces.view.BehaviorHolderAttachedObjectTarget;
82  import javax.faces.view.EditableValueHolderAttachedObjectHandler;
83  import javax.faces.view.EditableValueHolderAttachedObjectTarget;
84  import javax.faces.view.StateManagementStrategy;
85  import javax.faces.view.ValueHolderAttachedObjectHandler;
86  import javax.faces.view.ValueHolderAttachedObjectTarget;
87  import javax.faces.view.ViewDeclarationLanguage;
88  import javax.faces.view.ViewMetadata;
89  import javax.faces.view.facelets.Facelet;
90  import javax.faces.view.facelets.FaceletContext;
91  import javax.faces.view.facelets.ResourceResolver;
92  import javax.servlet.http.HttpServletResponse;
93  import org.apache.myfaces.application.StateManagerImpl;
94  
95  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
96  import org.apache.myfaces.config.RuntimeConfig;
97  import org.apache.myfaces.shared.application.DefaultViewHandlerSupport;
98  import org.apache.myfaces.shared.application.ViewHandlerSupport;
99  import org.apache.myfaces.shared.config.MyfacesConfig;
100 import org.apache.myfaces.shared.util.ClassUtils;
101 import org.apache.myfaces.shared.util.StringUtils;
102 import org.apache.myfaces.shared.util.WebConfigParamUtils;
103 import org.apache.myfaces.view.ViewDeclarationLanguageStrategy;
104 import org.apache.myfaces.view.ViewMetadataBase;
105 import org.apache.myfaces.view.facelets.compiler.Compiler;
106 import org.apache.myfaces.view.facelets.compiler.SAXCompiler;
107 import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
108 import org.apache.myfaces.view.facelets.el.LocationMethodExpression;
109 import org.apache.myfaces.view.facelets.el.LocationValueExpression;
110 import org.apache.myfaces.view.facelets.el.MethodExpressionMethodExpression;
111 import org.apache.myfaces.view.facelets.el.RedirectMethodExpressionValueExpressionActionListener;
112 import org.apache.myfaces.view.facelets.el.RedirectMethodExpressionValueExpressionValidator;
113 import org.apache.myfaces.view.facelets.el.RedirectMethodExpressionValueExpressionValueChangeListener;
114 import org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression;
115 import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
116 import org.apache.myfaces.view.facelets.impl.DefaultFaceletFactory;
117 import org.apache.myfaces.view.facelets.impl.DefaultResourceResolver;
118 import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorAttachedObjectTarget;
119 import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper;
120 import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectEventComponentWrapper;
121 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
122 import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
123 import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
124 
125 import static org.apache.myfaces.view.facelets.DefaultFaceletsStateManagementStrategy.*;
126 import org.apache.myfaces.view.facelets.compiler.FaceletsCompilerSupport;
127 import org.apache.myfaces.view.facelets.compiler.RefreshDynamicComponentListener;
128 import org.apache.myfaces.view.facelets.impl.SectionUniqueIdCounter;
129 import org.apache.myfaces.view.facelets.pool.RestoreViewFromPoolResult;
130 import org.apache.myfaces.view.facelets.pool.ViewEntry;
131 import org.apache.myfaces.view.facelets.pool.ViewPool;
132 import org.apache.myfaces.view.facelets.pool.ViewStructureMetadata;
133 import org.apache.myfaces.view.facelets.tag.composite.CreateDynamicCompositeComponentListener;
134 import org.apache.myfaces.view.facelets.tag.jsf.PartialMethodExpressionActionListener;
135 import org.apache.myfaces.view.facelets.tag.jsf.PartialMethodExpressionValidator;
136 import org.apache.myfaces.view.facelets.tag.jsf.PartialMethodExpressionValueChangeListener;
137 import org.apache.myfaces.view.facelets.util.FaceletsViewDeclarationLanguageUtils;
138 
139 /**
140  * This class represents the abstraction of Facelets as a ViewDeclarationLanguage.
141  *
142  * @author Simon Lessard (latest modification by $Author$)
143  * @version $Revision$ $Date$
144  *
145  * @since 2.0
146  */
147 public class FaceletViewDeclarationLanguage extends FaceletViewDeclarationLanguageBase
148 {
149     //private static final Log log = LogFactory.getLog(FaceletViewDeclarationLanguage.class);
150     private static final Logger log = Logger.getLogger(FaceletViewDeclarationLanguage.class.getName());
151 
152     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
153 
154     private static final Class<?>[] VALUE_CHANGE_LISTENER_SIGNATURE = new Class[]{ValueChangeEvent.class};
155 
156     private static final Class<?>[] ACTION_LISTENER_SIGNATURE = new Class[]{ActionEvent.class};
157 
158     private static final Class<?>[] VALIDATOR_SIGNATURE
159             = new Class[]{FacesContext.class, UIComponent.class, Object.class};
160 
161     public static final String CHARACTER_ENCODING_KEY = "javax.faces.request.charset";
162 
163     public final static long DEFAULT_REFRESH_PERIOD = 0;
164     public final static long DEFAULT_REFRESH_PERIOD_PRODUCTION = -1;
165 
166     public final static String DEFAULT_CHARACTER_ENCODING = "UTF-8";
167 
168     /**
169      * Define the default buffer size value passed to ExternalContext.setResponseBufferResponse() and in a
170      * servlet environment to HttpServletResponse.setBufferSize().
171      */
172     @JSFWebConfigParam(since = "2.0", deprecated = true, classType = "java.lang.Integer")
173     private final static String PARAM_BUFFER_SIZE_DEPRECATED = "facelets.BUFFER_SIZE";
174 
175     private final static String[] PARAMS_BUFFER_SIZE = {ViewHandler.FACELETS_BUFFER_SIZE_PARAM_NAME,
176         PARAM_BUFFER_SIZE_DEPRECATED};
177 
178     //private final static String PARAM_BUILD_BEFORE_RESTORE = "facelets.BUILD_BEFORE_RESTORE";
179 
180     /**
181      * Constant used by EncodingHandler to indicate the current encoding of the page being built,
182      * and indicate which one is the response encoding on getResponseEncoding(FacesContext, String) method.
183      */
184     public final static String PARAM_ENCODING = "facelets.Encoding";
185 
186     /**
187      * Define the period used to refresh the facelet abstract syntax tree from the view definition file. 
188      *
189      * <p>By default is infinite (no active).</p>
190      */
191     @JSFWebConfigParam(since = "2.0", defaultValue = "-1", deprecated = true)
192     public final static String PARAM_REFRESH_PERIOD_DEPRECATED = "facelets.REFRESH_PERIOD";
193 
194     public final static String[] PARAMS_REFRESH_PERIOD = {ViewHandler.FACELETS_REFRESH_PERIOD_PARAM_NAME,
195         PARAM_REFRESH_PERIOD_DEPRECATED};
196 
197     /**
198      * Class implementing ResourceResolver interface used to locate facelet resources. 
199      */
200     @JSFWebConfigParam(since = "2.0", alias = "facelets.RESOURCE_RESOLVER")
201     public final static String PARAM_RESOURCE_RESOLVER = "javax.faces.FACELETS_RESOURCE_RESOLVER";
202 
203     /**
204      * Class implementing ResourceResolver interface used to locate facelet resources.
205      */
206     @JSFWebConfigParam(since = "2.0", deprecated = true)
207     private final static String PARAM_RESOURCE_RESOLVER_DEPRECATED = "facelets.RESOURCE_RESOLVER";
208 
209     private final static String[] PARAMS_RESOURCE_RESOLVER
210             = {PARAM_RESOURCE_RESOLVER, PARAM_RESOURCE_RESOLVER_DEPRECATED};
211 
212     @JSFWebConfigParam(since = "2.1", defaultValue = "false", expectedValues = "true, false", tags = "performance")
213     private final static String PARAM_MARK_INITIAL_STATE_WHEN_APPLY_BUILD_VIEW
214             = "org.apache.myfaces.MARK_INITIAL_STATE_WHEN_APPLY_BUILD_VIEW";
215 
216     public final static String FILLED_VIEW = "org.apache.myfaces.FILLED_VIEW";
217 
218     //BEGIN CONSTANTS SET ON BUILD VIEW
219 
220     public final static String BUILDING_VIEW_METADATA = "org.apache.myfaces.BUILDING_VIEW_METADATA";
221 
222     public final static String REFRESHING_TRANSIENT_BUILD = "org.apache.myfaces.REFRESHING_TRANSIENT_BUILD";
223 
224     public final static String REFRESH_TRANSIENT_BUILD_ON_PSS = "org.apache.myfaces.REFRESH_TRANSIENT_BUILD_ON_PSS";
225 
226     public final static String USING_PSS_ON_THIS_VIEW = "org.apache.myfaces.USING_PSS_ON_THIS_VIEW";
227 
228     public final static String REMOVING_COMPONENTS_BUILD = "org.apache.myfaces.REMOVING_COMPONENTS_BUILD";
229     //END CONSTANTS SET ON BUILD VIEW
230 
231     /**
232      * Marker to indicate tag handlers the view currently being built is using
233      * partial state saving and it is necessary to call UIComponent.markInitialState
234      * after component instances are populated. 
235      */
236     public final static String MARK_INITIAL_STATE_KEY = "org.apache.myfaces.MARK_INITIAL_STATE";
237     
238     public final static String IS_BUILDING_INITIAL_STATE_KEY_ALIAS
239             = "javax.faces.view.ViewDeclarationLanguage.IS_BUILDING_INITIAL_STATE";
240 
241     public final static String CLEAN_TRANSIENT_BUILD_ON_RESTORE
242             = "org.apache.myfaces.CLEAN_TRANSIENT_BUILD_ON_RESTORE";
243 
244     private final static String STATE_KEY = "<!--@@JSF_FORM_STATE_MARKER@@-->";
245 
246     private final static int STATE_KEY_LEN = STATE_KEY.length();
247     
248     private static final Set<VisitHint> VISIT_HINTS_DYN_REFRESH = Collections.unmodifiableSet( 
249             EnumSet.of(VisitHint.SKIP_ITERATION));
250     
251     /**
252      * Key used to cache component ids for the counter
253      */
254     public final static String CACHED_COMPONENT_IDS = "oam.CACHED_COMPONENT_IDS"; 
255     
256     private static final String ASTERISK = "*";
257 
258     private int _bufferSize;
259 
260     // This param evolve in jsf 2.0 to partial state saving
261     //private boolean _buildBeforeRestore = false;
262 
263     private ViewHandlerSupport _cachedViewHandlerSupport;
264 
265     private String _defaultSuffix;
266 
267     private FaceletFactory _faceletFactory;
268 
269     private StateManagementStrategy _stateMgmtStrategy;
270     
271     private RenderKitFactory _renderKitFactory = null;
272 
273     private boolean _partialStateSaving;
274 
275     private boolean _refreshTransientBuildOnPSS;
276 
277     private boolean _refreshTransientBuildOnPSSAuto;
278 
279     private Set<String> _viewIds;
280 
281     private boolean _markInitialStateWhenApplyBuildView;
282 
283     private final ViewDeclarationLanguageStrategy _strategy;
284 
285     private ResourceResolver _resourceResolver;
286     
287     private Map<String, List<String>> _contractMappings;
288     private List<String> _prefixWildcardKeys;
289     
290     private FaceletsCompilerSupport _faceletsCompilerSupport;
291     
292     private MyfacesConfig _config;
293     
294     private ViewPoolProcessor _viewPoolProcessor;
295 
296     /**
297      *
298      */
299     public FaceletViewDeclarationLanguage(FacesContext context)
300     {
301         _config = MyfacesConfig.getCurrentInstance(context.getExternalContext());
302         initialize(context);
303         _strategy = new FaceletViewDeclarationLanguageStrategy();
304     }
305 
306     public FaceletViewDeclarationLanguage(FacesContext context, ViewDeclarationLanguageStrategy strategy)
307     {
308         _config = MyfacesConfig.getCurrentInstance(context.getExternalContext());
309         initialize(context);
310         _strategy = strategy;
311     }
312 
313 
314     @Override
315     public String getId()
316     {
317         return ViewDeclarationLanguage.FACELETS_VIEW_DECLARATION_LANGUAGE_ID;
318     }
319 
320     @Override
321     public boolean viewExists(FacesContext facesContext, String viewId)
322     {
323         if (_strategy.handles(viewId))
324         {
325             return _resourceResolver.resolveUrl(viewId) != null;
326         }
327         return false;
328     }
329 
330     private RestoreViewFromPoolResult tryRestoreViewFromCache(FacesContext context, UIViewRoot view)
331     {
332         if (_viewPoolProcessor != null)
333         {
334             ViewPool viewPool = _viewPoolProcessor.getViewPool(context, view);
335             if (viewPool != null)
336             {
337                 ViewStructureMetadata metadata = viewPool.retrieveStaticViewStructureMetadata(context, view);
338                 if (metadata != null)
339                 {
340                     ViewEntry entry = viewPool.popStaticOrPartialStructureView(context, view);
341                     if (entry != null)
342                     {
343                         _viewPoolProcessor.cloneAndRestoreView(context, view, entry, metadata);
344                         return entry.getResult();
345                     }
346                 }
347             }
348         }
349         return null;
350     }
351 
352     /**
353      * {@inheritDoc}
354      */
355     @Override
356     public void buildView(FacesContext context, UIViewRoot view) throws IOException
357     {
358         if (isFilledView(context, view))
359         {
360             if (view != null && 
361                 FaceletViewDeclarationLanguageBase.isDynamicComponentRefreshTransientBuildActive(context, view))
362             {
363                 // don't return
364             }
365             else
366             {
367                 return;
368             }
369         }
370 
371         // setup our viewId
372         String previousViewId = view.getViewId();
373         String renderedViewId = getRenderedViewId(context, previousViewId);
374 
375         if (renderedViewId == null)
376         {
377             view.setViewId(renderedViewId);
378         }
379         else if (!renderedViewId.equals(previousViewId))
380         {
381             view.setViewId(renderedViewId);
382         }
383 
384         if (log.isLoggable(Level.FINEST))
385         {
386             log.finest("Building View: " + renderedViewId);
387         }
388 
389         boolean usePartialStateSavingOnThisView = _usePartialStateSavingOnThisView(renderedViewId);
390         boolean refreshTransientBuild = (view.getChildCount() > 0);
391         boolean refreshTransientBuildOnPSS = (usePartialStateSavingOnThisView && _refreshTransientBuildOnPSS);
392         boolean refreshPartialView = false;
393 
394         if (_viewPoolProcessor != null && !refreshTransientBuild)
395         {
396             RestoreViewFromPoolResult result = tryRestoreViewFromCache(context, view);
397             if (result != null)
398             {
399                 // Since all transient stuff has been removed, add listeners that keep
400                 // track of tree updates.
401                 if (RestoreViewFromPoolResult.COMPLETE.equals(result))
402                 {
403                     if (!PhaseId.RESTORE_VIEW.equals(context.getCurrentPhaseId()))
404                     {
405                         ((DefaultFaceletsStateManagementStrategy) 
406                                 getStateManagementStrategy(context, view.getViewId())).
407                                 suscribeListeners(view);
408                     }
409                     // If the result is complete, the view restored here is static. 
410                     // static views can be marked as filled.
411                     if (!refreshTransientBuildOnPSS)
412                     {
413                         // This option will be true on this cases:
414                         // -pss is true and refresh is not active
415                         setFilledView(context, view);
416                     }
417                     //At this point refreshTransientBuild = false && refreshTransientBuildOnPSS is true
418                     else if (_refreshTransientBuildOnPSSAuto &&
419                              !context.getAttributes().containsKey(CLEAN_TRANSIENT_BUILD_ON_RESTORE))
420                     {
421                         setFilledView(context, view);
422                     }
423                     return;
424                 }
425                 else
426                 {
427                     // We need to refresh a partial view.
428                     refreshTransientBuild = true;
429                     refreshPartialView = true;
430                 }
431             }
432         }
433         
434         if (usePartialStateSavingOnThisView)
435         {
436             // Before apply we need to make sure the current view has
437             // a clientId that will be used as a key to save and restore
438             // the current view. Note that getClientId is never called (or used)
439             // from UIViewRoot.
440             if (view.getId() == null)
441             {
442                 view.setId(view.createUniqueId(context, null));
443             }
444 
445             context.getAttributes().put(USING_PSS_ON_THIS_VIEW, Boolean.TRUE);
446             //Add a key to indicate ComponentTagHandlerDelegate to 
447             //call UIComponent.markInitialState after it is populated
448             if (!refreshTransientBuild || refreshPartialView)
449             {
450                 context.getAttributes().put(StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
451                 context.getAttributes().put(IS_BUILDING_INITIAL_STATE_KEY_ALIAS, Boolean.TRUE);
452             }
453             if (!refreshTransientBuild && _markInitialStateWhenApplyBuildView)
454             {
455                 context.getAttributes().put(MARK_INITIAL_STATE_KEY, Boolean.TRUE);
456             }
457             if (refreshTransientBuildOnPSS)
458             {
459                 //This value is only set when _refreshTransientBuildOnPSSMode is "auto" or "true" 
460                 context.getAttributes().put(REFRESH_TRANSIENT_BUILD_ON_PSS,
461                                             _refreshTransientBuildOnPSSAuto ? "auto" : "true");
462             }
463         }
464 
465         try
466         {
467             if (refreshTransientBuild)
468             {
469                 context.getAttributes().put(REFRESHING_TRANSIENT_BUILD, Boolean.TRUE);
470 
471                 // In theory, this should be disabled on ComponentTagHandlerDelegate,
472                 // otherwise we could lost PostAddToViewEvent / PreRemoveFromViewEvent
473                 // caused by c:if effect or facelets cleanup algorithm
474                 //context.setProcessingEvents(false);
475             }
476             // populate UIViewRoot
477             _getFacelet(context, renderedViewId).apply(context, view);
478         }
479         finally
480         {
481             if (refreshTransientBuildOnPSS)
482             {
483                 context.getAttributes().remove(REFRESH_TRANSIENT_BUILD_ON_PSS);
484             }
485             if (refreshTransientBuild)
486             {
487                 //context.setProcessingEvents(true);
488                 if (FaceletViewDeclarationLanguageBase.isDynamicComponentRefreshTransientBuildActive(context))
489                 {
490                     VisitContext visitContext = (VisitContext) getVisitContextFactory().
491                         getVisitContext(context, null, VISIT_HINTS_DYN_REFRESH);
492                     view.visitTree(visitContext, new PublishDynamicComponentRefreshTransientBuildCallback());
493                 }
494                 if (!usePartialStateSavingOnThisView || refreshTransientBuildOnPSS)
495                 {
496                     // When the facelet is applied, all components are removed and added from view,
497                     // but the difference resides in the ordering. Since the view is
498                     // being refreshed, if we don't do this manually, some tags like
499                     // cc:insertChildren or cc:insertFacet will not work correctly, because
500                     // we expect PostAddToViewEvent will be propagated from parent to child, and
501                     // facelets refreshing algorithm do the opposite.
502                     //FaceletViewDeclarationLanguage._publishPreRemoveFromViewEvent(context, view);
503                     //FaceletViewDeclarationLanguage._publishPostAddToViewEvent(context, view);
504                     FaceletViewDeclarationLanguage._publishPostBuildComponentTreeOnRestoreViewEvent(context, view);
505                 }
506 
507                 context.getAttributes().remove(REFRESHING_TRANSIENT_BUILD);
508             }
509             else
510             {
511                 // Publish PostAddToView over UIViewRoot, because this is not done automatically.
512                 context.getApplication().publishEvent(context, PostAddToViewEvent.class, UIViewRoot.class, view);
513             }
514         }
515 
516         // set this view as filled
517         if (refreshTransientBuild)
518         {
519             //This option will be true on this cases:
520             //- pss is false, but we are refreshing
521             //- pss is true, and we are refreshing a view already filled
522             setFilledView(context, view);
523         }
524         else if (!refreshTransientBuildOnPSS)
525         {
526             // This option will be true on this cases:
527             // -pss is true and refresh is not active
528             setFilledView(context, view);
529         }
530         //At this point refreshTransientBuild = false && refreshTransientBuildOnPSS is true
531         else if (_refreshTransientBuildOnPSSAuto &&
532                  !context.getAttributes().containsKey(CLEAN_TRANSIENT_BUILD_ON_RESTORE))
533         {
534             setFilledView(context, view);
535         }
536 
537         // Suscribe listeners if we are using partialStateSaving
538         if (usePartialStateSavingOnThisView)
539         {
540             // UIViewRoot.markInitialState() is not called because it does
541             // not have a facelet tag handler class that create it, instead
542             // new instances are created programatically.
543             if (!refreshTransientBuild || refreshPartialView)
544             {
545                 // Save the state
546                 if (_viewPoolProcessor != null &&
547                     _viewPoolProcessor.isViewPoolEnabledForThisView(context, view))
548                 {
549                     _viewPoolProcessor.storeViewStructureMetadata(context, view);
550                 }
551                 if (_markInitialStateWhenApplyBuildView)
552                 {
553                     if (!refreshTransientBuildOnPSS ||
554                         !view.getAttributes().containsKey(COMPONENT_ADDED_AFTER_BUILD_VIEW))
555                     {
556                         view.markInitialState();
557                     }
558 
559                     //Remove the key that indicate we need to call UIComponent.markInitialState
560                     //on the current tree
561                     context.getAttributes().remove(MARK_INITIAL_STATE_KEY);
562                 }
563                 else
564                 {
565                     context.getAttributes().put(MARK_INITIAL_STATE_KEY, Boolean.TRUE);
566                     _markInitialStateOnView(view, refreshTransientBuildOnPSS);
567                     context.getAttributes().remove(MARK_INITIAL_STATE_KEY);
568                 }
569                 context.getAttributes().remove(StateManager.IS_BUILDING_INITIAL_STATE);
570                 context.getAttributes().remove(IS_BUILDING_INITIAL_STATE_KEY_ALIAS);
571             }
572 
573             // We need to suscribe the listeners of changes in the component tree
574             // only the first time here. Later we suscribe this listeners on
575             // DefaultFaceletsStateManagement.restoreView after calling 
576             // _publishPostBuildComponentTreeOnRestoreViewEvent(), to ensure 
577             // relocated components are not retrieved later on getClientIdsRemoved().
578             if (!(refreshTransientBuild && PhaseId.RESTORE_VIEW.equals(context.getCurrentPhaseId())) &&
579                 !view.isTransient())
580             {
581                 ((DefaultFaceletsStateManagementStrategy) getStateManagementStrategy(context, view.getViewId())).
582                         suscribeListeners(view);
583             }
584 
585             context.getAttributes().remove(USING_PSS_ON_THIS_VIEW);
586         }
587 
588         // Remove this var from faces context because this one prevent AjaxHandler
589         // register the standard script library on Post-Redirect-Get pattern or
590         // in the next view
591         context.getAttributes().remove(AjaxHandler.STANDARD_JSF_AJAX_LIBRARY_LOADED);
592     }
593 
594     private void _markInitialStateOnView(final UIViewRoot view, final boolean refreshTransientBuildOnPSS)
595     {
596         if (!refreshTransientBuildOnPSS ||
597                 !view.getAttributes().containsKey(COMPONENT_ADDED_AFTER_BUILD_VIEW))
598         {
599             if (!view.isTransient())
600             {
601                 view.markInitialState();
602             }
603         }
604 
605         int childCount = view.getChildCount();
606         if (childCount > 0)
607         {
608             for (int i = 0; i < childCount; i++)
609             {
610                 UIComponent child = view.getChildren().get(i);
611                 if (!child.isTransient())
612                 {
613                     _markInitialState(child);
614                 }
615             }
616         }
617         if (view.getFacetCount() > 0)
618         {
619             Map<String, UIComponent> facetMap = view.getFacets();
620             for (Map.Entry<String, UIComponent> entry : facetMap.entrySet())
621             {
622                 UIComponent child = entry.getValue();
623                 if (!child.isTransient())
624                 {
625                     _markInitialState(child);
626                 }
627             }
628 
629         }
630     }
631 
632     private void _markInitialState(final UIComponent component)
633     {
634         component.markInitialState();
635 
636         final int childCount = component.getChildCount();
637         if (childCount > 0)
638         {
639             for (int i = 0; i < childCount; i++)
640             {
641                 UIComponent child = component.getChildren().get(i);
642                 if (!child.isTransient())
643                 {
644                     _markInitialState(child);
645                 }
646             }
647         }
648         if (component.getFacetCount() > 0)
649         {
650             Map<String, UIComponent> facetMap = component.getFacets();
651             for (Map.Entry<String, UIComponent> entry : facetMap.entrySet())
652             {
653                 UIComponent child = entry.getValue();
654                 if (!child.isTransient())
655                 {
656                     _markInitialState(child);
657                 }
658             }
659 
660         }
661     }
662 
663     public static void _publishPostBuildComponentTreeOnRestoreViewEvent(FacesContext context, UIComponent component)
664     {
665         context.getApplication().publishEvent(context, PostBuildComponentTreeOnRestoreViewEvent.class,
666                                               component.getClass(), component);
667 
668         if (component.getChildCount() > 0)
669         {
670             // PostAddToViewEvent could cause component relocation
671             // (h:outputScript, h:outputStylesheet, composite:insertChildren, composite:insertFacet)
672             // so we need to check if the component was relocated or not
673             List<UIComponent> children = component.getChildren();
674             UIComponent child = null;
675             UIComponent currentChild = null;
676             int i = 0;
677             while (i < children.size())
678             {
679                 child = children.get(i);
680                 // Iterate over the same index if the component was removed
681                 // This prevents skip components when processing
682                 do
683                 {
684                     _publishPostBuildComponentTreeOnRestoreViewEvent(context, child);
685                     currentChild = child;
686                     child = children.get(i);
687                 }
688                 while ((i < children.size()) && child != currentChild);
689                 i++;
690             }
691         }
692         if (component.getFacetCount() > 0)
693         {
694             for (UIComponent child : component.getFacets().values())
695             {
696                 _publishPostBuildComponentTreeOnRestoreViewEvent(context, child);
697             }
698         }
699     }
700 
701     private boolean isFilledView(FacesContext context, UIViewRoot view)
702     {
703         // The view is only built on restoreView or renderView, but if
704         // we are not using partial state saving, we need to mark the current
705         // view as filled, otherwise it will be filled again on renderView.
706         return context.getAttributes().containsKey(view);
707         // -= Leonardo Uribe =- save this key on view cause render fail, because the view
708         // is built before render view to "restore" the transient components that has
709         // facelet markup (facelets UIInstructions ...) This effect is only notice when
710         // partial state saving is not used. 
711         //return view.getAttributes().containsKey(FILLED_VIEW);
712     }
713 
714     private void setFilledView(FacesContext context, UIViewRoot view)
715     {
716         context.getAttributes().put(view, Boolean.TRUE);
717         // -= Leonardo Uribe =- save this key on view cause render fail, because the view
718         // is built before render view to "restore" the transient components that has
719         // facelet markup (facelets UIInstructions ...) This effect is only notice when
720         // partial state saving is not used. 
721         // view.getAttributes().put(FILLED_VIEW, Boolean.TRUE);
722     }
723 
724     /**
725      * retargetMethodExpressions(FacesContext, UIComponent) has some clues about the behavior of this method
726      *
727      * {@inheritDoc}
728      */
729     @Override
730     public BeanInfo getComponentMetadata(FacesContext context, Resource componentResource)
731     {
732         BeanInfo beanInfo = null;
733 
734         checkNull(context, "context");
735 
736         try
737         {
738             Facelet compositeComponentFacelet;
739             FaceletFactory.setInstance(_faceletFactory);
740             try
741             {
742                 compositeComponentFacelet
743                         = _faceletFactory.getCompositeComponentMetadataFacelet(componentResource.getURL());
744             }
745             finally
746             {
747                 FaceletFactory.setInstance(null);
748             }
749             //context.getAttributes().put(BUILDING_COMPOSITE_COMPONENT_METADATA, Boolean.TRUE);
750 
751             // Create a temporal tree where all components will be put, but we are only
752             // interested in metadata.
753             UINamingContainer compositeComponentBase
754                     = (UINamingContainer) context.getApplication().createComponent(
755                     context, UINamingContainer.COMPONENT_TYPE, null);
756 
757             // Fill the component resource key, because this information should be available
758             // on metadata to recognize which is the component used as composite component base.
759             // Since this method is called from Application.createComponent(FacesContext,Resource),
760             // and in that specific method this key is updated, this is the best option we
761             // have for recognize it (also this key is used by UIComponent.isCompositeComponent)
762             compositeComponentBase.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY, componentResource);
763 
764             // According to UserTagHandler, in this point we need to wrap the facelet
765             // VariableMapper, so local changes are applied on "page context", but
766             // data is retrieved from full context
767             FaceletContext faceletContext = (FaceletContext) context.
768                     getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
769             VariableMapper orig = faceletContext.getVariableMapper();
770             try
771             {
772                 faceletContext.setVariableMapper(new VariableMapperWrapper(orig));
773 
774                 compositeComponentBase.pushComponentToEL(context, compositeComponentBase);
775 
776                 compositeComponentFacelet.apply(context, compositeComponentBase);
777 
778                 compositeComponentBase.popComponentFromEL(context);
779             }
780             finally
781             {
782                 faceletContext.setVariableMapper(orig);
783             }
784 
785             beanInfo = (BeanInfo) compositeComponentBase.getAttributes().get(UIComponent.BEANINFO_KEY);
786         }
787         catch (IOException e)
788         {
789             throw new FacesException(e);
790         }
791         //finally
792         //{
793         //context.getAttributes().remove(BUILDING_COMPOSITE_COMPONENT_METADATA);
794         //}
795 
796         return beanInfo;
797     }
798 
799     /**
800      * Check if the current facelet applied is used to build composite component metadata.
801      *
802      * @param context
803      * @return
804      */
805     //public static boolean isBuildingCompositeComponentMetadata(FacesContext context)
806     //{
807     //    return context.getAttributes().containsKey(BUILDING_COMPOSITE_COMPONENT_METADATA);
808     //}
809 
810     /**
811      * Check if the current facelet applied is used to build view metadata.
812      *
813      * @param context
814      * @return
815      */
816     public static boolean isBuildingViewMetadata(FacesContext context)
817     {
818         return context.getAttributes().containsKey(BUILDING_VIEW_METADATA);
819     }
820 
821     public static boolean isRefreshingTransientBuild(FacesContext context)
822     {
823         return context.getAttributes().containsKey(REFRESHING_TRANSIENT_BUILD);
824     }
825 
826     public static boolean isRemovingComponentBuild(FacesContext context)
827     {
828         return context.getAttributes().containsKey(REMOVING_COMPONENTS_BUILD);
829     }
830 
831     public static boolean isMarkInitialState(FacesContext context)
832     {
833         return Boolean.TRUE.equals(context.getAttributes().get(MARK_INITIAL_STATE_KEY));
834     }
835 
836     public static boolean isRefreshTransientBuildOnPSS(FacesContext context)
837     {
838         //this include both "true" and "auto"
839         return context.getAttributes().containsKey(REFRESH_TRANSIENT_BUILD_ON_PSS);
840     }
841 
842     public static boolean isRefreshTransientBuildOnPSSAuto(FacesContext context)
843     {
844         return "auto".equalsIgnoreCase((String) context.getAttributes().get(REFRESH_TRANSIENT_BUILD_ON_PSS));
845     }
846 
847     public static boolean isCleanTransientBuildOnRestore(FacesContext context)
848     {
849         return context.getAttributes().containsKey(CLEAN_TRANSIENT_BUILD_ON_RESTORE);
850     }
851 
852     public static void cleanTransientBuildOnRestore(FacesContext context)
853     {
854         context.getAttributes().put(CLEAN_TRANSIENT_BUILD_ON_RESTORE, Boolean.TRUE);
855     }
856 
857     public static boolean isUsingPSSOnThisView(FacesContext context)
858     {
859         return context.getAttributes().containsKey(USING_PSS_ON_THIS_VIEW);
860     }
861 
862     /**
863      * In short words, this method take care of "target" an "attached object".
864      * <ul>
865      * <li>The "attached object" is instantiated by a tag handler.</li> 
866      * <li>The "target" is an object used as "marker", that exposes a List<UIComponent></li>
867      * </ul>
868      * This method should be called from some composite component tag handler, after
869      * all children of composite component has been applied.
870      */
871     @Override
872     @SuppressWarnings("unchecked")
873     public void retargetAttachedObjects(FacesContext context,
874                                         UIComponent topLevelComponent, List<AttachedObjectHandler> handlerList)
875     {
876         checkNull(context, "context");
877         checkNull(topLevelComponent, "topLevelComponent");
878         checkNull(handlerList, "handlerList");
879 
880         BeanInfo compositeComponentMetadata
881                 = (BeanInfo) topLevelComponent.getAttributes().get(UIComponent.BEANINFO_KEY);
882 
883         if (compositeComponentMetadata == null)
884         {
885             log.severe("Composite component metadata not found for: " + topLevelComponent.getClientId(context));
886             return;
887         }
888 
889         BeanDescriptor compositeComponentDescriptor = compositeComponentMetadata.getBeanDescriptor();
890 
891         List<AttachedObjectTarget> targetList = (List<AttachedObjectTarget>)
892                 compositeComponentDescriptor.getValue(AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY);
893 
894         if (targetList == null || targetList.isEmpty())
895         {
896             return;
897         }
898 
899         for (int i = 0, size = handlerList.size(); i < size; i++)
900         {
901             AttachedObjectHandler currentHandler = handlerList.get(i);
902             // In the spec javadoc this variable is referred as forAttributeValue, but
903             // note it is also called curTargetName
904             String forValue = currentHandler.getFor();
905             
906             // perf: targetList is always arrayList: see AttachedObjectTargetHandler.apply 
907             // and ClientBehaviorHandler.apply 
908             for (int k = 0, targetsSize = targetList.size(); k < targetsSize; k++)
909             {
910                 AttachedObjectTarget currentTarget = targetList.get(k);
911                 FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance();
912 
913                 if ((forValue != null && forValue.equals(currentTarget.getName())) &&
914                         ((currentTarget instanceof ActionSource2AttachedObjectTarget &&
915                                 currentHandler instanceof ActionSource2AttachedObjectHandler) ||
916                                 (currentTarget instanceof EditableValueHolderAttachedObjectTarget &&
917                                         currentHandler instanceof EditableValueHolderAttachedObjectHandler) ||
918                                 (currentTarget instanceof ValueHolderAttachedObjectTarget &&
919                                         currentHandler instanceof ValueHolderAttachedObjectHandler)))
920                 {
921                     // perf: getTargets return ArrayList - see getTargets implementations
922                     List<UIComponent> targets = currentTarget.getTargets(topLevelComponent);
923                     for (int l = 0, targetsCount = targets.size(); l < targetsCount; l++)
924                     {
925                         UIComponent component = targets.get(l);
926                         // If we found composite components when traverse the tree
927                         // we have to call this one recursively, because each composite component
928                         // should have its own AttachedObjectHandler list, filled earlier when
929                         // its tag handler is applied.
930                         if (UIComponent.isCompositeComponent(component))
931                         {
932                             // How we obtain the list of AttachedObjectHandler for
933                             // the current composite component? It should be a component
934                             // attribute or retrieved by a key inside component.getAttributes
935                             // map. Since api does not specify any attribute, we suppose
936                             // this is an implementation detail and it should be retrieved
937                             // from component attribute map.
938                             // But this is only the point of the iceberg, because we should
939                             // define how we register attached object handlers in this list.
940                             // ANS: see CompositeComponentResourceTagHandler.
941                             // The current handler should be added to the list, to be chained.
942                             // Note that the inner component should have a target with the same name
943                             // as "for" attribute
944                             mctx.addAttachedObjectHandler(component, currentHandler);
945 
946                             List<AttachedObjectHandler> handlers = mctx.getAttachedObjectHandlers(component);
947 
948                             retargetAttachedObjects(context, component, handlers);
949 
950                             handlers.remove(currentHandler);
951                         }
952                         else
953                         {
954                             currentHandler.applyAttachedObject(context, component);
955                         }
956                         if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
957                         {
958                             component.markInitialState();
959                         }
960                     }
961                 }
962                 else if ((currentTarget instanceof BehaviorHolderAttachedObjectTarget &&
963                         currentHandler instanceof BehaviorHolderAttachedObjectHandler))
964                 {
965                     String eventName = ((BehaviorHolderAttachedObjectHandler) currentHandler).getEventName();
966                     boolean isDefaultEvent = ((BehaviorHolderAttachedObjectTarget) currentTarget).isDefaultEvent();
967 
968                     if ((eventName != null && eventName.equals(currentTarget.getName())) ||
969                             (eventName == null && isDefaultEvent))
970                     {
971                         List<UIComponent> targets = currentTarget.getTargets(topLevelComponent);
972                         for (int j = 0, targetssize = targets.size(); j < targetssize; j++)
973                         {
974                             UIComponent component = targets.get(j);
975                             // If we found composite components when traverse the tree
976                             // we have to call this one recursively, because each composite component
977                             // should have its own AttachedObjectHandler list, filled earlier when
978                             // its tag handler is applied.
979                             if (UIComponent.isCompositeComponent(component))
980                             {
981                                 if (currentTarget instanceof ClientBehaviorAttachedObjectTarget)
982                                 {
983                                     mctx.addAttachedObjectHandler(component,
984                                             new ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper(
985                                                     (BehaviorHolderAttachedObjectHandler) currentHandler,
986                                                     ((ClientBehaviorAttachedObjectTarget) currentTarget).getEvent()));
987                                 }
988                                 else
989                                 {
990                                     mctx.addAttachedObjectHandler(component, currentHandler);
991                                 }
992 
993                                 List<AttachedObjectHandler> handlers = mctx.getAttachedObjectHandlers(component);
994 
995                                 retargetAttachedObjects(context, component, handlers);
996 
997                                 handlers.remove(currentHandler);
998                             }
999                             else
1000                             {
1001                                 if (currentHandler instanceof
1002                                         ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper)
1003                                 {
1004                                     currentHandler.applyAttachedObject(context,
1005                                             new ClientBehaviorRedirectEventComponentWrapper(component,
1006                                             ((ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper)
1007                                                     currentHandler).getWrappedEventName(), eventName));
1008                                 }
1009                                 else
1010                                 {
1011                                     currentHandler.applyAttachedObject(context, component);
1012                                 }
1013                             }
1014                             if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
1015                             {
1016                                 component.markInitialState();
1017                             }
1018                         }
1019                     }
1020                 }
1021             }
1022         }
1023     }
1024 
1025     @Override
1026     public void retargetMethodExpressions(FacesContext context, UIComponent topLevelComponent)
1027     {
1028         checkNull(context, "context");
1029 
1030         BeanInfo compositeComponentMetadata
1031                 = (BeanInfo) topLevelComponent.getAttributes().get(UIComponent.BEANINFO_KEY);
1032 
1033         if (compositeComponentMetadata == null)
1034         {
1035             log.severe("Composite component metadata not found for: " + topLevelComponent.getClientId(context));
1036             return;
1037         }
1038 
1039         // "...For each attribute that is a MethodExpression..." This means we have to scan
1040         // all attributes with "method-signature" attribute and no "type" attribute
1041         // javax.faces.component._ComponentAttributesMap uses BeanInfo.getPropertyDescriptors to
1042         // traverse over it, but here the metadata returned by UIComponent.BEANINFO_KEY is available
1043         // only for composite components.
1044         // That means somewhere we need to create a custom BeanInfo object for composite components
1045         // that will be filled somewhere (theorically in ViewDeclarationLanguage.getComponentMetadata())
1046 
1047         PropertyDescriptor[] propertyDescriptors = compositeComponentMetadata.getPropertyDescriptors();
1048 
1049         ELContext elContext = (ELContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
1050 
1051         for (PropertyDescriptor propertyDescriptor : propertyDescriptors)
1052         {
1053             if (propertyDescriptor.getValue("type") != null)
1054             {
1055                 // This check is necessary if we have both "type" and "method-signature" set.
1056                 // In that case, "method-signature" is ignored
1057                 continue;
1058             }
1059 
1060             String attributeName = propertyDescriptor.getName();
1061             //boolean isKnownMethod = "action".equals(attributeName) || "actionListener".equals(attributeName)  
1062             //        || "validator".equals(attributeName) || "valueChangeListener".equals(attributeName);
1063 
1064             // <composite:attribute> method-signature attribute is 
1065             // ValueExpression that must evaluate to String
1066             ValueExpression methodSignatureExpression
1067                     = (ValueExpression) propertyDescriptor.getValue("method-signature");
1068             String methodSignature = null;
1069             if (methodSignatureExpression != null)
1070             {
1071                 // Check if the value expression holds a method signature
1072                 // Note that it could be null, so in that case we don't have to do anything
1073                 methodSignature = (String) methodSignatureExpression.getValue(elContext);
1074             }
1075 
1076             String targetAttributeName = null;
1077             ValueExpression targetAttributeNameVE
1078                     = (ValueExpression) propertyDescriptor.getValue("targetAttributeName");
1079             if (targetAttributeNameVE != null)
1080             {
1081                 targetAttributeName = (String) targetAttributeNameVE.getValue(context.getELContext());
1082                 if (targetAttributeName == null)
1083                 {
1084                     targetAttributeName = attributeName;
1085                 }
1086             }
1087             else
1088             {
1089                 targetAttributeName = attributeName;
1090             }
1091 
1092             boolean isKnownTargetAttributeMethod
1093                     = "action".equals(targetAttributeName) || "actionListener".equals(targetAttributeName)
1094                       || "validator".equals(targetAttributeName) || "valueChangeListener".equals(targetAttributeName);
1095 
1096             // either the attributeName has to be a knownMethod or there has to be a method-signature
1097             if (isKnownTargetAttributeMethod || methodSignature != null)
1098             {
1099                 ValueExpression targetsExpression =
1100                         (ValueExpression) propertyDescriptor.getValue("targets");
1101 
1102                 String targets = null;
1103                 // <composite:attribute> targets attribute is 
1104                 // ValueExpression that must evaluate to String
1105                 if (targetsExpression != null)
1106                 {
1107                     targets = (String) targetsExpression.getValue(elContext);
1108                 }
1109 
1110                 if (targets == null)
1111                 {
1112                     // "...let the name of the metadata element be the 
1113                     // evaluated value of the targets attribute..."
1114                     targets = attributeName;
1115                 }
1116 
1117                 FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance();
1118 
1119                 // If the MethodExpression attribute has been already applied, there is no need to
1120                 // handle it and it is probably a MethodExpression instance is on attribute map, so the
1121                 // inner code will cause a ClassCastException.
1122                 if (!mctx.isMethodExpressionAttributeApplied(topLevelComponent, attributeName))
1123                 {
1124 
1125                     ValueExpression attributeNameValueExpression =
1126                             (ValueExpression) topLevelComponent.getAttributes().get(attributeName);
1127 
1128                     if (attributeNameValueExpression == null)
1129                     {
1130                         // composite:attribute has a default property, so if we can't found on the
1131                         // component attribute map, we should get the default as CompositeComponentELResolver
1132                         // does.
1133                         attributeNameValueExpression = (ValueExpression) propertyDescriptor.getValue("default");
1134                         if (attributeNameValueExpression == null)
1135                         {
1136                             // It is only valid to log an error if the attribute is required
1137                             ValueExpression ve = (ValueExpression) propertyDescriptor.getValue("required");
1138                             if (ve != null)
1139                             {
1140                                 Object requiredValue = ve.getValue(elContext);
1141                                 Boolean required = null;
1142                                 if (requiredValue instanceof Boolean)
1143                                 {
1144                                     required = (Boolean) requiredValue;
1145                                 }
1146                                 else
1147                                 {
1148                                     required = Boolean.valueOf(requiredValue.toString());
1149                                 }
1150 
1151                                 if (required != null && required.booleanValue())
1152                                 {
1153                                     if (log.isLoggable(Level.SEVERE))
1154                                     {
1155                                         log.severe("attributeValueExpression not found under the key \""
1156                                                    + attributeName
1157                                                    + "\". Looking for the next attribute");
1158                                     }
1159                                 }
1160                             }
1161                             continue;
1162                         }
1163                     }
1164 
1165                     String[] targetsArray = StringUtils.splitShortString(targets, ' ');
1166                     String attributeExpressionString = attributeNameValueExpression.getExpressionString();
1167 
1168                     //Check if the stored valueExpression is a ccRedirection, to handle it properly later.
1169                     boolean ccAttrMeRedirection =
1170                             attributeNameValueExpression instanceof LocationValueExpression &&
1171                                     CompositeComponentELUtils.isCompositeComponentAttrsMethodExpression(
1172                                             attributeNameValueExpression.getExpressionString());
1173 
1174                     if (isKnownTargetAttributeMethod)
1175                     {
1176                         // To add support to #{cc.attrs.action}, #{cc.attrs.actionListener}, #{cc.attrs.validator} or
1177                         // #{cc.attrs.valueChangeListener} it is necessary to put a MethodExpression or a 
1178                         // ValueExpression pointing to the associated java method in the component attribute map.
1179                         // org.apache.myfaces.view.facelets.tag.composite.RetargetMethodExpressionRule already put
1180                         // a ValueExpression, so we only need to put a MethodExpression when a non redirecting
1181                         // expression is used (for example when a nested #{cc.attrs.xxx} is used).
1182                         if ("action".equals(targetAttributeName))
1183                         {
1184                             applyActionMethodExpressionEL(context, elContext,
1185                                     topLevelComponent, attributeName,
1186                                     attributeExpressionString, attributeNameValueExpression,
1187                                     ccAttrMeRedirection);
1188                         }
1189                         else if ("actionListener".equals(targetAttributeName))
1190                         {
1191                             applyActionListenerMethodExpressionEL(context, elContext,
1192                                     topLevelComponent, attributeName, 
1193                                     attributeExpressionString, attributeNameValueExpression, 
1194                                     ccAttrMeRedirection);
1195                         }
1196                         else if ("validator".equals(targetAttributeName))
1197                         {
1198                             applyValidatorMethodExpressionEL(context, elContext,
1199                                     topLevelComponent, attributeName,
1200                                     attributeExpressionString, attributeNameValueExpression, 
1201                                     ccAttrMeRedirection);
1202                         }
1203                         else if ("valueChangeListener".equals(targetAttributeName))
1204                         {
1205                             applyValueChangeListenerMethodExpressionEL(context, elContext,
1206                                     topLevelComponent, attributeName, 
1207                                     attributeExpressionString, attributeNameValueExpression,
1208                                     ccAttrMeRedirection);
1209                         }
1210 
1211                         UIComponent topLevelComponentBase = 
1212                             topLevelComponent.getFacet(UIComponent.COMPOSITE_FACET_NAME);
1213 
1214                         for (String target : targetsArray)
1215                         {
1216                             UIComponent innerComponent
1217                                     = ComponentSupport.findComponentChildOrFacetFrom(context, topLevelComponentBase,
1218                                                                                      target);
1219 
1220                             if (innerComponent == null)
1221                             {
1222                                 continue;
1223                             }
1224 
1225                             if (isCompositeComponentRetarget(context, innerComponent, targetAttributeName))
1226                             {
1227                                 innerComponent.getAttributes().put(targetAttributeName, attributeNameValueExpression);
1228 
1229                                 mctx.clearMethodExpressionAttribute(innerComponent, targetAttributeName);
1230 
1231                                 retargetMethodExpressions(context, innerComponent);
1232                                 if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
1233                                 {
1234                                     innerComponent.markInitialState();
1235                                 }
1236                             }
1237                             else
1238                             {
1239                                 if ("action".equals(targetAttributeName))
1240                                 {
1241                                     applyActionMethodExpressionTarget(context, mctx, elContext,
1242                                             topLevelComponentBase, innerComponent, 
1243                                             attributeName, targetAttributeName, 
1244                                             attributeExpressionString, attributeNameValueExpression, 
1245                                             ccAttrMeRedirection);
1246                                     if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
1247                                     {
1248                                         innerComponent.markInitialState();
1249                                     }
1250                                 }
1251                                 else if ("actionListener".equals(targetAttributeName))
1252                                 {
1253                                     applyActionListenerMethodExpressionTarget(context, mctx, elContext, 
1254                                             topLevelComponentBase, innerComponent, 
1255                                             attributeName, targetAttributeName, 
1256                                             attributeExpressionString, attributeNameValueExpression, 
1257                                             ccAttrMeRedirection);
1258                                     if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
1259                                     {
1260                                         innerComponent.markInitialState();
1261                                     }
1262                                 }
1263                                 else if ("validator".equals(targetAttributeName))
1264                                 {
1265                                     applyValidatorMethodExpressionTarget(context, mctx, elContext,
1266                                             topLevelComponentBase, innerComponent, 
1267                                             attributeName, targetAttributeName, 
1268                                             attributeExpressionString, attributeNameValueExpression, 
1269                                             ccAttrMeRedirection);
1270                                     if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
1271                                     {
1272                                         innerComponent.markInitialState();
1273                                     }
1274                                 }
1275                                 else if ("valueChangeListener".equals(targetAttributeName))
1276                                 {
1277                                     applyValueChangeListenerMethodExpressionTarget(context, mctx, elContext,
1278                                             topLevelComponentBase, innerComponent, 
1279                                             attributeName, targetAttributeName,
1280                                             attributeExpressionString, attributeNameValueExpression,
1281                                             ccAttrMeRedirection);
1282                                     if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
1283                                     {
1284                                         innerComponent.markInitialState();
1285                                     }
1286                                 }
1287                             }
1288                         }
1289                     }
1290                     else
1291                     {
1292                         MethodExpression methodExpression = null;
1293                         // composite:attribute targets property only has sense for action, actionListener,
1294                         // validator or valueChangeListener. This means we have to retarget the method expression
1295                         // to the topLevelComponent.
1296 
1297                         // Since a MethodExpression has no state, we can use it multiple times without problem, so
1298                         // first create it here.
1299                         methodSignature = methodSignature.trim();
1300                         methodExpression = context.getApplication().getExpressionFactory().
1301                                 createMethodExpression(elContext,
1302                                         attributeExpressionString, 
1303                                         FaceletsViewDeclarationLanguageUtils.getReturnType(methodSignature),
1304                                         FaceletsViewDeclarationLanguageUtils.getParameters(methodSignature));
1305 
1306                         methodExpression = reWrapMethodExpression(methodExpression, attributeNameValueExpression);
1307 
1308                         applyMethodExpression(context, mctx, topLevelComponent, attributeName, 
1309                                 targetAttributeName, attributeNameValueExpression, methodExpression, 
1310                                 ccAttrMeRedirection, targetsArray);
1311                     }
1312                     mctx.markMethodExpressionAttribute(topLevelComponent, attributeName);
1313                 }
1314 
1315                 // We need to remove the previous ValueExpression, to prevent some possible
1316                 // confusion when the same value is retrieved from the attribute map.
1317                 topLevelComponent.setValueExpression(attributeName, null);
1318             }
1319         }
1320     }
1321     
1322     private void applyActionMethodExpressionEL(FacesContext context, 
1323                                                ELContext elContext, 
1324                                                UIComponent topLevelComponent, 
1325                                                String attributeName,
1326                                                String attributeExpressionString, 
1327                                                ValueExpression attributeNameValueExpression, 
1328                                                boolean ccAttrMeRedirection)
1329     {
1330         // target is ActionSource2
1331         MethodExpression methodExpression = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1332                 createMethodExpression(elContext,
1333                         attributeExpressionString, null,
1334                         EMPTY_CLASS_ARRAY), attributeNameValueExpression);
1335 
1336         //Store the method expression to the topLevelComponent to allow reference it through EL
1337         if (!ccAttrMeRedirection)
1338         {
1339             //Replace it with a method expression
1340             topLevelComponent.getAttributes().put(attributeName, methodExpression);
1341         }
1342         // Otherwise keep the current ValueExpression,
1343         // because it will be used chain other value expressions
1344     }
1345 
1346     private void applyActionListenerMethodExpressionEL(FacesContext context, 
1347                                                        ELContext elContext, 
1348                                                        UIComponent topLevelComponent, 
1349                                                        String attributeName,
1350                                                        String attributeExpressionString, 
1351                                                        ValueExpression attributeNameValueExpression, 
1352                                                        boolean ccAttrMeRedirection)
1353     {
1354         // target is ActionSource2
1355         MethodExpression methodExpression = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1356                 createMethodExpression(elContext,
1357                         attributeExpressionString, Void.TYPE, ACTION_LISTENER_SIGNATURE),
1358                         attributeNameValueExpression);
1359 
1360         MethodExpression methodExpression2 = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1361                 createMethodExpression(elContext,
1362                         attributeExpressionString, Void.TYPE, EMPTY_CLASS_ARRAY),
1363                         attributeNameValueExpression);
1364 
1365         //Store the method expression to the topLevelComponent to allow reference it through EL
1366         if (!ccAttrMeRedirection)
1367         {
1368             //Replace it with a method expression
1369             topLevelComponent.getAttributes().put(attributeName,
1370                     new MethodExpressionMethodExpression(methodExpression, methodExpression2));
1371         }
1372         // Otherwise keep the current ValueExpression,
1373         // because it will be used chain other value expressions
1374     }
1375     
1376     private void applyValidatorMethodExpressionEL(FacesContext context, 
1377                                                   ELContext elContext, 
1378                                                   UIComponent topLevelComponent, 
1379                                                   String attributeName,
1380                                                   String attributeExpressionString, 
1381                                                   ValueExpression attributeNameValueExpression, 
1382                                                   boolean ccAttrMeRedirection)
1383     {
1384         // target is EditableValueHolder
1385         MethodExpression methodExpression = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1386                 createMethodExpression(elContext,
1387                         attributeExpressionString, Void.TYPE,
1388                         VALIDATOR_SIGNATURE), attributeNameValueExpression);
1389 
1390         //Store the method expression to the topLevelComponent to allow reference it through EL
1391         if (!ccAttrMeRedirection)
1392         {
1393             //Replace it with a method expression
1394             topLevelComponent.getAttributes().put(attributeName, methodExpression);
1395         }
1396         // Otherwise keep the current ValueExpression,
1397         // because it will be used chain other value expressions
1398     }
1399     
1400     private void applyValueChangeListenerMethodExpressionEL(FacesContext context, 
1401                                                             ELContext elContext, 
1402                                                             UIComponent topLevelComponent, 
1403                                                             String attributeName,
1404                                                             String attributeExpressionString, 
1405                                                             ValueExpression attributeNameValueExpression, 
1406                                                             boolean ccAttrMeRedirection)
1407     {
1408         // target is EditableValueHolder
1409         MethodExpression methodExpression = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1410                 createMethodExpression(elContext,
1411                         attributeExpressionString, Void.TYPE,
1412                         VALUE_CHANGE_LISTENER_SIGNATURE), attributeNameValueExpression);
1413 
1414         MethodExpression methodExpression2 = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1415                 createMethodExpression(elContext,
1416                         attributeExpressionString, Void.TYPE,
1417                         EMPTY_CLASS_ARRAY), attributeNameValueExpression);
1418 
1419         //Store the method expression to the topLevelComponent to allow reference it through EL
1420         if (!ccAttrMeRedirection)
1421         {
1422             //Replace it with a method expression
1423             topLevelComponent.getAttributes().put(attributeName,
1424                     new MethodExpressionMethodExpression(methodExpression, methodExpression2));
1425         }
1426         // Otherwise keep the current ValueExpression, because it will be used chain other value expressions
1427     }
1428     
1429     private void applyActionMethodExpressionTarget(FacesContext context, FaceletCompositionContext mctx,
1430                                                    ELContext elContext, 
1431                                                    UIComponent topLevelComponent,
1432                                                    UIComponent innerComponent,
1433                                                    String attributeName,
1434                                                    String targetAttributeName,
1435                                                    String attributeExpressionString,
1436                                                    ValueExpression attributeNameValueExpression,
1437                                                    boolean ccAttrMeRedirection)
1438     {
1439         // target is ActionSource2
1440         MethodExpression methodExpression
1441                 = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1442                 createMethodExpression(elContext,
1443                         attributeExpressionString, null, EMPTY_CLASS_ARRAY),
1444                         attributeNameValueExpression);
1445 
1446         // If it is a redirection, a wrapper is used to
1447         // locate the right instance and call it properly.
1448         if (ccAttrMeRedirection)
1449         {
1450             ((ActionSource2) innerComponent).setActionExpression(
1451                     new ValueExpressionMethodExpression(attributeNameValueExpression));
1452         }
1453         else
1454         {
1455             ((ActionSource2) innerComponent).setActionExpression(methodExpression);
1456         }
1457     }
1458 
1459     private void applyActionListenerMethodExpressionTarget(FacesContext context, FaceletCompositionContext mctx,
1460             ELContext elContext, 
1461             UIComponent topLevelComponent,
1462             UIComponent innerComponent,
1463             String attributeName,
1464             String targetAttributeName,
1465             String attributeExpressionString,
1466             ValueExpression attributeNameValueExpression,
1467             boolean ccAttrMeRedirection)
1468     {
1469         //First try to remove any prevous target if any
1470         ActionListener o = (ActionListener)
1471                 mctx.removeMethodExpressionTargeted(innerComponent, targetAttributeName);
1472         if (o != null)
1473         {
1474             ((ActionSource2) innerComponent).removeActionListener(o);
1475         }
1476 
1477         // target is ActionSource2
1478         ActionListener actionListener = null;
1479         // If it is a redirection, a wrapper is used to locate the right instance and call
1480         //it properly.
1481         if (ccAttrMeRedirection)
1482         {
1483             actionListener = new RedirectMethodExpressionValueExpressionActionListener(
1484                                          attributeNameValueExpression);
1485         }
1486         else
1487         {
1488             MethodExpression methodExpression = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1489                     createMethodExpression(elContext,
1490                        attributeExpressionString, Void.TYPE, ACTION_LISTENER_SIGNATURE), attributeNameValueExpression);
1491 
1492             MethodExpression methodExpression2 = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1493                     createMethodExpression(elContext,
1494                             attributeExpressionString, Void.TYPE, EMPTY_CLASS_ARRAY), attributeNameValueExpression);
1495 
1496             if (mctx.isUsingPSSOnThisView())
1497             {
1498                 actionListener = new PartialMethodExpressionActionListener(methodExpression, methodExpression2);
1499             }
1500             else
1501             {
1502                 actionListener = new MethodExpressionActionListener(methodExpression, methodExpression2);
1503             }
1504         }
1505         ((ActionSource2) innerComponent).addActionListener(actionListener);
1506         mctx.addMethodExpressionTargeted(innerComponent, targetAttributeName, actionListener);
1507     }
1508     
1509     private void applyValidatorMethodExpressionTarget(FacesContext context, FaceletCompositionContext mctx,
1510             ELContext elContext, 
1511             UIComponent topLevelComponent,
1512             UIComponent innerComponent,
1513             String attributeName,
1514             String targetAttributeName,
1515             String attributeExpressionString,
1516             ValueExpression attributeNameValueExpression,
1517             boolean ccAttrMeRedirection)
1518     {
1519         //First try to remove any prevous target if any
1520         Validator o = (Validator) mctx.removeMethodExpressionTargeted(innerComponent, targetAttributeName);
1521         if (o != null)
1522         {
1523             ((EditableValueHolder) innerComponent).removeValidator(o);
1524         }
1525 
1526         // target is EditableValueHolder
1527         Validator validator = null;
1528         // If it is a redirection, a wrapper is used to locate the right instance and call it properly.
1529         if (ccAttrMeRedirection)
1530         {
1531             validator = new RedirectMethodExpressionValueExpressionValidator(attributeNameValueExpression);
1532         }
1533         else
1534         {
1535             MethodExpression methodExpression = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1536                     createMethodExpression(elContext,
1537                             attributeExpressionString, Void.TYPE,
1538                             VALIDATOR_SIGNATURE), attributeNameValueExpression);
1539 
1540             if (mctx.isUsingPSSOnThisView())
1541             {
1542                 validator = new PartialMethodExpressionValidator(methodExpression);
1543             }
1544             else
1545             {
1546                 validator = new MethodExpressionValidator(methodExpression);
1547             }
1548         }
1549         ((EditableValueHolder) innerComponent).addValidator(validator);
1550         mctx.addMethodExpressionTargeted(innerComponent, targetAttributeName, validator);
1551     }
1552     
1553     private void applyValueChangeListenerMethodExpressionTarget(FacesContext context, FaceletCompositionContext mctx,
1554             ELContext elContext, 
1555             UIComponent topLevelComponent,
1556             UIComponent innerComponent,
1557             String attributeName,
1558             String targetAttributeName,
1559             String attributeExpressionString,
1560             ValueExpression attributeNameValueExpression,
1561             boolean ccAttrMeRedirection)
1562     {
1563         ValueChangeListener o = (ValueChangeListener) mctx.removeMethodExpressionTargeted(
1564                 innerComponent, targetAttributeName);
1565         if (o != null)
1566         {
1567             ((EditableValueHolder) innerComponent).removeValueChangeListener(o);
1568         }
1569 
1570         // target is EditableValueHolder
1571         ValueChangeListener valueChangeListener = null;
1572         // If it is a redirection, a wrapper is used to locate the right instance and call it properly.
1573         if (ccAttrMeRedirection)
1574         {
1575             valueChangeListener = new RedirectMethodExpressionValueExpressionValueChangeListener(
1576                     attributeNameValueExpression);
1577         }
1578         else
1579         {
1580             MethodExpression methodExpression = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1581                     createMethodExpression(elContext,
1582                             attributeExpressionString, Void.TYPE,
1583                             VALUE_CHANGE_LISTENER_SIGNATURE), attributeNameValueExpression);
1584 
1585             MethodExpression methodExpression2 = reWrapMethodExpression(context.getApplication().getExpressionFactory().
1586                     createMethodExpression(elContext,
1587                             attributeExpressionString, Void.TYPE,
1588                             EMPTY_CLASS_ARRAY), attributeNameValueExpression);
1589 
1590             if (mctx.isUsingPSSOnThisView())
1591             {
1592                 valueChangeListener = new PartialMethodExpressionValueChangeListener(
1593                         methodExpression, methodExpression2);
1594             }
1595             else
1596             {
1597                 valueChangeListener = new MethodExpressionValueChangeListener(methodExpression, methodExpression2);
1598             }
1599         }
1600         ((EditableValueHolder) innerComponent).addValueChangeListener(valueChangeListener);
1601         mctx.addMethodExpressionTargeted(innerComponent, targetAttributeName, valueChangeListener);
1602     }
1603     
1604     private void applyMethodExpression(FacesContext context, FaceletCompositionContext mctx, 
1605             UIComponent topLevelComponent,
1606             String attributeName,
1607             String targetAttributeName,
1608             ValueExpression attributeNameValueExpression,
1609             MethodExpression methodExpression,
1610             boolean ccAttrMeRedirection,
1611             String[] targetsArray)
1612     {
1613         UIComponent topLevelComponentBase = topLevelComponent.getFacet(
1614                 UIComponent.COMPOSITE_FACET_NAME);
1615 
1616         for (String target : targetsArray)
1617         {
1618             UIComponent innerComponent = ComponentSupport.findComponentChildOrFacetFrom(context, 
1619                     topLevelComponentBase, target);
1620 
1621             if (innerComponent == null)
1622             {
1623                 continue;
1624             }
1625 
1626             // If a component is found, that means the expression should be retarget to the
1627             // components related
1628             if (isCompositeComponentRetarget(context, innerComponent, targetAttributeName))
1629             {
1630                 innerComponent.getAttributes().put(targetAttributeName, attributeNameValueExpression);
1631 
1632                 mctx.clearMethodExpressionAttribute(innerComponent, targetAttributeName);
1633 
1634                 retargetMethodExpressions(context, innerComponent);
1635                 
1636                 if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
1637                 {
1638                     //retargetMethodExpression occur on build view time, so it is safe to call markInitiaState here
1639                     innerComponent.markInitialState();
1640                 }
1641             }
1642             else
1643             {
1644                 //Put the retarget
1645                 if (ccAttrMeRedirection)
1646                 {
1647                     // Since we require here a method expression, it is necessary to wrap 
1648                     // the ValueExpression into a MethodExpression that handles redirection.
1649                     innerComponent.getAttributes().put(targetAttributeName, 
1650                             new ValueExpressionMethodExpression(attributeNameValueExpression));
1651                 }
1652                 else
1653                 {
1654                     innerComponent.getAttributes().put(targetAttributeName, methodExpression);
1655                 }
1656                 if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
1657                 {
1658                     innerComponent.markInitialState();
1659                 }
1660             }
1661         }
1662         //Store the method expression to the topLevelComponent to allow reference it through EL
1663         if (!ccAttrMeRedirection)
1664         {
1665             //Replace it with a method expression
1666             topLevelComponent.getAttributes().put(attributeName, methodExpression);
1667         }
1668         // Othewise keep the current ValueExpression, because it will be used chain other value 
1669         // expressions
1670     }
1671 
1672 
1673     private boolean isCompositeComponentRetarget(FacesContext context, UIComponent component, String attributeName)
1674     {
1675         if (UIComponent.isCompositeComponent(component))
1676         {
1677             BeanInfo compositeComponentMetadata = (BeanInfo) component.getAttributes().get(UIComponent.BEANINFO_KEY);
1678 
1679             PropertyDescriptor[] propertyDescriptors = compositeComponentMetadata.getPropertyDescriptors();
1680 
1681             ELContext elContext = (ELContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
1682 
1683             for (PropertyDescriptor propertyDescriptor : propertyDescriptors)
1684             {
1685                 if (propertyDescriptor.getValue("type") != null)
1686                 {
1687                     // This check is necessary if we have both "type" and "method-signature" set.
1688                     // In that case, "method-signature" is ignored
1689                     continue;
1690                 }
1691 
1692                 if (attributeName.equals(propertyDescriptor.getName()))
1693                 {
1694                     //boolean isKnownMethod = "action".equals(attributeName) || "actionListener".equals(attributeName)  
1695                     //|| "validator".equals(attributeName) || "valueChangeListener".equals(attributeName);
1696 
1697                     // <composite:attribute> method-signature attribute is 
1698                     // ValueExpression that must evaluate to String
1699                     ValueExpression methodSignatureExpression
1700                             = (ValueExpression) propertyDescriptor.getValue("method-signature");
1701                     String methodSignature = null;
1702                     if (methodSignatureExpression != null)
1703                     {
1704                         // Check if the value expression holds a method signature
1705                         // Note that it could be null, so in that case we don't have to do anything
1706                         methodSignature = (String) methodSignatureExpression.getValue(elContext);
1707                     }
1708 
1709                     String targetAttributeName = null;
1710                     ValueExpression targetAttributeNameVE = (ValueExpression) 
1711                         propertyDescriptor.getValue("targetAttributeName");
1712                     if (targetAttributeNameVE != null)
1713                     {
1714                         targetAttributeName = (String) targetAttributeNameVE.getValue(context.getELContext());
1715                         if (targetAttributeName == null)
1716                         {
1717                             targetAttributeName = attributeName;
1718                         }
1719                     }
1720                     else
1721                     {
1722                         targetAttributeName = attributeName;
1723                     }
1724 
1725                     boolean isKnownTargetAttributeMethod = "action".equals(targetAttributeName)
1726                             || "actionListener".equals(targetAttributeName)
1727                             || "validator".equals(targetAttributeName)
1728                             || "valueChangeListener".equals(targetAttributeName);
1729 
1730                     // either the attributeName has to be a knownMethod or there has to be a method-signature
1731                     if (isKnownTargetAttributeMethod || methodSignature != null)
1732                     {
1733                         if ("action".equals(targetAttributeName))
1734                         {
1735                             return !(component instanceof ActionSource2);
1736                         }
1737                         else if ("actionListener".equals(targetAttributeName))
1738                         {
1739                             return !(component instanceof ActionSource2);
1740                         }
1741                         else if ("validator".equals(targetAttributeName))
1742                         {
1743                             return !(component instanceof EditableValueHolder);
1744                         }
1745                         else if ("valueChangeListener".equals(targetAttributeName))
1746                         {
1747                             return !(component instanceof EditableValueHolder);
1748                         }
1749                         else
1750                         {
1751                             return true;
1752                         }
1753                     }
1754                 }
1755             }
1756             return false;
1757         }
1758         else
1759         {
1760             return false;
1761         }
1762     }
1763 
1764     @SuppressWarnings("unchecked")
1765     private MethodExpression reWrapMethodExpression(MethodExpression createdMethodExpression,
1766                                                     ValueExpression originalValueExpression)
1767     {
1768         if (originalValueExpression instanceof LocationValueExpression)
1769         {
1770             return new LocationMethodExpression(
1771                     ((LocationValueExpression) originalValueExpression).getLocation(),
1772                     reWrapMethodExpression(createdMethodExpression,
1773                             ((LocationValueExpression) originalValueExpression).getWrapped()),
1774                     ((LocationValueExpression) originalValueExpression).getCCLevel());
1775         }
1776         else if (originalValueExpression instanceof FacesWrapper &&
1777                 ((FacesWrapper) originalValueExpression).getWrapped() instanceof ValueExpression)
1778         {
1779             return reWrapMethodExpression(createdMethodExpression,
1780                     (ValueExpression) ((FacesWrapper) originalValueExpression).getWrapped());
1781         }
1782         else
1783         {
1784             return createdMethodExpression;
1785         }
1786     }
1787 
1788     /**
1789      * {@inheritDoc}
1790      */
1791     @Override
1792     public Resource getScriptComponentResource(FacesContext context, Resource componentResource)
1793     {
1794         checkNull(context, "context");
1795         checkNull(componentResource, "componentResource");
1796         // TODO Auto-generated method stub
1797         return null;
1798     }
1799 
1800     /**
1801      * {@inheritDoc}
1802      */
1803     @Override
1804     public StateManagementStrategy getStateManagementStrategy(FacesContext context, String viewId)
1805     {
1806         // Use partial state saving strategy only if javax.faces.PARTIAL_STATE_SAVING is "true" and
1807         // the current view is not on javax.faces.FULL_STATE_SAVING_VIEW_IDS.
1808         if (_partialStateSaving && _stateMgmtStrategy == null)
1809         {
1810             _stateMgmtStrategy = new DefaultFaceletsStateManagementStrategy(context);
1811         }
1812 
1813         return _usePartialStateSavingOnThisView(viewId) ? _stateMgmtStrategy : null;
1814     }
1815 
1816     /**
1817      * {@inheritDoc}
1818      */
1819     @Override
1820     public ViewMetadata getViewMetadata(FacesContext context, String viewId)
1821     {
1822         checkNull(context, "facesContext");
1823         checkNull(viewId, "viewId");
1824         return new FaceletViewMetadata(viewId);
1825     }
1826 
1827     /**
1828      * {@inheritDoc}
1829      */
1830     @Override
1831     public void renderView(FacesContext context, UIViewRoot view) throws IOException
1832     {
1833         if (!view.isRendered())
1834         {
1835             return;
1836         }
1837 
1838         // log request
1839         if (log.isLoggable(Level.FINE))
1840         {
1841             log.fine("Rendering View: " + view.getViewId());
1842         }
1843 
1844         try
1845         {
1846             // build view - but not if we're in "buildBeforeRestore"
1847             // land and we've already got a populated view. Note
1848             // that this optimizations breaks if there's a "c:if" in
1849             // the page that toggles as a result of request processing -
1850             // should that be handled? Or
1851             // is this optimization simply so minor that it should just
1852             // be trimmed altogether?
1853             // See JSF 2.0 spec section 2.2.6, buildView is called before
1854             // Render Response
1855             //if (!isFilledView(context, view))
1856             //{
1857             //    buildView(context, view);
1858             //}
1859 
1860             // setup writer and assign it to the context
1861             ResponseWriter origWriter = createResponseWriter(context);
1862 
1863             ExternalContext extContext = context.getExternalContext();
1864             Writer outputWriter = extContext.getResponseOutputWriter();
1865 
1866             StateWriter stateWriter = new StateWriter(outputWriter, 1024, context);
1867             try
1868             {
1869                 ResponseWriter writer = origWriter.cloneWithWriter(stateWriter);
1870                 try
1871                 {
1872                     context.setResponseWriter(writer);
1873 
1874                     StateManager stateMgr = context.getApplication().getStateManager();
1875                     // force creation of session if saving state there
1876                     // -= Leonardo Uribe =- Do this does not have any sense!. The only reference
1877                     // about these lines are on http://java.net/projects/facelets/sources/svn/revision/376
1878                     // and it says: "fixed lazy session instantiation with eager response commit"
1879                     // This code is obviously to prevent this exception:
1880                     // java.lang.IllegalStateException: Cannot create a session after the response has been committed
1881                     // But in theory if that so, StateManager.saveState must happen before writer.close() is called,
1882                     // which can be done very easily.
1883                     //if (!stateMgr.isSavingStateInClient(context))
1884                     //{
1885                     //    extContext.getSession(true);
1886                     //}
1887 
1888                     // render the view to the response
1889                     writer.startDocument();
1890 
1891                     view.encodeAll(context);
1892 
1893                     writer.endDocument();
1894 
1895                     // finish writing
1896                     // -= Leonardo Uribe =- This does not has sense too, because that's the reason
1897                     // of the try/finally block. In practice, it only forces the close of the tag 
1898                     // in HtmlResponseWriter if necessary, but according to the spec, this should
1899                     // be done using writer.flush() instead.
1900                     // writer.close();
1901 
1902                     // flush to origWriter
1903                     if (stateWriter.isStateWritten())
1904                     {
1905                         // Call this method to force close the tag if necessary.
1906                         // The spec javadoc says this: 
1907                         // "... Flush any ouput buffered by the output method to the underlying 
1908                         // Writer or OutputStream. This method will not flush the underlying 
1909                         // Writer or OutputStream; it simply clears any values buffered by this 
1910                         // ResponseWriter. ..."
1911                         writer.flush();
1912 
1913                         // =-= markoc: STATE_KEY is in output ONLY if 
1914                         // stateManager.isSavingStateInClient(context)is true - see
1915                         // org.apache.myfaces.application.ViewHandlerImpl.writeState(FacesContext)
1916                         // TODO this class and ViewHandlerImpl contain same constant <!--@@JSF_FORM_STATE_MARKER@@-->
1917                         Object stateObj = stateMgr.saveView(context);
1918                         String content = stateWriter.getAndResetBuffer();
1919                         int end = content.indexOf(STATE_KEY);
1920                         // See if we can find any trace of the saved state.
1921                         // If so, we need to perform token replacement
1922                         if (end >= 0)
1923                         {
1924                             // save state
1925                             String stateStr;
1926                             if (view.isTransient())
1927                             {
1928                                 // Force state saving
1929                                 stateMgr.writeState(context, stateObj);
1930                                 stateStr = stateWriter.getAndResetBuffer();
1931                             }
1932                             else if (stateObj == null)
1933                             {
1934                                 stateStr = null;
1935                             }
1936                             else
1937                             {
1938                                 stateMgr.writeState(context, stateObj);
1939                                 stateStr = stateWriter.getAndResetBuffer();
1940                             }
1941 
1942                             int start = 0;
1943 
1944                             while (end != -1)
1945                             {
1946                                 origWriter.write(content, start, end - start);
1947                                 if (stateStr != null)
1948                                 {
1949                                     origWriter.write(stateStr);
1950                                 }
1951                                 start = end + STATE_KEY_LEN;
1952                                 end = content.indexOf(STATE_KEY, start);
1953                             }
1954 
1955                             origWriter.write(content, start, content.length() - start);
1956                             // No trace of any saved state, so we just need to flush
1957                             // the buffer
1958                         }
1959                         else
1960                         {
1961                             origWriter.write(content);
1962                         }
1963                     }
1964                     else if (stateWriter.isStateWrittenWithoutWrapper())
1965                     {
1966                         // The state token has been written but the state has not been
1967                         // saved yet.
1968                         stateMgr.saveView(context);
1969                     }
1970                     else
1971                     {
1972                         // GET case without any form that trigger state saving.
1973                         // Try to store it into cache.
1974                         if (_viewPoolProcessor != null && 
1975                             _viewPoolProcessor.isViewPoolEnabledForThisView(context, view))
1976                         {
1977                             ViewDeclarationLanguage vdl = context.getApplication().
1978                                     getViewHandler().getViewDeclarationLanguage(
1979                                         context, view.getViewId());
1980 
1981                             if (ViewDeclarationLanguage.FACELETS_VIEW_DECLARATION_LANGUAGE_ID.equals(
1982                                     vdl.getId()))
1983                             {
1984                                 StateManagementStrategy sms = vdl.getStateManagementStrategy(
1985                                         context, view.getId());
1986                                 if (sms != null)
1987                                 {
1988                                     context.getAttributes().put(ViewPoolProcessor.FORCE_HARD_RESET, Boolean.TRUE);
1989 
1990                                     // Force indirectly to store the map in the cache
1991                                     try
1992                                     {
1993                                         Object state = sms.saveView(context);
1994                                     }
1995                                     finally
1996                                     {
1997                                         context.getAttributes().remove(ViewPoolProcessor.FORCE_HARD_RESET);
1998                                     }
1999 
2000                                     // Clear the calculated value from the application map
2001                                     context.getAttributes().remove(SERIALIZED_VIEW_REQUEST_ATTR);
2002                                 }
2003                             }
2004                         }
2005                     }
2006                 }
2007                 finally
2008                 {
2009                     // The Facelets implementation must close the writer used to write the response
2010                     writer.close();
2011                 }
2012             }
2013             finally
2014             {
2015                 stateWriter.release(context);
2016             }
2017         }
2018         catch (FileNotFoundException fnfe)
2019         {
2020             handleFaceletNotFound(context, view.getViewId());
2021         }
2022         catch (Exception e)
2023         {
2024             handleRenderException(context, e);
2025         }
2026     }
2027     
2028     private static final String SERIALIZED_VIEW_REQUEST_ATTR = 
2029         StateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
2030 
2031     /**
2032      * {@inheritDoc}
2033      */
2034     @Override
2035     public UIViewRoot createView(FacesContext context, String viewId)
2036     {
2037         checkNull(viewId, "viewId");
2038         // we have to check for a possible debug request
2039         if (UIDebug.debugRequest(context))
2040         {
2041             // the current request is a debug request, so we don't need
2042             // to create a view, since the output has already been written
2043             // in UIDebug.debugRequest() and facesContext.responseComplete()
2044             // has been called.
2045             return null;
2046         }
2047         else
2048         {
2049             UIViewRoot root = super.createView(context, viewId);
2050             if (root != null)
2051             {
2052                 //Ensure calculateResourceLibraryContracts() can be decorated
2053                 ViewDeclarationLanguage vdl = context.getApplication().getViewHandler().
2054                     getViewDeclarationLanguage(context, viewId);
2055                 List<String> contracts = vdl.calculateResourceLibraryContracts(
2056                     context, root.getViewId() != null ? root.getViewId() : viewId);
2057                 context.setResourceLibraryContracts(contracts);
2058             }
2059             return root;
2060         }
2061     }
2062 
2063     /**
2064      * {@inheritDoc}
2065      */
2066     @Override
2067     public UIViewRoot restoreView(FacesContext context, String viewId)
2068     {
2069         checkNull(viewId, "viewId");
2070         // Currently there is no way, in which UIDebug.debugRequest(context)
2071         // can create debug information and return true at this point,
2072         // because this method is only accessed if the current request
2073         // is a postback, which will never be true for a debug page.
2074         // The only point where valid debug output can be produced by now
2075         // is in createView() -= Jakob Korherr =-
2076         //if (UIDebug.debugRequest(context))
2077         //{
2078         //    return new UIViewRoot();
2079         //}
2080 
2081         //else if (!_buildBeforeRestore)
2082         //{
2083         
2084         // When partial state saving is not used, createView() is not called. To ensure
2085         // everything is in place it is necessary to calculate the resource library 
2086         // contracts and set them into facesContext.
2087         ViewDeclarationLanguage vdl = context.getApplication().getViewHandler().
2088             getViewDeclarationLanguage(context, viewId);
2089         List<String> contracts = vdl.calculateResourceLibraryContracts(
2090             context, viewId);
2091         context.setResourceLibraryContracts(contracts);
2092         
2093         // JSF 2.2 stateless views
2094         // We need to check if the incoming view is stateless or not and if that so rebuild it here
2095         // note we cannot do this in DefaultFaceletsStateManagementStrategy because it is only used
2096         // when PSS is enabled, but stateless views can be used without PSS. If the view is stateless,
2097         // there is no need to ask to the StateManager.
2098         Application application = context.getApplication();
2099         ViewHandler applicationViewHandler = application.getViewHandler();
2100         String renderKitId = applicationViewHandler.calculateRenderKitId(context);
2101 
2102         ResponseStateManager manager = getRenderKitFactory().getRenderKit(
2103             context, renderKitId).getResponseStateManager();
2104         
2105         if (manager.isStateless(context, viewId))
2106         {
2107             // Per the spec: build the view.
2108             UIViewRoot view = null;
2109             try
2110             {
2111                 ViewMetadata metadata = vdl.getViewMetadata (context, viewId);
2112                 if (metadata != null)
2113                 {
2114                     view = metadata.createMetadataView(context);
2115                 }
2116                 if (view == null)
2117                 {
2118                     view = context.getApplication().getViewHandler().createView(context, viewId);
2119                 }
2120                 context.setViewRoot (view); 
2121                 boolean oldContextEventState = context.isProcessingEvents();
2122                 try 
2123                 {
2124                     context.setProcessingEvents (true);
2125                     vdl.buildView (context, view);
2126                     // If the view is not transient, then something is wrong. Throw an exception.
2127                     if (!view.isTransient())
2128                     {
2129                         throw new FacesException ("unable to create view \"" + viewId + "\"");
2130                     } 
2131                 }
2132                 finally
2133                 {
2134                     context.setProcessingEvents (oldContextEventState);
2135                 } 
2136             }
2137             catch (Throwable e)
2138             {
2139                 throw new FacesException ("unable to create view \"" + viewId + "\"", e);
2140             }
2141             return view;
2142         }
2143         else
2144         {
2145             return super.restoreView(context, viewId);
2146         }
2147     }
2148 
2149     /**
2150      * {@inheritDoc}
2151      */
2152     @Override
2153     protected String calculateViewId(FacesContext context, String viewId)
2154     {
2155         if (_cachedViewHandlerSupport == null)
2156         {
2157             _cachedViewHandlerSupport = new DefaultViewHandlerSupport();
2158         }
2159 
2160         return _cachedViewHandlerSupport.calculateViewId(context, viewId);
2161     }
2162 
2163     /**
2164      * Creates the Facelet page compiler.
2165      *
2166      * @param context
2167      *            the current FacesContext
2168      *
2169      * @return the application's Facelet page compiler
2170      */
2171     protected Compiler createCompiler(FacesContext context)
2172     {
2173         Compiler compiler = new SAXCompiler();
2174 
2175         compiler.setDevelopmentProjectStage(context.isProjectStage(ProjectStage.Development));
2176 
2177         loadLibraries(context, compiler);
2178         loadDecorators(context, compiler);
2179         loadOptions(context, compiler);
2180 
2181         return compiler;
2182     }
2183 
2184     /**
2185      * Creates a FaceletFactory instance using the specified compiler.
2186      *
2187      * @param context
2188      *            the current FacesContext
2189      * @param compiler
2190      *            the compiler to be used by the factory
2191      *
2192      * @return the factory used by this VDL to load pages
2193      */
2194     protected FaceletFactory createFaceletFactory(FacesContext context, Compiler compiler)
2195     {
2196         ExternalContext eContext = context.getExternalContext();
2197 
2198         // refresh period
2199         long refreshPeriod;
2200         if (context.isProjectStage(ProjectStage.Production))
2201         {
2202             refreshPeriod = WebConfigParamUtils.getLongInitParameter(eContext, PARAMS_REFRESH_PERIOD,
2203                     DEFAULT_REFRESH_PERIOD_PRODUCTION);
2204         }
2205         else
2206         {
2207             refreshPeriod = WebConfigParamUtils.getLongInitParameter(eContext, PARAMS_REFRESH_PERIOD,
2208                     DEFAULT_REFRESH_PERIOD);
2209         }
2210 
2211         // resource resolver
2212         ResourceResolver resolver = new DefaultResourceResolver();
2213         ArrayList<String> classNames = new ArrayList<String>();
2214         String faceletsResourceResolverClassName = WebConfigParamUtils.getStringInitParameter(eContext,
2215                 PARAMS_RESOURCE_RESOLVER, null);
2216         List<String> resourceResolversFromAnnotations = RuntimeConfig.getCurrentInstance(
2217             context.getExternalContext()).getResourceResolvers();
2218         if (faceletsResourceResolverClassName != null)
2219         {
2220             classNames.add(faceletsResourceResolverClassName);
2221         }
2222         if (!resourceResolversFromAnnotations.isEmpty())
2223         {
2224             classNames.addAll(resourceResolversFromAnnotations);
2225         }
2226         if (!classNames.isEmpty())
2227         {
2228             resolver = ClassUtils.buildApplicationObject(ResourceResolver.class, classNames, resolver);
2229         }
2230 
2231         _resourceResolver = resolver;
2232 
2233         return new DefaultFaceletFactory(compiler, resolver, refreshPeriod);
2234     }
2235 
2236 
2237     protected ResponseWriter createResponseWriter(FacesContext context) throws IOException, FacesException
2238     {
2239         ExternalContext extContext = context.getExternalContext();
2240         RenderKit renderKit = context.getRenderKit();
2241         // Avoid a cryptic NullPointerException when the renderkit ID
2242         // is incorrectly set
2243         if (renderKit == null)
2244         {
2245             String id = context.getViewRoot().getRenderKitId();
2246             throw new IllegalStateException("No render kit was available for id \"" + id + "\"");
2247         }
2248 
2249         // set the buffer for content
2250         if (_bufferSize != -1)
2251         {
2252             extContext.setResponseBufferSize(_bufferSize);
2253         }
2254 
2255         // get our content type
2256         String contentType = (String) context.getAttributes().get("facelets.ContentType");
2257 
2258         // get the encoding
2259         String encoding = (String) context.getAttributes().get("facelets.Encoding");
2260 
2261         // -= Leonardo Uribe =- Add */* to the contentType is a fix done from FaceletViewHandler
2262         // to make old RI versions work, but since this is for JSF 2.0 it is not necessary that code.
2263         ResponseWriter writer = renderKit.createResponseWriter(FaceletsVDLUtils.NullWriter.INSTANCE,
2264             contentType, encoding);
2265 
2266         //ResponseWriter writer;
2267         // append */* to the contentType so createResponseWriter will succeed no matter
2268         // the requested contentType.
2269         //if (contentType != null && !contentType.equals("*/*"))
2270         //{
2271         //    contentType += ",*/*";
2272         //}
2273         // Create a dummy ResponseWriter with a bogus writer,
2274         // so we can figure out what content type the ReponseWriter
2275         // is really going to ask for
2276         //try
2277         //{
2278         //    writer = renderKit.createResponseWriter(NullWriter.Instance, contentType, encoding);
2279         //}
2280         // catch (IllegalArgumentException e)
2281         //{
2282         // Added because of an RI bug prior to 1.2_05-b3. Might as well leave it in case other
2283         // impls have the same problem. https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=613
2284         //log.finest("The impl didn't correctly handled '*/*' in the content type list.  Trying '*/*' directly.");
2285         //writer = renderKit.createResponseWriter(NullWriter.Instance, "*/*", encoding);
2286         //}
2287 
2288         // Override the JSF provided content type if necessary
2289         contentType = getResponseContentType(context, writer.getContentType());
2290         encoding = getResponseEncoding(context, writer.getCharacterEncoding());
2291 
2292         // apply them to the response
2293         extContext.setResponseContentType(contentType + "; charset=" + encoding);
2294 
2295         // removed 2005.8.23 to comply with J2EE 1.3
2296         // response.setCharacterEncoding(encoding);
2297 
2298         // Now, clone with the real writer
2299         writer = writer.cloneWithWriter(extContext.getResponseOutputWriter());
2300 
2301         return writer;
2302     }
2303 
2304     /**
2305      * @deprecated this code is not used anymore
2306      */
2307     @Deprecated
2308     protected String getDefaultSuffix(FacesContext context) throws FacesException
2309     {
2310         if (_defaultSuffix == null)
2311         {
2312             ExternalContext eContext = context.getExternalContext();
2313 
2314             String viewSuffix = eContext.getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
2315 
2316             _defaultSuffix = viewSuffix == null ? ViewHandler.DEFAULT_FACELETS_SUFFIX : viewSuffix;
2317         }
2318 
2319         return _defaultSuffix;
2320     }
2321 
2322     /**
2323      * @deprecated
2324      */
2325     @Deprecated
2326     protected String getRenderedViewId(FacesContext context, String actionId)
2327     {
2328         // The previous code comes from Facelets 1.1.x but now it becomes invalid. In JSF 2.1, it is possible
2329         // to have multiple file extensions, and to make work correctly viewExists(), it is necessary to return
2330         // the viewId without changes
2331         return actionId;
2332     }
2333 
2334     /**
2335      * Generate the content type
2336      *
2337      * @param context
2338      * @param orig
2339      * @return
2340      */
2341     protected String getResponseContentType(FacesContext context, String orig)
2342     {
2343         String contentType = orig;
2344 
2345         // see if we need to override the contentType
2346         Map<Object, Object> m = context.getAttributes();
2347         if (m.containsKey("facelets.ContentType"))
2348         {
2349             contentType = (String) m.get("facelets.ContentType");
2350             if (log.isLoggable(Level.FINEST))
2351             {
2352                 log.finest("Facelet specified alternate contentType '" + contentType + "'");
2353             }
2354         }
2355 
2356         // safety check
2357         if (contentType == null)
2358         {
2359             contentType = "text/html";
2360             log.finest("ResponseWriter created had a null ContentType, defaulting to text/html");
2361         }
2362 
2363         return contentType;
2364     }
2365 
2366     /**
2367      * Generate the encoding
2368      *
2369      * @param context
2370      * @param orig
2371      * @return
2372      */
2373     protected String getResponseEncoding(FacesContext context, String orig)
2374     {
2375         String encoding = orig;
2376 
2377         // see if we need to override the encoding
2378         Map<Object, Object> m = context.getAttributes();
2379 
2380         Object session = context.getExternalContext().getSession(false);
2381 
2382         // 1. check the request attribute
2383         if (m.containsKey(PARAM_ENCODING))
2384         {
2385             encoding = (String) m.get(PARAM_ENCODING);
2386             if (encoding != null && log.isLoggable(Level.FINEST))
2387             {
2388                 log.finest("Facelet specified alternate encoding '" + encoding + "'");
2389             }
2390 
2391             if (session != null)
2392             {
2393                 context.getExternalContext().getSessionMap().put(CHARACTER_ENCODING_KEY, encoding);
2394             }
2395         }
2396 
2397         // 2. get it from request
2398         if (encoding == null)
2399         {
2400             encoding = context.getExternalContext().getRequestCharacterEncoding();
2401         }
2402 
2403         // 3. get it from the session
2404         if (encoding == null)
2405         {
2406             if (session != null)
2407             {
2408                 encoding = (String) context.getExternalContext().getSessionMap().get(CHARACTER_ENCODING_KEY);
2409                 if (encoding != null && log.isLoggable(Level.FINEST))
2410                 {
2411                     log.finest("Session specified alternate encoding '" + encoding + '\'');
2412                 }
2413             }
2414         }
2415 
2416         // 4. default it
2417         if (encoding == null)
2418         {
2419             encoding = DEFAULT_CHARACTER_ENCODING;
2420             if (log.isLoggable(Level.FINEST))
2421             {
2422                 log.finest("ResponseWriter created had a null CharacterEncoding, defaulting to " + encoding);
2423             }
2424         }
2425 
2426         return encoding;
2427     }
2428 
2429     protected void handleFaceletNotFound(FacesContext context, String viewId) throws FacesException, IOException
2430     {
2431         String actualId = context.getApplication().getViewHandler().getActionURL(context, viewId);
2432         context.getExternalContext().responseSendError(HttpServletResponse.SC_NOT_FOUND, actualId);
2433         context.responseComplete();
2434 
2435     }
2436 
2437     protected void handleRenderException(FacesContext context, Exception e)
2438             throws IOException, ELException, FacesException
2439     {
2440         /*
2441         UIViewRoot root = context.getViewRoot();
2442         StringBuffer sb = new StringBuffer(64);
2443         sb.append("Error Rendering View");
2444         if (root != null)
2445         {
2446             sb.append('[');
2447             sb.append(root.getViewId());
2448             sb.append(']');
2449         }
2450         
2451         log.log(Level.SEVERE, sb.toString(), e);
2452         */
2453 
2454         // rethrow the Exception to be handled by the ExceptionHandler
2455         if (e instanceof RuntimeException)
2456         {
2457             throw (RuntimeException) e;
2458         }
2459         else if (e instanceof IOException)
2460         {
2461             throw (IOException) e;
2462         }
2463         else
2464         {
2465             throw new FacesException(e.getMessage(), e);
2466         }
2467     }
2468 
2469     /**
2470      * Initialize the ViewHandler during its first request.
2471      */
2472     protected void initialize(FacesContext context)
2473     {
2474         log.finest("Initializing");
2475 
2476         Compiler compiler = createCompiler(context);
2477 
2478         _faceletFactory = createFaceletFactory(context, compiler);
2479 
2480         ExternalContext eContext = context.getExternalContext();
2481         _initializeBuffer(eContext);
2482         _initializeMode(eContext);
2483         _initializeContractMappings(eContext);
2484         
2485         // Create a component ids cache and store it on application map to
2486         // reduce the overhead associated with create such ids over and over.
2487         MyfacesConfig mfConfig = MyfacesConfig.getCurrentInstance(eContext);
2488         if (mfConfig.getComponentUniqueIdsCacheSize() > 0)
2489         {
2490             String[] componentIdsCached = SectionUniqueIdCounter.generateUniqueIdCache("_", 
2491                     mfConfig.getComponentUniqueIdsCacheSize());
2492             eContext.getApplicationMap().put(
2493                     CACHED_COMPONENT_IDS, componentIdsCached);
2494         }
2495         
2496         _viewPoolProcessor = ViewPoolProcessor.getInstance(context);
2497 
2498         log.finest("Initialization Successful");
2499     }
2500 
2501     /**
2502      * Load the various decorators for Facelets.
2503      *
2504      * @param context
2505      *            the current FacesContext
2506      * @param compiler
2507      *            the page compiler
2508      */
2509     protected void loadDecorators(FacesContext context, Compiler compiler)
2510     {
2511         getFaceletsCompilerSupport().loadDecorators(context, compiler);
2512     }
2513 
2514     protected FaceletsCompilerSupport getFaceletsCompilerSupport()
2515     {
2516         if (_faceletsCompilerSupport == null)
2517         {
2518             _faceletsCompilerSupport = new FaceletsCompilerSupport();
2519         }
2520         return _faceletsCompilerSupport;
2521     }
2522     
2523     public void setFaceletsCompilerSupport(FaceletsCompilerSupport support)
2524     {
2525         _faceletsCompilerSupport = support;
2526     }
2527 
2528     /**
2529      * Load the various tag libraries for Facelets.
2530      *
2531      * @param context
2532      *            the current FacesContext
2533      * @param compiler
2534      *            the page compiler
2535      */
2536     protected void loadLibraries(FacesContext context, Compiler compiler)
2537     {
2538         getFaceletsCompilerSupport().loadLibraries(context, compiler);
2539     }
2540 
2541     /**
2542      * Load the various options for Facelets compiler. Currently only comment skipping is supported.
2543      *
2544      * @param context
2545      *            the current FacesContext
2546      * @param compiler
2547      *            the page compiler
2548      */
2549     protected void loadOptions(FacesContext context, Compiler compiler)
2550     {
2551         getFaceletsCompilerSupport().loadOptions(context, compiler);
2552     }
2553 
2554     /**
2555      * {@inheritDoc}
2556      */
2557     @Override
2558     protected void sendSourceNotFound(FacesContext context, String message)
2559     {
2560         try
2561         {
2562             context.responseComplete();
2563             context.getExternalContext().responseSendError(HttpServletResponse.SC_NOT_FOUND, message);
2564         }
2565         catch (IOException ioe)
2566         {
2567             throw new FacesException(ioe);
2568         }
2569     }
2570 
2571     /**
2572      * Gets the Facelet representing the specified view identifier.
2573      *
2574      * @param viewId
2575      *            the view identifier
2576      *
2577      * @return the Facelet representing the specified view identifier
2578      *
2579      * @throws IOException
2580      *             if a read or parsing error occurs
2581      */
2582     private Facelet _getFacelet(FacesContext context, String viewId) throws IOException
2583     {
2584         // grab our FaceletFactory and create a Facelet
2585         FaceletFactory.setInstance(_faceletFactory);
2586         try
2587         {
2588             return _faceletFactory.getFacelet(context, viewId);
2589         }
2590         finally
2591         {
2592             FaceletFactory.setInstance(null);
2593         }
2594     }
2595 
2596     private Facelet _getViewMetadataFacelet(FacesContext context, String viewId) throws IOException
2597     {
2598         // grab our FaceletFactory and create a Facelet used to create view metadata
2599         FaceletFactory.setInstance(_faceletFactory);
2600         try
2601         {
2602             return _faceletFactory.getViewMetadataFacelet(context, viewId);
2603         }
2604         finally
2605         {
2606             FaceletFactory.setInstance(null);
2607         }
2608     }
2609 
2610     private void _initializeBuffer(ExternalContext context)
2611     {
2612         _bufferSize = WebConfigParamUtils.getIntegerInitParameter(context, PARAMS_BUFFER_SIZE, 1024);
2613     }
2614 
2615     private void _initializeMode(ExternalContext context)
2616     {
2617         String facesVersion = RuntimeConfig.getCurrentInstance(context).getFacesVersion();
2618         boolean partialStateSavingDefault;
2619 
2620         // Per spec section 11.1.3, the default value for the partial state saving feature needs
2621         // to be true if 2.0, false otherwise.
2622 
2623         partialStateSavingDefault = facesVersion == null
2624                 || facesVersion.trim().isEmpty()
2625                 || Float.parseFloat(facesVersion) >= 2;
2626 
2627         // In jsf 2.0 this code evolve as PartialStateSaving feature
2628         //_buildBeforeRestore = _getBooleanParameter(context, PARAM_BUILD_BEFORE_RESTORE, false);
2629         _partialStateSaving = WebConfigParamUtils.getBooleanInitParameter(context,
2630                 StateManager.PARTIAL_STATE_SAVING_PARAM_NAME, partialStateSavingDefault);
2631 
2632         String[] viewIds = StringUtils.splitShortString(WebConfigParamUtils.getStringInitParameter(context,
2633                 StateManager.FULL_STATE_SAVING_VIEW_IDS_PARAM_NAME), ',');
2634 
2635         if (viewIds.length > 0)
2636         {
2637             _viewIds = new HashSet<String>(viewIds.length, 1.0f);
2638             Collections.addAll(_viewIds, viewIds);
2639         }
2640         else
2641         {
2642             _viewIds = null;
2643         }
2644 
2645         if (_partialStateSaving)
2646         {
2647             _refreshTransientBuildOnPSS = MyfacesConfig.getCurrentInstance(context).isRefreshTransientBuildOnPSS();
2648 
2649             _refreshTransientBuildOnPSSAuto
2650                     = MyfacesConfig.getCurrentInstance(context).isRefreshTransientBuildOnPSSAuto();
2651 
2652             _markInitialStateWhenApplyBuildView = WebConfigParamUtils.getBooleanInitParameter(context,
2653                     PARAM_MARK_INITIAL_STATE_WHEN_APPLY_BUILD_VIEW, false);
2654         }
2655     }
2656     
2657     private void _initializeContractMappings(ExternalContext context)
2658     {
2659         RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(context);
2660         List<String> prefixWildcardKeys = new ArrayList<String>();
2661         Map<String, List<String>> contractMappings = new HashMap<String, List<String>>();
2662         
2663         for (Map.Entry<String, List<String>> entry : runtimeConfig.getContractMappings().entrySet())
2664         {
2665             String urlPattern = entry.getKey().trim();
2666             if (urlPattern.endsWith(ASTERISK))
2667             {
2668                 prefixWildcardKeys.add(urlPattern);
2669             }
2670             contractMappings.put(entry.getKey(), new ArrayList<String>(entry.getValue()));
2671         }
2672         
2673         Collections.sort(prefixWildcardKeys, new FaceletsVDLUtils.KeyComparator());
2674         
2675         this._prefixWildcardKeys = prefixWildcardKeys;
2676         this._contractMappings = contractMappings;
2677     }
2678 
2679     private boolean _usePartialStateSavingOnThisView(String viewId)
2680     {
2681         return _partialStateSaving && !(_viewIds != null && _viewIds.contains(viewId));
2682     }
2683 
2684     @Override
2685     public List<String> calculateResourceLibraryContracts(FacesContext context, String viewId)
2686     {
2687         List<String> contracts = this._contractMappings.get(viewId);
2688         if (contracts == null)
2689         {
2690             //Check prefix mapping
2691             for (String prefix : this._prefixWildcardKeys)
2692             {
2693                 if (FaceletsVDLUtils.matchPattern(viewId, prefix))
2694                 {
2695                     contracts =  this._contractMappings.get(prefix);
2696                     break;
2697                 }
2698             }
2699         }
2700         return contracts;
2701     }
2702 
2703     private class FaceletViewMetadata extends ViewMetadataBase
2704     {
2705         /**
2706          * Constructor
2707          *
2708          * Note that this viewId is not the one after calculateViewId() method
2709          */
2710         public FaceletViewMetadata(String viewId)
2711         {
2712             super(viewId);
2713         }
2714 
2715         @Override
2716         public UIViewRoot createMetadataView(FacesContext context)
2717         {
2718             try
2719             {
2720                 context.setProcessingEvents(false);
2721 
2722                 // spec doesn't say that this is necessary, but we blow up later if
2723                 // the viewroot isn't available from the FacesContext.
2724                 // -= Leonardo Uribe =- since it is supposed when we apply view metadata
2725                 // facelet we don't apply components with renderers and we don't call getRenderKit()
2726                 // it is safe to let this one commented
2727                 // context.setViewRoot(view);
2728 
2729                 // -= Leonardo Uribe =- This part is related to section 2.5.5 of jsf 2.0 spec.
2730                 // In theory what we need here is fill UIViewRoot.METADATA_FACET_NAME facet
2731                 // with UIViewParameter instances. Later, ViewHandlerImpl.getBookmarkableURL(),
2732                 // ViewHandlerImpl.getRedirectURL() and UIViewRoot.encodeEnd uses them. 
2733                 // For now, the only way to do this is call buildView(context,view) method, but 
2734                 // this is a waste of resources. We need to find another way to handle facelets view metadata.
2735                 // Call to buildView causes the view is not created on Render Response phase,
2736                 // if buildView is called from here all components pass through current lifecycle and only
2737                 // UIViewParameter instances should be taken into account.
2738                 // It should be an additional call to buildView on Render Response phase.
2739                 // buildView(context, view);
2740 
2741                 context.getAttributes().put(BUILDING_VIEW_METADATA, Boolean.TRUE);
2742 
2743                 // we have to invoke createView() on the application's ViewHandler
2744                 // here instead of invoking it directly in FaceletVDL, because
2745                 // the ViewHandler might be wrapped and wants to do some work
2746                 // in createView() (e.g. in Trinidad - see MYFACES-2641)
2747                 UIViewRoot view = context.getApplication().getViewHandler().createView(context, getViewId());
2748 
2749                 if (view != null)
2750                 {
2751                     // inside createView(context,viewId), calculateViewId() is called and
2752                     // the result is stored inside created UIViewRoot, so we can safely take the derived
2753                     // viewId from there.
2754                     Facelet facelet = null;
2755                     try
2756                     {
2757                         facelet = _getViewMetadataFacelet(context, view.getViewId());
2758                     }
2759                     catch (FileNotFoundException e)
2760                     {
2761                         sendSourceNotFound(context, getViewId());
2762                         return null;
2763                     }
2764 
2765                     facelet.apply(context, view);
2766                 }
2767 
2768                 return view;
2769             }
2770             catch (IOException ioe)
2771             {
2772                 throw new FacesException(ioe);
2773             }
2774             finally
2775             {
2776                 context.getAttributes().remove(BUILDING_VIEW_METADATA);
2777 
2778                 context.setProcessingEvents(true);
2779             }
2780         }
2781     }
2782     
2783     public FaceletFactory getFaceletFactory()
2784     {
2785         return _faceletFactory;
2786     }
2787 
2788     @Override
2789     public UIComponent createComponent(FacesContext context, 
2790         String taglibURI, String tagName, Map<String, Object> attributes)
2791     {
2792         checkNull(context, "context");
2793         UIComponent createdComponent = null;
2794         try
2795         {
2796             Facelet componentFacelet;
2797             FaceletFactory.setInstance(_faceletFactory);
2798             try
2799             {
2800                 componentFacelet
2801                         = _faceletFactory.compileComponentFacelet(taglibURI, tagName, attributes);
2802             }
2803             finally
2804             {
2805                 FaceletFactory.setInstance(null);
2806             }
2807             if (componentFacelet == null)
2808             {
2809                 return null;
2810             }
2811             // Create a temporal component base class where all components will be put, but we are only
2812             // interested in the inner UIComponent and if multiple are created, return this one.
2813             boolean requiresDynamicRefresh = false;
2814             boolean requiresFaceletDynamicRefresh = false;
2815             UIPanel tempParent
2816                     = (UIPanel) context.getApplication().createComponent(
2817                     context, UIPanel.COMPONENT_TYPE, null);
2818             tempParent.setId(context.getViewRoot().createUniqueId(context, null));
2819             String baseKey = tempParent.getId();
2820             baseKey = baseKey.startsWith(UIViewRoot.UNIQUE_ID_PREFIX) ? baseKey.substring(4) : baseKey;
2821 
2822             try
2823             {
2824                 tempParent.pushComponentToEL(context, tempParent);
2825                 ((AbstractFacelet)componentFacelet).applyDynamicComponentHandler(
2826                     context, tempParent, baseKey);
2827             }
2828             finally
2829             {
2830                 tempParent.popComponentFromEL(context);
2831                 // There are two cases:
2832                 // 1. If we are under facelets algorithm control (binding case), the refreshing logic will be done
2833                 // outside this block. We can check that condition easily with FaceletCompositionContext
2834                 // 2. If we are not under facelets algorithm control, check if the dynamic component requires refresh,
2835                 // if that so, mark the view to be refreshed and reset the flag, otherwise continue. This check
2836                 // allows us to decide if we add a third listener to refresh on transient build.
2837                     // Check if the current component requires dynamic refresh and if that so,
2838                 FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(context);
2839                 if (fcc != null)
2840                 {
2841                     requiresFaceletDynamicRefresh = true;
2842                 }
2843                 else if (FaceletViewDeclarationLanguageBase.isDynamicComponentNeedsRefresh(context))
2844                 {
2845                     FaceletViewDeclarationLanguageBase.activateDynamicComponentRefreshTransientBuild(context);
2846                     FaceletViewDeclarationLanguageBase.resetDynamicComponentNeedsRefreshFlag(context);
2847                     requiresDynamicRefresh = true;
2848                 }
2849             }
2850             if (tempParent.getChildCount() > 1)
2851             {
2852                 // Multiple child. The tempParent will be returned. No need to
2853                 // save MARK_CREATED.
2854                 createdComponent = tempParent;
2855                 tempParent.getAttributes().put("oam.vf.DYN_WRAPPER", baseKey);
2856                 tempParent.subscribeToEvent(PostRestoreStateEvent.class, new 
2857                     RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
2858                 if (requiresFaceletDynamicRefresh)
2859                 {
2860                     FaceletViewDeclarationLanguageBase.dynamicComponentNeedsRefresh(context);
2861                 }
2862             }
2863             else if (tempParent.getChildCount() == 1)
2864             {
2865                 createdComponent = tempParent.getChildren().get(0);
2866                 boolean requiresRefresh = false;
2867                 // One child. In that case there are three choices:
2868                 if (UIComponent.isCompositeComponent(createdComponent))
2869                 {
2870                     // 1. Composite component. Needs special handling because
2871                     // facets will be added programatically. The algorithm that
2872                     // process the composite component content should occur
2873                     // after the component is added to the view (PostAddToViewEvent).
2874                     // Requires refresh. To do that, we need to save the MARK_CREATED
2875                     // value and set it only when the full component is refreshed after 
2876                     // restore it.
2877                     createdComponent.getAttributes().put("oam.vf.GEN_MARK_ID",
2878                         createdComponent.getAttributes().get(ComponentSupport.MARK_CREATED));
2879                     createdComponent.getAttributes().put(ComponentSupport.MARK_CREATED, null);
2880                     createdComponent.subscribeToEvent(PostAddToViewEvent.class, new 
2881                         CreateDynamicCompositeComponentListener(taglibURI, tagName, attributes, baseKey));
2882                     requiresRefresh = true;
2883                     if (requiresFaceletDynamicRefresh)
2884                     {
2885                         FaceletViewDeclarationLanguageBase.dynamicComponentNeedsRefresh(context);
2886                     }
2887                 }
2888                 else if (createdComponent.getChildCount() > 0)
2889                 {
2890                     // 2. Single component with children inside.
2891                     // Requires refresh. To do that, we need to save the MARK_CREATED
2892                     // value and set it only when the full component is refreshed after 
2893                     // restore it.
2894                     createdComponent.getAttributes().put("oam.vf.GEN_MARK_ID",
2895                         createdComponent.getAttributes().get(ComponentSupport.MARK_CREATED));
2896                     createdComponent.getAttributes().put(ComponentSupport.MARK_CREATED, null);
2897                     requiresRefresh = true;
2898                     if (requiresFaceletDynamicRefresh)
2899                     {
2900                         FaceletViewDeclarationLanguageBase.dynamicComponentNeedsRefresh(context);
2901                     }
2902                 }
2903                 else if (createdComponent.isTransient())
2904                 {
2905                     // Just transient markup inside. It is necessary to wrap
2906                     // that content into a component. Requires refresh. No need to
2907                     // save MARK_CREATED. No requires dynamic refresh.
2908                     createdComponent = tempParent;
2909                     tempParent.getAttributes().put("oam.vf.DYN_WRAPPER", baseKey);
2910                     requiresRefresh = true;
2911                 }
2912                 else
2913                 {
2914                     // 4. Single component without children: 
2915                     // Remove MARK_CREATED because it does not requires
2916                     // refresh on restore. When it is added to the component
2917                     // tree, it will be saved and restored as if was a programatically
2918                     // added component.
2919                     createdComponent.getAttributes().put(ComponentSupport.MARK_CREATED, null);
2920                 }
2921                 if (requiresRefresh)
2922                 {
2923                     createdComponent.subscribeToEvent(PostRestoreStateEvent.class, new 
2924                         RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
2925                 }
2926                 if (requiresDynamicRefresh)
2927                 {
2928                     createdComponent.subscribeToEvent(DynamicComponentRefreshTransientBuildEvent.class, new 
2929                         RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
2930                     createdComponent.getAttributes().put(
2931                             DynamicComponentRefreshTransientBuildEvent.DYN_COMP_REFRESH_FLAG, Boolean.TRUE);
2932                 }
2933                 if (requiresFaceletDynamicRefresh)
2934                 {
2935                     createdComponent.subscribeToEvent(FaceletDynamicComponentRefreshTransientBuildEvent.class, new 
2936                         RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
2937                 }
2938             }
2939         }
2940         catch (IOException e)
2941         {
2942             throw new FacesException(e);
2943         }
2944         return createdComponent;
2945     }
2946     
2947     protected RenderKitFactory getRenderKitFactory()
2948     {
2949         if (_renderKitFactory == null)
2950         {
2951             _renderKitFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
2952         }
2953         return _renderKitFactory;
2954     }
2955 }