Clover coverage report - Code Coverage for tapestry release 4.0-alpha-3
Coverage timestamp: Mon May 16 2005 09:05:49 EDT
file stats: LOC: 596   Methods: 37
NCLOC: 238   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
ComponentSpecification.java 83.3% 90.4% 94.6% 89.7%
coverage coverage
 1   
 // Copyright 2004, 2005 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.tapestry.spec;
 16   
 
 17   
 import java.util.ArrayList;
 18   
 import java.util.Collection;
 19   
 import java.util.Collections;
 20   
 import java.util.HashMap;
 21   
 import java.util.HashSet;
 22   
 import java.util.List;
 23   
 import java.util.Map;
 24   
 import java.util.Set;
 25   
 
 26   
 import org.apache.commons.lang.builder.ToStringBuilder;
 27   
 import org.apache.hivemind.Resource;
 28   
 import org.apache.tapestry.Tapestry;
 29   
 
 30   
 /**
 31   
  * A specification for a component, as read from an XML specification file.
 32   
  * <p>
 33   
  * A specification consists of
 34   
  * <ul>
 35   
  * <li>An implementing class
 36   
  * <li>An optional template
 37   
  * <li>An optional description
 38   
  * <li>A set of contained components
 39   
  * <li>Bindings for the properties of each contained component
 40   
  * <li>A set of named assets
 41   
  * <li>Definitions for helper beans
 42   
  * <li>Any reserved names (used for HTML attributes)
 43   
  * </ul>
 44   
  * <p>
 45   
  * From this information, an actual component may be instantiated and initialized. Instantiating a
 46   
  * component is usually a recursive process, since to initialize a container component, it is
 47   
  * necessary to instantiate and initialize its contained components as well.
 48   
  * 
 49   
  * @see org.apache.tapestry.IComponent
 50   
  * @see IContainedComponent
 51   
  * @see org.apache.tapestry.engine.IPageLoader
 52   
  * @author Howard Lewis Ship
 53   
  */
 54   
 
 55   
 public class ComponentSpecification extends LocatablePropertyHolder implements
 56   
         IComponentSpecification
 57   
 {
 58   
     private String _componentClassName;
 59   
 
 60   
     /** @since 1.0.9 * */
 61   
 
 62   
     private String _description;
 63   
 
 64   
     /**
 65   
      * Keyed on component id, value is {@link IContainedComponent}.
 66   
      */
 67   
 
 68   
     protected Map _components;
 69   
 
 70   
     /**
 71   
      * Keyed on asset name, value is {@link IAssetSpecification}.
 72   
      */
 73   
 
 74   
     protected Map _assets;
 75   
 
 76   
     /**
 77   
      * Defines all formal parameters. Keyed on parameter name, value is
 78   
      * {@link IParameterSpecification}.
 79   
      */
 80   
 
 81   
     protected Map _parameters;
 82   
 
 83   
     /**
 84   
      * Defines all helper beans. Keyed on name, value is {@link IBeanSpecification}.
 85   
      * 
 86   
      * @since 1.0.4
 87   
      */
 88   
 
 89   
     protected Map _beans;
 90   
 
 91   
     /**
 92   
      * The names of all reserved informal parameter names (as lower-case). This allows the page
 93   
      * loader to filter out any informal parameters during page load, rather than during render.
 94   
      * 
 95   
      * @since 1.0.5
 96   
      */
 97   
 
 98   
     protected Set _reservedParameterNames;
 99   
 
 100   
     /**
 101   
      * Is the component allowed to have a body (that is, wrap other elements?).
 102   
      */
 103   
 
 104   
     private boolean _allowBody = true;
 105   
 
 106   
     /**
 107   
      * Is the component allow to have informal parameter specified.
 108   
      */
 109   
 
 110   
     private boolean _allowInformalParameters = true;
 111   
 
 112   
     /**
 113   
      * The XML Public Id used when the page or component specification was read (if applicable).
 114   
      * 
 115   
      * @since 2.2
 116   
      */
 117   
 
 118   
     private String _publicId;
 119   
 
 120   
     /**
 121   
      * Indicates that the specification is for a page, not a component.
 122   
      * 
 123   
      * @since 2.2
 124   
      */
 125   
 
 126   
     private boolean _pageSpecification;
 127   
 
 128   
     /**
 129   
      * The location from which the specification was obtained.
 130   
      * 
 131   
      * @since 3.0
 132   
      */
 133   
 
 134   
     private Resource _specificationLocation;
 135   
 
 136   
     /**
 137   
      * A Map of {@link IPropertySpecification}keyed on the name of the property.
 138   
      * 
 139   
      * @since 3.0
 140   
      */
 141   
 
 142   
     private Map _propertySpecifications;
 143   
 
 144   
     /**
 145   
      * List of {@link InjectSpecification}.
 146   
      * 
 147   
      * @since 4.0
 148   
      */
 149   
 
 150   
     private List _injectSpecifications;
 151   
 
 152   
     /**
 153   
      * @throws IllegalArgumentException
 154   
      *             if the name already exists.
 155   
      */
 156   
 
 157  46
     public void addAsset(String name, IAssetSpecification asset)
 158   
     {
 159  46
         if (_assets == null)
 160  39
             _assets = new HashMap();
 161   
 
 162  46
         if (_assets.containsKey(name))
 163  0
             throw new IllegalArgumentException(Tapestry.format(
 164   
                     "ComponentSpecification.duplicate-asset",
 165   
                     this,
 166   
                     name));
 167   
 
 168  46
         _assets.put(name, asset);
 169   
     }
 170   
 
 171   
     /**
 172   
      * @throws IllegalArgumentException
 173   
      *             if the id is already defined.
 174   
      */
 175   
 
 176  310
     public void addComponent(String id, IContainedComponent component)
 177   
     {
 178  310
         if (_components == null)
 179  93
             _components = new HashMap();
 180   
 
 181  310
         if (_components.containsKey(id))
 182  0
             throw new IllegalArgumentException(Tapestry.format(
 183   
                     "ComponentSpecification.duplicate-component",
 184   
                     this,
 185   
                     id));
 186   
 
 187  310
         _components.put(id, component);
 188   
     }
 189   
 
 190   
     /**
 191   
      * Adds the parameter. The name is added as a reserved name.
 192   
      * 
 193   
      * @throws IllegalArgumentException
 194   
      *             if the name already exists.
 195   
      */
 196   
 
 197  1139
     public void addParameter(String name, IParameterSpecification spec)
 198   
     {
 199  1139
         if (_parameters == null)
 200  317
             _parameters = new HashMap();
 201   
 
 202  1139
         if (_parameters.containsKey(name))
 203  0
             throw new IllegalArgumentException(Tapestry.format(
 204   
                     "ComponentSpecification.duplicate-parameter",
 205   
                     this,
 206   
                     name));
 207   
 
 208  1139
         _parameters.put(name, spec);
 209   
 
 210  1139
         addReservedParameterName(name);
 211   
     }
 212   
 
 213   
     /**
 214   
      * Returns true if the component is allowed to wrap other elements (static HTML or other
 215   
      * components). The default is true.
 216   
      * 
 217   
      * @see #setAllowBody(boolean)
 218   
      */
 219   
 
 220  2660
     public boolean getAllowBody()
 221   
     {
 222  2660
         return _allowBody;
 223   
     }
 224   
 
 225   
     /**
 226   
      * Returns true if the component allows informal parameters (parameters not formally defined).
 227   
      * Informal parameters are generally used to create additional HTML attributes for an HTML tag
 228   
      * rendered by the component. This is often used to specify JavaScript event handlers or the
 229   
      * class of the component (for Cascarding Style Sheets).
 230   
      * <p>
 231   
      * The default value is true.
 232   
      * 
 233   
      * @see #setAllowInformalParameters(boolean)
 234   
      */
 235   
 
 236  899
     public boolean getAllowInformalParameters()
 237   
     {
 238  899
         return _allowInformalParameters;
 239   
     }
 240   
 
 241   
     /**
 242   
      * Returns the {@link IAssetSpecification}with the given name, or null if no such specification
 243   
      * exists.
 244   
      * 
 245   
      * @see #addAsset(String,IAssetSpecification)
 246   
      */
 247   
 
 248  105
     public IAssetSpecification getAsset(String name)
 249   
     {
 250   
 
 251  105
         return (IAssetSpecification) get(_assets, name);
 252   
     }
 253   
 
 254   
     /**
 255   
      * Returns a <code>List</code> of the String names of all assets, in alphabetical order
 256   
      */
 257   
 
 258  1621
     public List getAssetNames()
 259   
     {
 260  1621
         return sortedKeys(_assets);
 261   
     }
 262   
 
 263   
     /**
 264   
      * Returns the specification of a contained component with the given id, or null if no such
 265   
      * contained component exists.
 266   
      * 
 267   
      * @see #addComponent(String, IContainedComponent)
 268   
      */
 269   
 
 270  1626
     public IContainedComponent getComponent(String id)
 271   
     {
 272  1626
         return (IContainedComponent) get(_components, id);
 273   
     }
 274   
 
 275  1167
     public String getComponentClassName()
 276   
     {
 277  1167
         return _componentClassName;
 278   
     }
 279   
 
 280   
     /**
 281   
      * Returns an <code>List</code> of the String names of the {@link IContainedComponent}s for
 282   
      * this component.
 283   
      * 
 284   
      * @see #addComponent(String, IContainedComponent)
 285   
      */
 286   
 
 287  1622
     public List getComponentIds()
 288   
     {
 289  1622
         return sortedKeys(_components);
 290   
     }
 291   
 
 292   
     /**
 293   
      * Returns the specification of a parameter with the given name, or null if no such parameter
 294   
      * exists.
 295   
      * 
 296   
      * @see #addParameter(String, IParameterSpecification)
 297   
      */
 298   
 
 299  16046
     public IParameterSpecification getParameter(String name)
 300   
     {
 301  16046
         return (IParameterSpecification) get(_parameters, name);
 302   
     }
 303   
 
 304   
     /**
 305   
      * Returns a List of of String names of all parameters. This list is in alphabetical order.
 306   
      * 
 307   
      * @see #addParameter(String, IParameterSpecification)
 308   
      */
 309   
 
 310  2729
     public List getParameterNames()
 311   
     {
 312  2729
         return sortedKeys(_parameters);
 313   
     }
 314   
 
 315  369
     public void setAllowBody(boolean value)
 316   
     {
 317  369
         _allowBody = value;
 318   
     }
 319   
 
 320  369
     public void setAllowInformalParameters(boolean value)
 321   
     {
 322  369
         _allowInformalParameters = value;
 323   
     }
 324   
 
 325  419
     public void setComponentClassName(String value)
 326   
     {
 327  419
         _componentClassName = value;
 328   
     }
 329   
 
 330   
     /**
 331   
      * @since 1.0.4
 332   
      * @throws IllegalArgumentException
 333   
      *             if the bean already has a specification.
 334   
      */
 335   
 
 336  44
     public void addBeanSpecification(String name, IBeanSpecification specification)
 337   
     {
 338  44
         if (_beans == null)
 339  39
             _beans = new HashMap();
 340   
 
 341  5
         else if (_beans.containsKey(name))
 342  0
             throw new IllegalArgumentException(Tapestry.format(
 343   
                     "ComponentSpecification.duplicate-bean",
 344   
                     this,
 345   
                     name));
 346   
 
 347  44
         _beans.put(name, specification);
 348   
     }
 349   
 
 350   
     /**
 351   
      * Returns the {@link IBeanSpecification}for the given name, or null if not such specification
 352   
      * exists.
 353   
      * 
 354   
      * @since 1.0.4
 355   
      */
 356   
 
 357  182
     public IBeanSpecification getBeanSpecification(String name)
 358   
     {
 359  182
         if (_beans == null)
 360  0
             return null;
 361   
 
 362  182
         return (IBeanSpecification) _beans.get(name);
 363   
     }
 364   
 
 365   
     /**
 366   
      * Returns an unmodifiable collection of the names of all beans.
 367   
      */
 368   
 
 369  484
     public Collection getBeanNames()
 370   
     {
 371  484
         if (_beans == null)
 372  430
             return Collections.EMPTY_LIST;
 373   
 
 374  54
         return Collections.unmodifiableCollection(_beans.keySet());
 375   
     }
 376   
 
 377   
     /**
 378   
      * Adds the value as a reserved name. Reserved names are not allowed as the names of informal
 379   
      * parameters. Since the comparison is caseless, the value is converted to lowercase before
 380   
      * being stored.
 381   
      * 
 382   
      * @since 1.0.5
 383   
      */
 384   
 
 385  1280
     public void addReservedParameterName(String value)
 386   
     {
 387  1280
         if (_reservedParameterNames == null)
 388  317
             _reservedParameterNames = new HashSet();
 389   
 
 390  1280
         _reservedParameterNames.add(value.toLowerCase());
 391   
     }
 392   
 
 393   
     /**
 394   
      * Returns true if the value specified is in the reserved name list. The comparison is caseless.
 395   
      * All formal parameters are automatically in the reserved name list, as well as any additional
 396   
      * reserved names specified in the component specification. The latter refer to HTML attributes
 397   
      * generated directly by the component.
 398   
      * 
 399   
      * @since 1.0.5
 400   
      */
 401   
 
 402  95
     public boolean isReservedParameterName(String value)
 403   
     {
 404  95
         if (_reservedParameterNames == null)
 405  0
             return false;
 406   
 
 407  95
         return _reservedParameterNames.contains(value.toLowerCase());
 408   
     }
 409   
 
 410  1
     public String toString()
 411   
     {
 412  1
         ToStringBuilder builder = new ToStringBuilder(this);
 413   
 
 414  1
         builder.append("componentClassName", _componentClassName);
 415  1
         builder.append("pageSpecification", _pageSpecification);
 416  1
         builder.append("specificationLocation", _specificationLocation);
 417  1
         builder.append("allowBody", _allowBody);
 418  1
         builder.append("allowInformalParameter", _allowInformalParameters);
 419   
 
 420  1
         return builder.toString();
 421   
     }
 422   
 
 423   
     /**
 424   
      * Returns the documentation for this component.
 425   
      * 
 426   
      * @since 1.0.9
 427   
      */
 428   
 
 429  1
     public String getDescription()
 430   
     {
 431  1
         return _description;
 432   
     }
 433   
 
 434   
     /**
 435   
      * Sets the documentation for this component.
 436   
      * 
 437   
      * @since 1.0.9
 438   
      */
 439   
 
 440  314
     public void setDescription(String description)
 441   
     {
 442  314
         _description = description;
 443   
     }
 444   
 
 445   
     /**
 446   
      * Returns the XML Public Id for the specification file, or null if not applicable.
 447   
      * <p>
 448   
      * This method exists as a convienience for the Spindle plugin. A previous method used an
 449   
      * arbitrary version string, the public id is more useful and less ambiguous.
 450   
      * 
 451   
      * @since 2.2
 452   
      */
 453   
 
 454  0
     public String getPublicId()
 455   
     {
 456  0
         return _publicId;
 457   
     }
 458   
 
 459   
     /** @since 2.2 * */
 460   
 
 461  0
     public void setPublicId(String publicId)
 462   
     {
 463  0
         _publicId = publicId;
 464   
     }
 465   
 
 466   
     /**
 467   
      * Returns true if the specification is known to be a page specification and not a component
 468   
      * specification. Earlier versions of the framework did not distinguish between the two, but
 469   
      * starting in 2.2, there are seperate XML entities for pages and components. Pages omit several
 470   
      * attributes and entities related to parameters, as parameters only make sense for components.
 471   
      * 
 472   
      * @since 2.2
 473   
      */
 474   
 
 475  51
     public boolean isPageSpecification()
 476   
     {
 477  51
         return _pageSpecification;
 478   
     }
 479   
 
 480   
     /** @since 2.2 * */
 481   
 
 482  135
     public void setPageSpecification(boolean pageSpecification)
 483   
     {
 484  135
         _pageSpecification = pageSpecification;
 485   
     }
 486   
 
 487   
     /** @since 2.2 * */
 488   
 
 489  6436
     private List sortedKeys(Map input)
 490   
     {
 491  6436
         if (input == null)
 492  3892
             return Collections.EMPTY_LIST;
 493   
 
 494  2544
         List result = new ArrayList(input.keySet());
 495   
 
 496  2544
         Collections.sort(result);
 497   
 
 498  2544
         return result;
 499   
     }
 500   
 
 501   
     /** @since 2.2 * */
 502   
 
 503  17917
     private Object get(Map map, Object key)
 504   
     {
 505  17917
         if (map == null)
 506  560
             return null;
 507   
 
 508  17357
         return map.get(key);
 509   
     }
 510   
 
 511   
     /** @since 3.0 * */
 512   
 
 513  1155
     public Resource getSpecificationLocation()
 514   
     {
 515  1155
         return _specificationLocation;
 516   
     }
 517   
 
 518   
     /** @since 3.0 * */
 519   
 
 520  520
     public void setSpecificationLocation(Resource specificationLocation)
 521   
     {
 522  520
         _specificationLocation = specificationLocation;
 523   
     }
 524   
 
 525   
     /**
 526   
      * Adds a new property specification. The name of the property must not already be defined (and
 527   
      * must not change after being added).
 528   
      * 
 529   
      * @since 3.0
 530   
      */
 531   
 
 532  112
     public void addPropertySpecification(IPropertySpecification spec)
 533   
     {
 534  112
         if (_propertySpecifications == null)
 535  53
             _propertySpecifications = new HashMap();
 536   
 
 537  112
         String name = spec.getName();
 538   
 
 539  112
         if (_propertySpecifications.containsKey(name))
 540  1
             throw new IllegalArgumentException(Tapestry.format(
 541   
                     "ComponentSpecification.duplicate-property-specification",
 542   
                     this,
 543   
                     name));
 544   
 
 545  111
         _propertySpecifications.put(name, spec);
 546   
     }
 547   
 
 548   
     /**
 549   
      * Returns a sorted, immutable list of the names of all
 550   
      * {@link org.apache.tapestry.spec.IPropertySpecification}s.
 551   
      * 
 552   
      * @since 3.0
 553   
      */
 554   
 
 555  464
     public List getPropertySpecificationNames()
 556   
     {
 557  464
         return sortedKeys(_propertySpecifications);
 558   
     }
 559   
 
 560   
     /**
 561   
      * Returns the named {@link org.apache.tapestry.spec.IPropertySpecification}, or null if no
 562   
      * such specification exist.
 563   
      * 
 564   
      * @since 3.0
 565   
      * @see #addPropertySpecification(IPropertySpecification)
 566   
      */
 567   
 
 568  140
     public IPropertySpecification getPropertySpecification(String name)
 569   
     {
 570  140
         return (IPropertySpecification) get(_propertySpecifications, name);
 571   
     }
 572   
 
 573  381
     public void addInjectSpecification(InjectSpecification spec)
 574   
     {
 575  381
         if (_injectSpecifications == null)
 576  169
             _injectSpecifications = new ArrayList();
 577   
 
 578   
         // Note: we could check for property name collisions here, but since properties, parameters
 579   
         // and injects can all collide, best to do that inside the component class enhancer.
 580   
 
 581  381
         _injectSpecifications.add(spec);
 582   
     }
 583   
 
 584  463
     public List getInjectSpecifications()
 585   
     {
 586  463
         return safeList(_injectSpecifications);
 587   
     }
 588   
 
 589  463
     private List safeList(List input)
 590   
     {
 591  463
         if (input == null)
 592  294
             return Collections.EMPTY_LIST;
 593   
 
 594  169
         return Collections.unmodifiableList(input);
 595   
     }
 596   
 }