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