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.io.IOException;
23  import java.util.Collection;
24  import java.util.logging.Level;
25  import java.util.logging.Logger;
26  
27  import javax.faces.application.ProjectStage;
28  import javax.faces.component.UIComponent;
29  import javax.faces.context.FacesContext;
30  import javax.faces.view.Location;
31  import javax.faces.view.facelets.FaceletContext;
32  import javax.faces.view.facelets.TagAttribute;
33  import javax.faces.view.facelets.TagConfig;
34  import javax.faces.view.facelets.TagHandler;
35  
36  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
37  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
38  import org.apache.myfaces.view.facelets.AbstractFaceletContext;
39  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
40  import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
41  
42  /**
43   * @author Leonardo Uribe (latest modification by $Author$)
44   * @version $Revision$ $Date$
45   */
46  @JSFFaceletTag(name="composite:interface")
47  public class InterfaceHandler extends TagHandler implements InterfaceDescriptorCreator
48  {
49      private static final Logger log = Logger.getLogger(InterfaceHandler.class.getName());
50      
51      public final static String NAME = "interface";
52      
53      /**
54       * String array defining all standard attributes of this tag.
55       * ATTENTION: this array MUST be sorted alphabetically in order to use binary search!!
56       */
57      private static final String[] STANDARD_ATTRIBUTES_SORTED = new String[]
58      {
59          "componentType",
60          "displayName",
61          "expert",
62          "hidden",
63          "name",
64          "preferred",
65          "shortDescription"
66      };
67      
68      /**
69       * 
70       */
71      @JSFFaceletAttribute(name="name",
72              className="javax.el.ValueExpression",
73              deferredValueType="java.lang.String")
74      private final TagAttribute _name;
75      
76      /**
77       * 
78       */
79      @JSFFaceletAttribute(name="componentType",
80              className="javax.el.ValueExpression",
81              deferredValueType="java.lang.String")
82      private final TagAttribute _componentType;
83      
84      /**
85       * Only available if ProjectStage is Development.
86       */
87      @JSFFaceletAttribute(name="displayName",
88              className="javax.el.ValueExpression",
89              deferredValueType="java.lang.String")
90      private final TagAttribute _displayName;
91      
92      /**
93       * Only available if ProjectStage is Development.
94       */
95      @JSFFaceletAttribute(name="preferred",
96              className="javax.el.ValueExpression",
97              deferredValueType="boolean")
98      private final TagAttribute _preferred;
99      
100     /**
101      * Only available if ProjectStage is Development.
102      */
103     @JSFFaceletAttribute(name="expert",
104             className="javax.el.ValueExpression",
105             deferredValueType="boolean")
106     private final TagAttribute _expert;
107     
108     /**
109      * Only available if ProjectStage is Development.
110      */
111     @JSFFaceletAttribute(name="shortDescription",
112             className="javax.el.ValueExpression",
113             deferredValueType="java.lang.String")
114     private final TagAttribute _shortDescription;
115     
116     /**
117      * The "hidden" flag is used to identify features that are intended only 
118      * for tool use, and which should not be exposed to humans.
119      * Only available if ProjectStage is Development.
120      */
121     @JSFFaceletAttribute(name="hidden",
122             className="javax.el.ValueExpression",
123             deferredValueType="boolean")
124     protected final TagAttribute _hidden;
125     
126     /**
127      * Check if the BeanInfo instance created by this handler
128      * can be cacheable or not. 
129      */
130     private boolean _cacheable;
131     
132 
133     private Collection<InterfaceDescriptorCreator> attrHandlerList;
134     
135     public InterfaceHandler(TagConfig config)
136     {
137         super(config);
138         _name = getAttribute("name");
139         _componentType = getAttribute("componentType");
140         _displayName = getAttribute("displayName");
141         _preferred = getAttribute("preferred");
142         _expert = getAttribute("expert");
143         _shortDescription = getAttribute("shortDescription");
144         _hidden = getAttribute("hidden");
145         
146         // Note that only if ProjectStage is Development, The "displayName",
147         // "shortDescription", "expert", "hidden", and "preferred" attributes are exposed
148         final boolean development = FacesContext.getCurrentInstance()
149                 .isProjectStage(ProjectStage.Development);
150         
151         // note that we don't have to check the componentType and any unspecified
152         // attributes here, because these ones are stored as a ValueExpression in the
153         // BeanDescriptor and thus they have no effect on caching
154         if ((_name == null || _name.isLiteral()) 
155                 && (!development || _areDevelopmentAttributesLiteral()))
156         {
157             _cacheable = true;
158             // Check if all InterfaceDescriptorCreator children are cacheable.
159             // If so, we can cache this instance, otherwise not.
160             attrHandlerList = 
161                 TagHandlerUtils.findNextByType( nextHandler, InterfaceDescriptorCreator.class);
162             for (InterfaceDescriptorCreator handler : attrHandlerList)
163             {
164                 if (!handler.isCacheable())
165                 {
166                     _cacheable = false;
167                     break;
168                 }
169             }
170             if (!_cacheable)
171             {
172                 // Disable cache on attributes because this tag is the responsible for reuse
173                 for (InterfaceDescriptorCreator handler : attrHandlerList)
174                 {
175                     handler.setCacheable(false);
176                 }
177             }
178         }
179         else
180         {
181             _cacheable = false;
182         }
183     }
184     
185     /**
186      * True if the "displayName", "shortDescription", "expert", "hidden", and
187      * "preferred" attributes are either null or literal.
188      * @return
189      */
190     private boolean _areDevelopmentAttributesLiteral()
191     {
192         return CompositeTagAttributeUtils.areAttributesLiteral(
193                 _displayName, _shortDescription, _expert, _hidden, _preferred);
194     }
195 
196     public void apply(FaceletContext ctx, UIComponent parent)
197             throws IOException
198     {
199         // Only apply if we are building composite component metadata,
200         // in other words we are calling ViewDeclarationLanguage.getComponentMetadata
201         if ( ((AbstractFaceletContext)ctx).isBuildingCompositeComponentMetadata() )
202         {
203             FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(ctx);
204             UIComponent compositeBaseParent
205                     = fcc.getCompositeComponentFromStack();
206             
207             CompositeComponentBeanInfo beanInfo = 
208                 (CompositeComponentBeanInfo) compositeBaseParent.getAttributes()
209                 .get(UIComponent.BEANINFO_KEY);
210             
211             if (beanInfo == null)
212             {
213                 if (log.isLoggable(Level.SEVERE))
214                 {
215                     log.severe("Cannot find composite bean descriptor UIComponent.BEANINFO_KEY ");
216                 }
217                 return;
218             }            
219             
220             BeanDescriptor descriptor = beanInfo.getBeanDescriptor();
221             // Add values to descriptor according to pld javadoc
222             if (_name != null)
223             {
224                 descriptor.setName(_name.getValue(ctx));
225             }
226             if (_componentType != null)
227             {
228                 // componentType is required by Application.createComponent(FacesContext, Resource)
229                 // to instantiate the base component for this composite component. It should be
230                 // as family javax.faces.NamingContainer .
231                 descriptor.setValue(UIComponent.COMPOSITE_COMPONENT_TYPE_KEY, 
232                         _componentType.getValueExpression(ctx, String.class));
233             }
234             
235             // If ProjectStage is Development, The "displayName", "shortDescription",
236             // "expert", "hidden", and "preferred" attributes are exposed
237             if (ctx.getFacesContext().isProjectStage(ProjectStage.Development))
238             {
239                 CompositeTagAttributeUtils.addDevelopmentAttributes(descriptor, ctx, 
240                         _displayName, _shortDescription, _expert, _hidden, _preferred);
241             }
242             
243             // Any additional attributes are exposed as attributes accessible
244             // from the getValue() and attributeNames() methods on BeanDescriptor
245             CompositeTagAttributeUtils.addUnspecifiedAttributes(descriptor, tag, 
246                     STANDARD_ATTRIBUTES_SORTED, ctx);
247             
248             try
249             {
250                 fcc.startComponentUniqueIdSection("__ccmd_");
251                 
252                 nextHandler.apply(ctx, parent);
253             }
254             finally
255             {
256                 fcc.endComponentUniqueIdSection("__ccmd_");
257             }
258         }
259     }
260     
261     public boolean isCacheable()
262     {
263         return _cacheable;
264     }
265 
266     public void setCacheable(boolean cacheable)
267     {
268         _cacheable = cacheable;
269         for (InterfaceDescriptorCreator handler : attrHandlerList)
270         {
271             handler.setCacheable(cacheable);
272         }
273     }
274     
275     public Location getLocation()
276     {
277         return this.tag.getLocation();
278     }
279 }