Coverage Report - org.apache.myfaces.view.facelets.tag.composite.AttributeHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
AttributeHandler
0%
0/80
0%
0/54
6
 
 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.IntrospectionException;
 22  
 import java.beans.PropertyDescriptor;
 23  
 import java.io.IOException;
 24  
 import java.util.List;
 25  
 import java.util.logging.Level;
 26  
 import java.util.logging.Logger;
 27  
 
 28  
 import javax.faces.application.ProjectStage;
 29  
 import javax.faces.component.UIComponent;
 30  
 import javax.faces.context.FacesContext;
 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.TagException;
 35  
 import javax.faces.view.facelets.TagHandler;
 36  
 
 37  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
 38  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
 39  
 import org.apache.myfaces.shared.util.ClassUtils;
 40  
 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
 41  
 
 42  
 /**
 43  
  * @author Leonardo Uribe (latest modification by $Author$)
 44  
  * @version $Revision$ $Date$
 45  
  */
 46  
 @JSFFaceletTag(name="composite:attribute")
 47  
 public class AttributeHandler extends TagHandler implements InterfaceDescriptorCreator
 48  
 {
 49  
     
 50  
     //private static final Log log = LogFactory.getLog(AttributeHandler.class);
 51  0
     private static final Logger log = Logger.getLogger(AttributeHandler.class.getName());
 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  0
     private static final String[] STANDARD_ATTRIBUTES_SORTED = new String[]
 58  
     {
 59  
         "default",
 60  
         "displayName",
 61  
         "expert",
 62  
         "hidden",
 63  
         "method-signature",
 64  
         "name",
 65  
         "preferred",
 66  
         "required",
 67  
         "shortDescription",
 68  
         "targetAttributeName",
 69  
         "targets",
 70  
         "type"
 71  
     };
 72  
 
 73  
     @JSFFaceletAttribute(name="name",
 74  
             className="javax.el.ValueExpression",
 75  
             deferredValueType="java.lang.String",
 76  
             required=true)
 77  
     private final TagAttribute _name;
 78  
     
 79  
     @JSFFaceletAttribute(name="targets",
 80  
             className="javax.el.ValueExpression",
 81  
             deferredValueType="java.lang.String")
 82  
     private final TagAttribute _targets;
 83  
     
 84  
     /**
 85  
      * If this property is set and the attribute does not have any
 86  
      * value (null), the value set on this property is returned as default
 87  
      * instead null.
 88  
      */
 89  
     @JSFFaceletAttribute(name="default",
 90  
             className="javax.el.ValueExpression",
 91  
             deferredValueType="java.lang.String")
 92  
     private final TagAttribute _default;
 93  
     
 94  
     /**
 95  
      * Only available if ProjectStage is Development.
 96  
      */
 97  
     @JSFFaceletAttribute(name="displayName",
 98  
             className="javax.el.ValueExpression",
 99  
             deferredValueType="java.lang.String")
 100  
     private final TagAttribute _displayName;
 101  
 
 102  
     /**
 103  
      * Indicate if the attribute is required or not
 104  
      * <p>
 105  
      * Myfaces specific feature: this attribute is checked only if project stage is
 106  
      * not ProjectStage.Production when a composite component is created.</p>
 107  
      */
 108  
     @JSFFaceletAttribute(name="required",
 109  
             className="javax.el.ValueExpression",
 110  
             deferredValueType="boolean")
 111  
     private final TagAttribute _required;
 112  
 
 113  
     /**
 114  
      * Only available if ProjectStage is Development.
 115  
      */
 116  
     @JSFFaceletAttribute(name="preferred",
 117  
             className="javax.el.ValueExpression",
 118  
             deferredValueType="boolean")
 119  
     private final TagAttribute _preferred;
 120  
 
 121  
     /**
 122  
      * Only available if ProjectStage is Development.
 123  
      */
 124  
     @JSFFaceletAttribute(name="expert",
 125  
             className="javax.el.ValueExpression",
 126  
             deferredValueType="boolean")
 127  
     private final TagAttribute _expert;
 128  
 
 129  
     /**
 130  
      * Only available if ProjectStage is Development.
 131  
      */
 132  
     @JSFFaceletAttribute(name="shortDescription",
 133  
             className="javax.el.ValueExpression",
 134  
             deferredValueType="java.lang.String")
 135  
     private final TagAttribute _shortDescription;
 136  
 
 137  
     @JSFFaceletAttribute(name="method-signature",
 138  
             className="javax.el.ValueExpression",
 139  
             deferredValueType="java.lang.String")
 140  
     private final TagAttribute _methodSignature;
 141  
 
 142  
     @JSFFaceletAttribute(name="type",
 143  
             className="javax.el.ValueExpression",
 144  
             deferredValueType="java.lang.String")
 145  
     private final TagAttribute _type;
 146  
     
 147  
     /**
 148  
      * The "hidden" flag is used to identify features that are intended only 
 149  
      * for tool use, and which should not be exposed to humans.
 150  
      * Only available if ProjectStage is Development.
 151  
      */
 152  
     @JSFFaceletAttribute(name="hidden",
 153  
             className="javax.el.ValueExpression",
 154  
             deferredValueType="boolean")
 155  
     protected final TagAttribute _hidden;
 156  
     
 157  
     @JSFFaceletAttribute(name="targetAttributeName",
 158  
             className="javax.el.ValueExpression",
 159  
             deferredValueType="java.lang.String")
 160  
     private final TagAttribute _targetAttributeName;
 161  
     
 162  
     /**
 163  
      * Check if the PropertyDescriptor instance created by this handler
 164  
      * can be cacheable or not. 
 165  
      */
 166  
     private boolean _cacheable;
 167  
     
 168  
     /**
 169  
      * Cached instance used by this component. Note here we have a 
 170  
      * "racy single-check". If this field is used, it is supposed 
 171  
      * the object cached by this handler is immutable, and this is
 172  
      * granted if all properties not saved as ValueExpression are
 173  
      * "literal". 
 174  
      */
 175  
     private PropertyDescriptor _propertyDescriptor; 
 176  
     
 177  
     public AttributeHandler(TagConfig config)
 178  
     {
 179  0
         super(config);
 180  0
         _name = getRequiredAttribute("name");
 181  0
         _targets = getAttribute("targets");
 182  0
         _default = getAttribute("default");
 183  0
         _displayName = getAttribute("displayName");
 184  0
         _required = getAttribute("required");
 185  0
         _preferred = getAttribute("preferred");
 186  0
         _expert = getAttribute("expert");
 187  0
         _shortDescription = getAttribute("shortDescription");
 188  0
         _methodSignature = getAttribute("method-signature");
 189  0
         _type = getAttribute("type");
 190  0
         _hidden = getAttribute("hidden");
 191  0
         _targetAttributeName = getAttribute("targetAttributeName");
 192  
         
 193  
         // We can reuse the same PropertyDescriptor only if the properties
 194  
         // that requires to be evaluated when apply (build view time)
 195  
         // occur are literal or null. Otherwise we need to create it.
 196  
         // Note that only if ProjectStage is Development, The "displayName",
 197  
         // "shortDescription", "expert", "hidden", and "preferred" attributes are exposed
 198  0
         final boolean development = FacesContext.getCurrentInstance()
 199  
                 .isProjectStage(ProjectStage.Development);
 200  
         
 201  0
         if (_name.isLiteral() 
 202  
                 && (!development || _areDevelopmentAttributesLiteral()))
 203  
         {
 204  
             // Unfortunately its not possible to create the required 
 205  
             // PropertyDescriptor instance here, because there is no way 
 206  
             // to get a FaceletContext to create ValueExpressions. It is
 207  
             // possible to create it if we not have set all this properties:
 208  
             // targets, default, required, methodSignature, type and possible
 209  
             // unspecified attributes. This prevents the racy single-check.
 210  0
             _cacheable = true;
 211  0
             if ( _targets == null && _default == null && _required == null &&
 212  
                  _methodSignature == null && _type == null && _targetAttributeName == null &&
 213  
                  !CompositeTagAttributeUtils.containsUnspecifiedAttributes(tag, 
 214  
                          STANDARD_ATTRIBUTES_SORTED))
 215  
             {
 216  0
                 _propertyDescriptor = _createPropertyDescriptor(development);
 217  
             }
 218  
         }
 219  
         else
 220  
         {
 221  0
             _cacheable = false;
 222  
         }
 223  0
     }
 224  
     
 225  
     /**
 226  
      * True if the "displayName", "shortDescription", "expert", "hidden", and
 227  
      * "preferred" attributes are either null or literal.
 228  
      * @return
 229  
      */
 230  
     private boolean _areDevelopmentAttributesLiteral()
 231  
     {
 232  0
         return CompositeTagAttributeUtils.areAttributesLiteral(
 233  
                 _displayName, _shortDescription, _expert, _hidden, _preferred);
 234  
     }
 235  
     
 236  
     public void apply(FaceletContext ctx, UIComponent parent)
 237  
             throws IOException
 238  
     {
 239  0
         UIComponent compositeBaseParent
 240  
                 = FaceletCompositionContext.getCurrentInstance(ctx).getCompositeComponentFromStack();
 241  
 
 242  0
         CompositeComponentBeanInfo beanInfo = 
 243  
             (CompositeComponentBeanInfo) compositeBaseParent.getAttributes()
 244  
             .get(UIComponent.BEANINFO_KEY);
 245  
         
 246  0
         if (beanInfo == null)
 247  
         {
 248  0
             if (log.isLoggable(Level.SEVERE))
 249  
             {
 250  0
                 log.severe("Cannot find composite bean descriptor UIComponent.BEANINFO_KEY ");
 251  
             }
 252  0
             return;
 253  
         }
 254  
         
 255  0
         List<PropertyDescriptor> attributeList = beanInfo.getPropertyDescriptorsList();
 256  
         
 257  0
         if (isCacheable())
 258  
         {
 259  0
             if (_propertyDescriptor == null)
 260  
             {
 261  0
                 _propertyDescriptor = _createPropertyDescriptor(ctx);
 262  
             }
 263  0
             attributeList.add(_propertyDescriptor);
 264  
         }
 265  
         else
 266  
         {
 267  0
             PropertyDescriptor attribute = _createPropertyDescriptor(ctx);
 268  0
             attributeList.add(attribute);
 269  
         }
 270  
         
 271  
         // Any "next" handler is going to be used to process nested attributes, which we don't want
 272  
         // to do since they can only possibly refer to bean properties.
 273  
         
 274  
         //nextHandler.apply(ctx, parent);
 275  0
     }
 276  
     
 277  
     /**
 278  
      * This method could be called only if it is not necessary to set the following properties:
 279  
      * targets, default, required, methodSignature and type
 280  
      * 
 281  
      * @param development true if the current ProjectStage is Development
 282  
      * @return
 283  
      */
 284  
     private PropertyDescriptor _createPropertyDescriptor(boolean development)
 285  
     {
 286  
         try
 287  
         {
 288  0
             CompositeComponentPropertyDescriptor attributeDescriptor = 
 289  
                 new CompositeComponentPropertyDescriptor(_name.getValue());
 290  
             
 291  
             // If ProjectStage is Development, The "displayName", "shortDescription",
 292  
             // "expert", "hidden", and "preferred" attributes are exposed
 293  0
             if (development)
 294  
             {
 295  0
                 CompositeTagAttributeUtils.addDevelopmentAttributesLiteral(attributeDescriptor,
 296  
                         _displayName, _shortDescription, _expert, _hidden, _preferred);
 297  
             }
 298  
             
 299  
             // note that no unspecified attributes are handled here, because the current
 300  
             // tag does not contain any, otherwise this code would not have been called.
 301  
             
 302  0
             return attributeDescriptor;
 303  
         }
 304  0
         catch (IntrospectionException e)
 305  
         {
 306  0
             if (log.isLoggable(Level.SEVERE))
 307  
             {
 308  0
                 log.log(Level.SEVERE, "Cannot create PropertyDescriptor for attribute ",e);
 309  
             }
 310  0
             throw new TagException(tag,e);
 311  
         }
 312  
     }
 313  
     
 314  
     private PropertyDescriptor _createPropertyDescriptor(FaceletContext ctx)
 315  
         throws TagException, IOException
 316  
     {
 317  
         try
 318  
         {
 319  0
             CompositeComponentPropertyDescriptor attributeDescriptor = 
 320  
                 new CompositeComponentPropertyDescriptor(_name.getValue(ctx));
 321  
             
 322  
             // The javadoc of ViewDeclarationLanguage.retargetMethodExpressions says that
 323  
             // 'type', 'method-signature', 'targets' should return ValueExpressions.
 324  0
             if (_targets != null)
 325  
             {
 326  0
                 attributeDescriptor.setValue("targets", _targets.getValueExpression(ctx, String.class));
 327  
             }
 328  0
             if (_default != null)
 329  
             {
 330  0
                 if (_type != null)
 331  
                 {
 332  0
                     String type = _type.getValue(ctx);
 333  0
                     Class clazz = String.class;
 334  0
                     if (type != null)
 335  
                     {
 336  
                         try
 337  
                         {
 338  0
                             clazz = ClassUtils.javaDefaultTypeToClass(type);
 339  
                         }
 340  0
                         catch (ClassNotFoundException e)
 341  
                         {
 342  
                             //Assume String
 343  0
                         }
 344  
                     }
 345  
                     
 346  0
                     if (_default.isLiteral())
 347  
                     {
 348  
                         //If it is literal, calculate it and store it on a ValueExpression
 349  0
                         attributeDescriptor.setValue("default", _default.getObject(ctx, clazz));
 350  
                     }
 351  
                     else
 352  
                     {
 353  0
                         attributeDescriptor.setValue("default", _default.getValueExpression(ctx, clazz));
 354  
                     }
 355  0
                 }
 356  
                 else
 357  
                 {
 358  0
                     attributeDescriptor.setValue("default", _default.getValueExpression(ctx, String.class));
 359  
                 }
 360  
             }
 361  0
             if (_required != null)
 362  
             {
 363  0
                 attributeDescriptor.setValue("required", _required.getValueExpression(ctx, Boolean.class));
 364  
             }
 365  0
             if (_methodSignature != null)
 366  
             {
 367  0
                 attributeDescriptor.setValue("method-signature",
 368  
                                              _methodSignature.getValueExpression(ctx, String.class));
 369  
             }
 370  0
             if (_type != null)
 371  
             {
 372  0
                 attributeDescriptor.setValue("type", _type.getValueExpression(ctx, String.class));
 373  
             }
 374  0
             if (_targetAttributeName != null)
 375  
             {
 376  0
                 attributeDescriptor.setValue("targetAttributeName",
 377  
                                              _targetAttributeName.getValueExpression(ctx, String.class));
 378  
             }
 379  
             
 380  
             // If ProjectStage is Development, The "displayName", "shortDescription",
 381  
             // "expert", "hidden", and "preferred" attributes are exposed
 382  0
             if (ctx.getFacesContext().isProjectStage(ProjectStage.Development))
 383  
             {
 384  0
                 CompositeTagAttributeUtils.addDevelopmentAttributes(attributeDescriptor, ctx, 
 385  
                         _displayName, _shortDescription, _expert, _hidden, _preferred);
 386  
             }
 387  
             
 388  
             // Any additional attributes are exposed as attributes accessible
 389  
             // from the getValue() and attributeNames() methods on FeatureDescriptor
 390  0
             CompositeTagAttributeUtils.addUnspecifiedAttributes(attributeDescriptor, tag, 
 391  
                     STANDARD_ATTRIBUTES_SORTED, ctx);
 392  
             
 393  0
             return attributeDescriptor;
 394  
         }
 395  0
         catch (IntrospectionException e)
 396  
         {
 397  0
             if (log.isLoggable(Level.SEVERE))
 398  
             {
 399  0
                 log.log(Level.SEVERE, "Cannot create PropertyDescriptor for attribute ",e);
 400  
             }
 401  0
             throw new TagException(tag,e);
 402  
         }
 403  
     }
 404  
 
 405  
     public boolean isCacheable()
 406  
     {
 407  0
         return _cacheable;
 408  
     }
 409  
     
 410  
     public void setCacheable(boolean cacheable)
 411  
     {
 412  0
         _cacheable = cacheable;
 413  0
     }
 414  
 }