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.tag.composite;
20  
21  import java.beans.BeanDescriptor;
22  import java.beans.BeanInfo;
23  import java.io.IOException;
24  import java.util.Collection;
25  
26  import javax.faces.component.UIComponent;
27  import javax.faces.view.facelets.FaceletContext;
28  import javax.faces.view.facelets.FaceletHandler;
29  
30  import org.apache.myfaces.view.facelets.AbstractFaceletContext;
31  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
32  import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
33  import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
34  
35  /**
36   * This handler wraps a composite component definition. 
37   * <p>
38   * This handler is set by facelets compiler through 
39   * CompositeComponentUnit class by the presence of cc:interface 
40   * or cc:implementation tag.
41   * </p> 
42   * <p>
43   * The presence of this class has the following objectives:
44   * </p>
45   * <ul>
46   * <li>Cache the BeanInfo instance for a composite component</li>
47   * <li>Set a Location object to resolve #{cc} correctly</li>
48   * <li>Push the current composite component on FaceletCompositionContext stack</li>
49   * </ul>
50   * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
51   * @version $Revision: 1491838 $ $Date: 2013-06-11 10:29:14 -0500 (Tue, 11 Jun 2013) $
52   */
53  public final class CompositeComponentDefinitionTagHandler implements FaceletHandler
54  {
55      private final FaceletHandler _nextHandler;
56      
57      private boolean _cacheable;
58      
59      /**
60       * Cached instance used by this component. Note here we have a 
61       * "racy single-check".If this field is used, it is supposed 
62       * the object cached by this handler is immutable, and this is
63       * granted if all properties not saved as ValueExpression are
64       * "literal". 
65       **/
66      private BeanInfo _cachedBeanInfo;
67      
68      private InterfaceHandler _interfaceHandler;
69      
70      private ImplementationHandler _implementationHandler;
71      
72      public CompositeComponentDefinitionTagHandler(FaceletHandler next)
73      {
74          this._nextHandler = next;
75          
76          _cacheable = true;
77          
78          _interfaceHandler = TagHandlerUtils.findFirstNextByType(_nextHandler, InterfaceHandler.class);
79          
80          _implementationHandler = TagHandlerUtils.findFirstNextByType(_nextHandler, ImplementationHandler.class);
81          
82          Collection<InterfaceDescriptorCreator> metadataInterfaceHandlerList = 
83              TagHandlerUtils.findNextByType( _nextHandler, InterfaceDescriptorCreator.class);
84          
85          for (InterfaceDescriptorCreator handler : metadataInterfaceHandlerList)
86          {
87              if (!handler.isCacheable())
88              {
89                  _cacheable = false;
90                  break;
91              }
92          }
93          if (!_cacheable)
94          {
95              for (InterfaceDescriptorCreator handler : metadataInterfaceHandlerList)
96              {
97                  handler.setCacheable(false);
98              }
99          }
100     }
101 
102     public void apply(FaceletContext ctx, UIComponent parent)
103             throws IOException
104     {
105         FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
106         AbstractFaceletContext actx = (AbstractFaceletContext)ctx;
107         UIComponent compositeBaseParent = actx.isBuildingCompositeComponentMetadata() ? parent : parent.getParent();
108         
109         // Store the current Location on the parent (the location is needed
110         // to resolve the related composite component via #{cc} properly).
111         if (_interfaceHandler != null)
112         {
113             if (!compositeBaseParent.getAttributes().containsKey(CompositeComponentELUtils.LOCATION_KEY))
114             {
115                 compositeBaseParent.getAttributes()
116                     .put(CompositeComponentELUtils.LOCATION_KEY, this._interfaceHandler.getLocation());
117             }
118         }
119         else if (_implementationHandler != null)
120         {
121             if (!compositeBaseParent.getAttributes().containsKey(CompositeComponentELUtils.LOCATION_KEY))
122             {
123                 compositeBaseParent.getAttributes()
124                     .put(CompositeComponentELUtils.LOCATION_KEY, this._implementationHandler.getLocation());
125             }
126         }
127         
128         // Only apply if we are building composite component metadata,
129         // in other words we are calling ViewDeclarationLanguage.getComponentMetadata
130         if ( actx.isBuildingCompositeComponentMetadata() )
131         {
132             CompositeComponentBeanInfo tempBeanInfo = 
133                 (CompositeComponentBeanInfo) compositeBaseParent.getAttributes()
134                 .get(UIComponent.BEANINFO_KEY);
135             
136             if (tempBeanInfo == null)
137             {
138                 if (_cacheable)
139                 {
140                     if (_cachedBeanInfo == null)
141                     {
142                         tempBeanInfo  = _createCompositeComponentMetadata(ctx, compositeBaseParent);
143                         compositeBaseParent.getAttributes().put(
144                                 UIComponent.BEANINFO_KEY, tempBeanInfo);
145                         
146                         try
147                         {
148                             mctx.pushCompositeComponentToStack(compositeBaseParent);
149                             
150                             // Store the ccLevel key here
151                             if (!compositeBaseParent.getAttributes().containsKey(CompositeComponentELUtils.LEVEL_KEY))
152                             {
153                                 compositeBaseParent.getAttributes()
154                                     .put(CompositeComponentELUtils.LEVEL_KEY, mctx.getCompositeComponentLevel());
155                             }
156 
157                             _nextHandler.apply(ctx, parent);
158                         }
159                         finally
160                         {
161                             mctx.popCompositeComponentToStack();
162                             
163                             _cachedBeanInfo = tempBeanInfo;
164                         }
165                     }
166                     else
167                     {
168                         // Put the cached instance, but in that case it is not necessary to call
169                         // nextHandler
170                         compositeBaseParent.getAttributes().put(
171                                 UIComponent.BEANINFO_KEY, _cachedBeanInfo);
172                     }
173                 }
174                 else
175                 {
176                     tempBeanInfo = _createCompositeComponentMetadata(ctx, compositeBaseParent);
177                     compositeBaseParent.getAttributes().put(
178                             UIComponent.BEANINFO_KEY, tempBeanInfo);
179                     
180                     try
181                     {
182                         mctx.pushCompositeComponentToStack(compositeBaseParent);
183                         
184                         // Store the ccLevel key here
185                         if (!compositeBaseParent.getAttributes().containsKey(CompositeComponentELUtils.LEVEL_KEY))
186                         {
187                             compositeBaseParent.getAttributes()
188                                 .put(CompositeComponentELUtils.LEVEL_KEY, mctx.getCompositeComponentLevel());
189                         }
190                     
191                         _nextHandler.apply(ctx, parent);
192                         
193                     }
194                     finally
195                     {
196                         mctx.popCompositeComponentToStack();
197                     }
198                 }
199             }
200         }
201         else
202         {
203             try
204             {
205                 mctx.pushCompositeComponentToStack(compositeBaseParent);
206 
207                 // Store the ccLevel key here
208                 if (!compositeBaseParent.getAttributes().containsKey(CompositeComponentELUtils.LEVEL_KEY))
209                 {
210                     compositeBaseParent.getAttributes()
211                         .put(CompositeComponentELUtils.LEVEL_KEY, mctx.getCompositeComponentLevel());
212                 }
213             
214                 _nextHandler.apply(ctx, parent);
215             }
216             finally
217             {
218                 mctx.popCompositeComponentToStack();
219             }
220         }
221     }
222     
223     private CompositeComponentBeanInfo _createCompositeComponentMetadata(
224             FaceletContext ctx, UIComponent parent)
225     {
226         BeanDescriptor descriptor = new BeanDescriptor(parent.getClass());
227         CompositeComponentBeanInfo beanInfo = new CompositeComponentBeanInfo(descriptor);
228         return beanInfo;
229     }
230 }