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