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.impl;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.NoSuchElementException;
30  import java.util.Set;
31  
32  import javax.el.ELException;
33  import javax.el.ValueExpression;
34  import javax.faces.FacesException;
35  import javax.faces.component.UIComponent;
36  import javax.faces.view.facelets.Facelet;
37  import javax.faces.view.facelets.FaceletContext;
38  import javax.faces.view.facelets.FaceletException;
39  
40  import org.apache.myfaces.util.AbstractAttributeMap;
41  import org.apache.myfaces.view.facelets.AbstractFacelet;
42  import org.apache.myfaces.view.facelets.AbstractFaceletContext;
43  import org.apache.myfaces.view.facelets.PageContext;
44  import org.apache.myfaces.view.facelets.TemplateClient;
45  import org.apache.myfaces.view.facelets.TemplateContext;
46  import org.apache.myfaces.view.facelets.TemplateManager;
47  
48  /**
49   * 
50   * @author Leonardo Uribe (latest modification by $Author$)
51   * @version $Revision$ $Date$
52   * @since 2.0.1
53   */
54  public class TemplateContextImpl extends TemplateContext
55  {
56      /**
57       * This is a dummy instance
58       */
59      private static final TemplateClient INITIAL_TEMPLATE_CLIENT = new InitialTemplateClient();
60      
61      /**
62       * This is a dummy instance
63       */
64      private static final PageContext INITIAL_PAGE_CONTEXT = new InitialPageContext();
65      
66      private final List<TemplateManagerImpl> _clients;
67      
68      private TemplateManager _compositeComponentClient;
69      
70      private TemplateManagerImpl _lastClient;
71      
72      private boolean _isCacheELExpressions;
73      
74      private final TemplateClientAttributeMap _templateClientAttributeMap;
75      
76      private final TemplateClientKnownParameterMap _templateClientKnownParameterMap;
77  
78      public TemplateContextImpl()
79      {
80          super();
81          _clients = new ArrayList<TemplateManagerImpl>(4);
82          // Parameters registered using ui:param now are bound to template manager instances, because
83          // it should follow the same rules as template clients registered here. For example, to resolve
84          // params on nested ui:decorate and ui:composition the same rules applies than for ui:define and
85          // ui:insert. The simplest solution is add a template manager with a dummy template client and
86          // page context, so when a new context is added (like in a ui:include), all params registered go 
87          // to this manager. 
88          _clients.add(new TemplateManagerImpl(null, INITIAL_TEMPLATE_CLIENT, true, INITIAL_PAGE_CONTEXT));
89          _lastClient = _clients.get(0); //_clients.getFirst();
90          _isCacheELExpressions = true;
91          _templateClientAttributeMap = new TemplateClientAttributeMap();
92          _templateClientKnownParameterMap = new TemplateClientKnownParameterMap();
93      }
94  
95      @Override
96      public TemplateManager popClient(final AbstractFaceletContext actx)
97      {
98          _lastClient = null;
99          return _clients.remove(0);
100     }
101 
102     @Override
103     public void pushClient(final AbstractFaceletContext actx, final AbstractFacelet owner, final TemplateClient client)
104     {
105         _clients.add(0, new TemplateManagerImpl(owner, client, true, actx.getPageContext()));
106         _lastClient = _clients.get(0);
107     }
108 
109     public TemplateManager popExtendedClient(final AbstractFaceletContext actx)
110     {
111         _lastClient = null;
112         return _clients.remove(_clients.size()-1);
113     }
114     
115     @Override
116     public void extendClient(final AbstractFaceletContext actx, final AbstractFacelet owner,
117                              final TemplateClient client)
118     {
119         _clients.add(new TemplateManagerImpl(owner, client, false, actx.getPageContext()));
120         _lastClient = _clients.get(_clients.size()-1);
121     }
122 
123     @Override
124     public boolean includeDefinition(FaceletContext ctx, Facelet owner, UIComponent parent, String name)
125             throws IOException, FaceletException, FacesException, ELException
126     {
127         boolean found = false;
128         TemplateManager client;
129         for (int i = 0; i < _clients.size() && !found; i++)
130         {
131             client = _clients.get(i);
132             if (client.equals(owner))
133             {
134                 continue;
135             }
136             found = client.apply(ctx, parent, name);
137         }
138         return found;
139     }
140     
141     private final static class TemplateManagerImpl extends TemplateManager implements TemplateClient
142     {
143         private final AbstractFacelet _owner;
144 
145         private final TemplateClient _target;
146 
147         private final boolean _root;
148 
149         private Set<String> _names;
150         
151         private final PageContext _pageContext;
152         
153         private Map<String, ValueExpression> _parameters = null;
154         
155         private Set<String> _knownParameters;
156 
157         public TemplateManagerImpl(AbstractFacelet owner, TemplateClient target,
158                 boolean root, PageContext pageContext)
159         {
160             this._owner = owner;
161             this._target = target;
162             this._root = root;
163             this._pageContext = pageContext;
164         }
165 
166         public boolean apply(FaceletContext ctx, UIComponent parent, String name)
167                 throws IOException, FacesException, FaceletException,
168                 ELException
169         {
170             String testName = (name != null) ? name : "facelets._NULL_DEF_";
171             if (this._owner == null)
172             {
173                 return false;
174             }
175             if (this._names != null && this._names.contains(testName))
176             {
177                 return false;
178             }
179             else
180             {
181                 if (this._names == null)
182                 {
183                     this._names =  new HashSet<String>();
184                 }
185                 this._names.add(testName);
186                 boolean found = false;
187                 AbstractFaceletContext actx = new DefaultFaceletContext(
188                         (DefaultFaceletContext) ctx, this._owner, false);
189                 ctx.getFacesContext().getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, actx);
190                 try
191                 {
192                     actx.pushPageContext(this._pageContext);
193                     found = this._target
194                             .apply(actx,
195                                     parent, name);
196                 }
197                 finally
198                 {
199                     actx.popPageContext();
200                 }
201                 ctx.getFacesContext().getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, ctx);
202                 this._names.remove(testName);
203                 return found;
204             }
205         }
206         
207         public Map<String, ValueExpression> getParametersMap()
208         {
209             if (_parameters == null)
210             {
211                 _parameters = new HashMap<String, ValueExpression>();
212             }
213             return _parameters;
214         }
215         
216         public boolean isParametersMapEmpty()
217         {
218             return _parameters == null ? true : _parameters.isEmpty();
219         }
220 
221         public Set<String> getKnownParameters()
222         {
223             if (_knownParameters == null)
224             {
225                 _knownParameters = new HashSet<String>(4);
226             }
227             return _knownParameters;
228         }
229         
230         public boolean isKnownParametersEmpty()
231         {
232             return _knownParameters == null ? true : _knownParameters.isEmpty();
233         }
234         
235         public boolean equals(Object o)
236         {
237             if (this._owner != null)
238             {
239                 return this._owner == o || this._target == o;
240             }
241             else
242             {
243                 return this._target == o;
244             }
245         }
246 
247         @Override
248         public int hashCode()
249         {
250             int result = _owner != null ? _owner.hashCode() : 0;
251             result = 31 * result + (_target != null ? _target.hashCode() : 0);
252             return result;
253         }
254 
255         public boolean isRoot()
256         {
257             return this._root;
258         }
259     }
260     
261     
262     public TemplateManager getCompositeComponentClient()
263     {
264         return _compositeComponentClient;
265     }
266 
267     public void setCompositeComponentClient(
268             TemplateManager compositeComponentClient)
269     {
270         _compositeComponentClient = compositeComponentClient;
271     }
272 
273     
274     @Override
275     public ValueExpression getParameter(String key)
276     {
277         TemplateManagerImpl client;
278         for (int i = 0; i < _clients.size(); i++)
279         {
280             client = _clients.get(i);
281             if (!client.isParametersMapEmpty() &&
282                  client.getParametersMap().containsKey(key))
283             {
284                 return client.getParametersMap().get(key);
285             }
286         }
287         return null;
288     }
289 
290     @Override
291     public boolean containsParameter(String key)
292     {
293         TemplateManagerImpl client;
294         for (int i = 0; i < _clients.size(); i++)
295         {
296             client = _clients.get(i);
297             if (!client.isParametersMapEmpty() &&
298                 client.getParametersMap().containsKey(key))
299             {
300                 return true;
301             }
302         }
303         return false;
304     }
305 
306     @Override
307     public void setParameter(String key, ValueExpression value)
308     {
309         if (_lastClient != null)
310         {
311             _lastClient.getParametersMap().put(key, value);
312             _lastClient.getKnownParameters().add(key);
313         }
314     }
315 
316     @Override
317     public boolean isParameterEmpty()
318     {
319         TemplateManagerImpl client;
320         for (int i = 0; i < _clients.size(); i++)
321         {
322             client = _clients.get(i);
323             if (!client.isParametersMapEmpty())
324             {
325                 return false;
326             }
327         }
328         return true;
329     }
330     
331     public Map<String, ValueExpression> getParameterMap()
332     {
333         return _templateClientAttributeMap;
334     }
335     
336     public boolean isKnownParametersEmpty()
337     {
338         TemplateManagerImpl client;
339         for (int i = 0; i < _clients.size(); i++)
340         {
341             client = _clients.get(i);
342             if (!client.isKnownParametersEmpty())
343             {
344                 return false;
345             }
346         }
347         return true;
348     }
349     
350     public Set<String> getKnownParameters()
351     {
352         return _templateClientKnownParameterMap.keySet();
353     }
354     
355     @Override
356     public boolean containsKnownParameter(String key)
357     {
358         TemplateManagerImpl client;
359         for (int i = 0; i < _clients.size(); i++)
360         {
361             client = _clients.get(i);
362             if (client.getKnownParameters().contains(key))
363             {
364                 return true;
365             }
366         }
367         return false;
368     }
369     
370     @Override
371     public void addKnownParameters(String key)
372     {
373         if (_lastClient != null)
374         {        
375             _lastClient.getKnownParameters().add(key);
376         }
377     }
378 
379     private final class TemplateClientAttributeMap extends AbstractAttributeMap<ValueExpression>
380     {
381 
382         public TemplateClientAttributeMap()
383         {
384         }
385         
386         @Override
387         protected ValueExpression getAttribute(String key)
388         {
389             TemplateManagerImpl client;
390             for (int i = 0; i < _clients.size(); i++)
391             {
392                 client = _clients.get(i);
393                 if (!client.isParametersMapEmpty() &&
394                      client.getParametersMap().containsKey(key))
395                 {
396                     return client.getParametersMap().get(key);
397                 }
398             }
399             return null;
400         }
401 
402         @Override
403         protected void setAttribute(String key, ValueExpression value)
404         {
405             //Use the parent methods.
406             throw new UnsupportedOperationException();
407         }
408 
409         @Override
410         protected void removeAttribute(String key)
411         {
412             throw new UnsupportedOperationException();
413         }
414 
415         @Override
416         protected Enumeration<String> getAttributeNames()
417         {
418             Set<String> attributeNames = new HashSet<String>();
419             TemplateManagerImpl client;
420             for (int i = 0; i < _clients.size(); i++)
421             {
422                 client = _clients.get(i);
423                 if (!client.isParametersMapEmpty())
424                 {
425                     attributeNames.addAll(client.getParametersMap().keySet());
426                 }
427             }
428             
429             return new ParameterNameEnumeration(attributeNames.toArray(new String[attributeNames.size()]));
430         }
431     }
432     
433     private static class ParameterNameEnumeration implements Enumeration<String>
434     {
435         private final String[] _parameterNames;
436         private final int _length;
437         private int _index;
438 
439         public ParameterNameEnumeration(final String[] parameterNames)
440         {
441             _parameterNames = parameterNames;
442             _length = parameterNames.length;
443         }
444 
445         public boolean hasMoreElements()
446         {
447             return _index < _length;
448         }
449 
450         public String nextElement()
451         {
452             if (!hasMoreElements())
453             {
454                 throw new NoSuchElementException();
455             }
456             return _parameterNames[_index++];
457         }
458     }
459     
460     private final class TemplateClientKnownParameterMap extends AbstractAttributeMap<Boolean>
461     {
462 
463         public TemplateClientKnownParameterMap()
464         {
465         }
466         
467         @Override
468         protected Boolean getAttribute(String key)
469         {
470             TemplateManagerImpl client;
471             for (int i = 0; i < _clients.size(); i++)
472             {
473                 client = _clients.get(i);
474                 if (!client.isKnownParametersEmpty() &&
475                      client.getKnownParameters().contains(key))
476                 {
477                     return Boolean.TRUE;
478                 }
479             }
480             return null;
481         }
482 
483         @Override
484         protected void setAttribute(String key, Boolean value)
485         {
486             throw new UnsupportedOperationException();
487         }
488 
489         @Override
490         protected void removeAttribute(String key)
491         {
492             throw new UnsupportedOperationException();
493         }
494 
495         @Override
496         protected Enumeration<String> getAttributeNames()
497         {
498             Set<String> attributeNames = new HashSet<String>();
499             TemplateManagerImpl client;
500             for (int i = 0; i < _clients.size(); i++)
501             {
502                 client = _clients.get(i);
503                 if (!client.isParametersMapEmpty())
504                 {
505                     attributeNames.addAll(client.getParametersMap().keySet());
506                 }
507             }
508             
509             return new ParameterNameEnumeration(attributeNames.toArray(new String[attributeNames.size()]));
510         }
511     }    
512     
513     /**
514      * This is just a dummy template client that does nothing that is added by default
515      * for each template context 
516      *
517      */
518     public static final class InitialTemplateClient implements TemplateClient
519     {
520         public boolean apply(FaceletContext ctx, UIComponent parent, String name)
521                 throws IOException, FacesException, FaceletException, ELException
522         {
523             return false;
524         }
525     }
526     
527     public static final class InitialPageContext extends PageContext
528     {
529         private boolean _isCacheELExpressions;
530         
531         public InitialPageContext()
532         {
533             _isCacheELExpressions = true;
534         }
535         
536         @Override
537         public Map<String, ValueExpression> getAttributes()
538         {
539             return Collections.emptyMap();
540         }
541 
542         @Override
543         public int getAttributeCount()
544         {
545             return 0;
546         }
547 
548         @Override
549         public boolean isAllowCacheELExpressions()
550         {
551             return _isCacheELExpressions;
552         }
553 
554         @Override
555         public void setAllowCacheELExpressions(boolean cacheELExpressions)
556         {
557             _isCacheELExpressions = cacheELExpressions;
558         }
559     }
560 
561 
562     @Override
563     public boolean isAllowCacheELExpressions()
564     {
565         return _isCacheELExpressions;
566     }
567 
568     @Override
569     public void setAllowCacheELExpressions(boolean cacheELExpressions)
570     {
571         _isCacheELExpressions = cacheELExpressions;
572     }
573     
574 }