Coverage Report - org.apache.myfaces.view.facelets.tag.composite.FacetHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
FacetHandler
0%
0/59
0%
0/30
4.143
 
 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.IntrospectionException;
 23  
 import java.beans.PropertyDescriptor;
 24  
 import java.io.IOException;
 25  
 import java.util.HashMap;
 26  
 import java.util.Map;
 27  
 import java.util.logging.Level;
 28  
 import java.util.logging.Logger;
 29  
 
 30  
 import javax.faces.application.ProjectStage;
 31  
 import javax.faces.component.UIComponent;
 32  
 import javax.faces.context.FacesContext;
 33  
 import javax.faces.view.facelets.FaceletContext;
 34  
 import javax.faces.view.facelets.TagAttribute;
 35  
 import javax.faces.view.facelets.TagConfig;
 36  
 import javax.faces.view.facelets.TagException;
 37  
 import javax.faces.view.facelets.TagHandler;
 38  
 
 39  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
 40  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
 41  
 
 42  
 /**
 43  
  * Define the facets used by this composite component.
 44  
  * <p>
 45  
  * This tag is used inside composite:interface tag. All facets
 46  
  * should be saved under the key UIComponent.FACETS_KEY on the
 47  
  * bean descriptor map as a Map&lt;String, PropertyDescriptor&gt;
 48  
  * </p>
 49  
  * 
 50  
  * @author Leonardo Uribe (latest modification by $Author$)
 51  
  * @version $Revision$ $Date$
 52  
  */
 53  
 @JSFFaceletTag(name="composite:facet")
 54  
 public class FacetHandler extends TagHandler implements InterfaceDescriptorCreator
 55  
 {
 56  
 
 57  
     //private static final Log log = LogFactory.getLog(FacetHandler.class);
 58  0
     private static final Logger log = Logger.getLogger(FacetHandler.class.getName());
 59  
     
 60  
     /**
 61  
      * String array defining all standard attributes of this tag.
 62  
      * ATTENTION: this array MUST be sorted alphabetically in order to use binary search!!
 63  
      */
 64  0
     private static final String[] STANDARD_ATTRIBUTES_SORTED = new String[]
 65  
     {
 66  
         "displayName",
 67  
         "expert",
 68  
         "hidden",
 69  
         "name",
 70  
         "preferred",
 71  
         "required",
 72  
         "shortDescription"
 73  
     };
 74  
 
 75  
     /**
 76  
      * 
 77  
      */
 78  
     @JSFFaceletAttribute(name="name",
 79  
             className="javax.el.ValueExpression",
 80  
             deferredValueType="java.lang.String")
 81  
     private final TagAttribute _name;
 82  
 
 83  
     /**
 84  
      * Only available if ProjectStage is Development.
 85  
      */
 86  
     @JSFFaceletAttribute(name="displayName",
 87  
             className="javax.el.ValueExpression",
 88  
             deferredValueType="java.lang.String")
 89  
     private final TagAttribute _displayName;
 90  
 
 91  
     /**
 92  
      * Indicate if the attribute is required or not
 93  
      * <p>
 94  
      * Myfaces specific feature: this attribute is checked only if project stage is
 95  
      * not ProjectStage.Production when a composite component is created.
 96  
      * </p>
 97  
      */
 98  
     @JSFFaceletAttribute(name="required",
 99  
             className="javax.el.ValueExpression",
 100  
             deferredValueType="boolean")
 101  
     private final TagAttribute _required;
 102  
 
 103  
     /**
 104  
      * Only available if ProjectStage is Development.
 105  
      */
 106  
     @JSFFaceletAttribute(name="preferred",
 107  
             className="javax.el.ValueExpression",
 108  
             deferredValueType="boolean")
 109  
     private final TagAttribute _preferred;
 110  
 
 111  
     /**
 112  
      * Only available if ProjectStage is Development.
 113  
      */
 114  
     @JSFFaceletAttribute(name="expert",
 115  
             className="javax.el.ValueExpression",
 116  
             deferredValueType="boolean")
 117  
     private final TagAttribute _expert;
 118  
 
 119  
     /**
 120  
      * Only available if ProjectStage is Development.
 121  
      */
 122  
     @JSFFaceletAttribute(name="shortDescription",
 123  
             className="javax.el.ValueExpression",
 124  
             deferredValueType="java.lang.String")
 125  
     private final TagAttribute _shortDescription;
 126  
     
 127  
     /**
 128  
      * The "hidden" flag is used to identify features that are intended only 
 129  
      * for tool use, and which should not be exposed to humans.
 130  
      * Only available if ProjectStage is Development.
 131  
      */
 132  
     @JSFFaceletAttribute(name="hidden",
 133  
             className="javax.el.ValueExpression",
 134  
             deferredValueType="boolean")
 135  
     protected final TagAttribute _hidden;
 136  
     
 137  
     /**
 138  
      * Check if the PropertyDescriptor instance created by this handler
 139  
      * can be cacheable or not. 
 140  
      */
 141  
     private boolean _cacheable;
 142  
     
 143  
     /**
 144  
      * Cached instance used by this component. Note here we have a 
 145  
      * "racy single-check". If this field is used, it is supposed 
 146  
      * the object cached by this handler is immutable, and this is
 147  
      * granted if all properties not saved as ValueExpression are
 148  
      * "literal". 
 149  
      */
 150  
     private PropertyDescriptor _propertyDescriptor; 
 151  
     
 152  
     public FacetHandler(TagConfig config)
 153  
     {
 154  0
         super(config);
 155  0
         _name = getRequiredAttribute("name");
 156  0
         _displayName = getAttribute("displayName");
 157  0
         _required = getAttribute("required");
 158  0
         _preferred = getAttribute("preferred");
 159  0
         _expert = getAttribute("expert");
 160  0
         _shortDescription = getAttribute("shortDescription");
 161  0
         _hidden = getAttribute("hidden");
 162  
         
 163  
         // We can reuse the same PropertyDescriptor only if the properties
 164  
         // that requires to be evaluated when apply (build view time)
 165  
         // occur are literal or null. Otherwise we need to create it.
 166  
         // Note that only if ProjectStage is Development, The "displayName",
 167  
         // "shortDescription", "expert", "hidden", and "preferred" attributes are exposed
 168  0
         final boolean development = FacesContext.getCurrentInstance()
 169  
                 .isProjectStage(ProjectStage.Development);
 170  
         
 171  0
         if (_name.isLiteral() 
 172  
                 && (!development || _areDevelopmentAttributesLiteral()))
 173  
         {
 174  
             // Unfortunately its not possible to create the required 
 175  
             // PropertyDescriptor instance here, because there is no way 
 176  
             // to get a FaceletContext to create ValueExpressions. It is
 177  
             // possible to create it if we not have set all this properties:
 178  
             // required and possible unspecified attributes. This prevents 
 179  
             // the racy single-check.
 180  0
             _cacheable = true;
 181  0
             if (_required == null &&
 182  
                     !CompositeTagAttributeUtils.containsUnspecifiedAttributes(tag, 
 183  
                             STANDARD_ATTRIBUTES_SORTED))
 184  
             {
 185  0
                 _propertyDescriptor = _createFacetPropertyDescriptor(development);
 186  
             }
 187  
         }
 188  
         else
 189  
         {
 190  0
             _cacheable = false;
 191  
         }
 192  0
     }
 193  
     
 194  
     /**
 195  
      * True if the "displayName", "shortDescription", "expert", "hidden", and
 196  
      * "preferred" attributes are either null or literal.
 197  
      * @return
 198  
      */
 199  
     private boolean _areDevelopmentAttributesLiteral()
 200  
     {
 201  0
         return CompositeTagAttributeUtils.areAttributesLiteral(
 202  
                 _displayName, _shortDescription, _expert, _hidden, _preferred);
 203  
     }
 204  
 
 205  
     @SuppressWarnings("unchecked")
 206  
     public void apply(FaceletContext ctx, UIComponent parent)
 207  
             throws IOException
 208  
     {
 209  0
         CompositeComponentBeanInfo beanInfo = 
 210  
             (CompositeComponentBeanInfo) parent.getAttributes()
 211  
             .get(UIComponent.BEANINFO_KEY);
 212  
         
 213  0
         if (beanInfo == null)
 214  
         {
 215  0
             if (log.isLoggable(Level.SEVERE))
 216  
             {
 217  0
                 log.severe("Cannot find composite bean descriptor UIComponent.BEANINFO_KEY ");
 218  
             }
 219  0
             return;
 220  
         }
 221  
         
 222  0
         BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
 223  
 
 224  0
         Map<String, PropertyDescriptor> facetPropertyDescriptorMap = (Map<String, PropertyDescriptor>)
 225  
             beanDescriptor.getValue(UIComponent.FACETS_KEY);
 226  
         
 227  0
         if (facetPropertyDescriptorMap == null)
 228  
         {
 229  0
             facetPropertyDescriptorMap = new HashMap<String, PropertyDescriptor>();
 230  0
             beanDescriptor.setValue(UIComponent.FACETS_KEY, facetPropertyDescriptorMap);
 231  
         }
 232  
         
 233  0
         String facetName = _name.getValue(ctx);
 234  
         
 235  0
         if (isCacheable())
 236  
         {
 237  0
             if (_propertyDescriptor == null)
 238  
             {
 239  0
                 _propertyDescriptor = _createFacetPropertyDescriptor(facetName, ctx);
 240  
             }
 241  0
             facetPropertyDescriptorMap.put(facetName, _propertyDescriptor);
 242  
         }
 243  
         else
 244  
         {
 245  0
             PropertyDescriptor facetDescriptor = _createFacetPropertyDescriptor(facetName, ctx);
 246  0
             facetPropertyDescriptorMap.put(facetName, facetDescriptor);
 247  
         }
 248  
                 
 249  0
         nextHandler.apply(ctx, parent);
 250  0
     }
 251  
     
 252  
     /**
 253  
      * This method could be called only if it is not necessary to set the following properties:
 254  
      * targets, default, required, methodSignature and type
 255  
      * 
 256  
      * @return
 257  
      */
 258  
     private PropertyDescriptor _createFacetPropertyDescriptor(boolean development)
 259  
     {
 260  
         try
 261  
         {
 262  0
             CompositeComponentPropertyDescriptor facetPropertyDescriptor = 
 263  
                 new CompositeComponentPropertyDescriptor(_name.getValue());
 264  
             
 265  
             // If ProjectStage is Development, The "displayName", "shortDescription",
 266  
             // "expert", "hidden", and "preferred" attributes are exposed
 267  0
             if (development)
 268  
             {
 269  0
                 CompositeTagAttributeUtils.addDevelopmentAttributesLiteral(facetPropertyDescriptor,
 270  
                         _displayName, _shortDescription, _expert, _hidden, _preferred);
 271  
             }
 272  
             
 273  
             // note that no unspecified attributes are handled here, because the current
 274  
             // tag does not contain any, otherwise this code would not have been called.
 275  
             
 276  0
             return facetPropertyDescriptor;
 277  
         }
 278  0
         catch (IntrospectionException e)
 279  
         {
 280  0
             if (log.isLoggable(Level.SEVERE))
 281  
             {
 282  0
                 log.log(Level.SEVERE, "Cannot create PropertyDescriptor for facet ",e);
 283  
             }
 284  0
             throw new TagException(tag,e);
 285  
         }
 286  
     }
 287  
     
 288  
     private PropertyDescriptor _createFacetPropertyDescriptor(String facetName, FaceletContext ctx)
 289  
         throws TagException, IOException
 290  
     {
 291  
         try
 292  
         {
 293  0
             CompositeComponentPropertyDescriptor facetPropertyDescriptor = 
 294  
                 new CompositeComponentPropertyDescriptor(facetName);
 295  
             
 296  0
             if (_required != null)
 297  
             {
 298  0
                 facetPropertyDescriptor.setValue("required", _required.getValueExpression(ctx, Boolean.class));
 299  
             }
 300  
             
 301  
             // If ProjectStage is Development, The "displayName", "shortDescription",
 302  
             // "expert", "hidden", and "preferred" attributes are exposed
 303  0
             if (ctx.getFacesContext().isProjectStage(ProjectStage.Development))
 304  
             {
 305  0
                 CompositeTagAttributeUtils.addDevelopmentAttributes(facetPropertyDescriptor, ctx, 
 306  
                         _displayName, _shortDescription, _expert, _hidden, _preferred);
 307  
             }
 308  
             
 309  
             // Any additional attributes are exposed as attributes accessible
 310  
             // from the getValue() and attributeNames() methods on FeatureDescriptor
 311  0
             CompositeTagAttributeUtils.addUnspecifiedAttributes(facetPropertyDescriptor, tag, 
 312  
                     STANDARD_ATTRIBUTES_SORTED, ctx);
 313  
             
 314  0
             return facetPropertyDescriptor;
 315  
         }
 316  0
         catch (IntrospectionException e)
 317  
         {
 318  0
             if (log.isLoggable(Level.SEVERE))
 319  
             {
 320  0
                 log.log(Level.SEVERE, "Cannot create PropertyDescriptor for attribute ",e);
 321  
             }
 322  0
             throw new TagException(tag,e);
 323  
         }
 324  
     }
 325  
 
 326  
     public boolean isCacheable()
 327  
     {
 328  0
         return _cacheable;
 329  
     }
 330  
     
 331  
     public void setCacheable(boolean cacheable)
 332  
     {
 333  0
         _cacheable = cacheable;
 334  0
     }
 335  
 
 336  
     //@Override
 337  
     //public FaceletHandler getNextHandler()
 338  
     //{
 339  
     //    return nextHandler;
 340  
     //}
 341  
 }