Clover coverage report - Code Coverage for tapestry release 4.0-alpha-2
Coverage timestamp: Thu May 5 2005 09:57:44 EDT
file stats: LOC: 617   Methods: 39
NCLOC: 249   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 81.6% 90.8% 94.9% 89.6%
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   
      * List of {@link InjectStateSpecification}.
 154   
      * 
 155   
      * @since 4.0
 156   
      */
 157   
 
 158   
     private List _injectStateSpecifications;
 159   
 
 160   
     /**
 161   
      * @throws IllegalArgumentException
 162   
      *             if the name already exists.
 163   
      */
 164   
 
 165  46
     public void addAsset(String name, IAssetSpecification asset)
 166   
     {
 167  46
         if (_assets == null)
 168  39
             _assets = new HashMap();
 169   
 
 170  46
         if (_assets.containsKey(name))
 171  0
             throw new IllegalArgumentException(Tapestry.format(
 172   
                     "ComponentSpecification.duplicate-asset",
 173   
                     this,
 174   
                     name));
 175   
 
 176  46
         _assets.put(name, asset);
 177   
     }
 178   
 
 179   
     /**
 180   
      * @throws IllegalArgumentException
 181   
      *             if the id is already defined.
 182   
      */
 183   
 
 184  310
     public void addComponent(String id, IContainedComponent component)
 185   
     {
 186  310
         if (_components == null)
 187  93
             _components = new HashMap();
 188   
 
 189  310
         if (_components.containsKey(id))
 190  0
             throw new IllegalArgumentException(Tapestry.format(
 191   
                     "ComponentSpecification.duplicate-component",
 192   
                     this,
 193   
                     id));
 194   
 
 195  310
         _components.put(id, component);
 196   
     }
 197   
 
 198   
     /**
 199   
      * Adds the parameter. The name is added as a reserved name.
 200   
      * 
 201   
      * @throws IllegalArgumentException
 202   
      *             if the name already exists.
 203   
      */
 204   
 
 205  1139
     public void addParameter(String name, IParameterSpecification spec)
 206   
     {
 207  1139
         if (_parameters == null)
 208  317
             _parameters = new HashMap();
 209   
 
 210  1139
         if (_parameters.containsKey(name))
 211  0
             throw new IllegalArgumentException(Tapestry.format(
 212   
                     "ComponentSpecification.duplicate-parameter",
 213   
                     this,
 214   
                     name));
 215   
 
 216  1139
         _parameters.put(name, spec);
 217   
 
 218  1139
         addReservedParameterName(name);
 219   
     }
 220   
 
 221   
     /**
 222   
      * Returns true if the component is allowed to wrap other elements (static HTML or other
 223   
      * components). The default is true.
 224   
      * 
 225   
      * @see #setAllowBody(boolean)
 226   
      */
 227   
 
 228  2660
     public boolean getAllowBody()
 229   
     {
 230  2660
         return _allowBody;
 231   
     }
 232   
 
 233   
     /**
 234   
      * Returns true if the component allows informal parameters (parameters not formally defined).
 235   
      * Informal parameters are generally used to create additional HTML attributes for an HTML tag
 236   
      * rendered by the component. This is often used to specify JavaScript event handlers or the
 237   
      * class of the component (for Cascarding Style Sheets).
 238   
      * <p>
 239   
      * The default value is true.
 240   
      * 
 241   
      * @see #setAllowInformalParameters(boolean)
 242   
      */
 243   
 
 244  899
     public boolean getAllowInformalParameters()
 245   
     {
 246  899
         return _allowInformalParameters;
 247   
     }
 248   
 
 249   
     /**
 250   
      * Returns the {@link IAssetSpecification}with the given name, or null if no such specification
 251   
      * exists.
 252   
      * 
 253   
      * @see #addAsset(String,IAssetSpecification)
 254   
      */
 255   
 
 256  105
     public IAssetSpecification getAsset(String name)
 257   
     {
 258   
 
 259  105
         return (IAssetSpecification) get(_assets, name);
 260   
     }
 261   
 
 262   
     /**
 263   
      * Returns a <code>List</code> of the String names of all assets, in alphabetical order
 264   
      */
 265   
 
 266  1623
     public List getAssetNames()
 267   
     {
 268  1623
         return sortedKeys(_assets);
 269   
     }
 270   
 
 271   
     /**
 272   
      * Returns the specification of a contained component with the given id, or null if no such
 273   
      * contained component exists.
 274   
      * 
 275   
      * @see #addComponent(String, IContainedComponent)
 276   
      */
 277   
 
 278  1626
     public IContainedComponent getComponent(String id)
 279   
     {
 280  1626
         return (IContainedComponent) get(_components, id);
 281   
     }
 282   
 
 283  1167
     public String getComponentClassName()
 284   
     {
 285  1167
         return _componentClassName;
 286   
     }
 287   
 
 288   
     /**
 289   
      * Returns an <code>List</code> of the String names of the {@link IContainedComponent}s for
 290   
      * this component.
 291   
      * 
 292   
      * @see #addComponent(String, IContainedComponent)
 293   
      */
 294   
 
 295  1624
     public List getComponentIds()
 296   
     {
 297  1624
         return sortedKeys(_components);
 298   
     }
 299   
 
 300   
     /**
 301   
      * Returns the specification of a parameter with the given name, or null if no such parameter
 302   
      * exists.
 303   
      * 
 304   
      * @see #addParameter(String, IParameterSpecification)
 305   
      */
 306   
 
 307  15559
     public IParameterSpecification getParameter(String name)
 308   
     {
 309  15559
         return (IParameterSpecification) get(_parameters, name);
 310   
     }
 311   
 
 312   
     /**
 313   
      * Returns a List of of String names of all parameters. This list is in alphabetical order.
 314   
      * 
 315   
      * @see #addParameter(String, IParameterSpecification)
 316   
      */
 317   
 
 318  2731
     public List getParameterNames()
 319   
     {
 320  2731
         return sortedKeys(_parameters);
 321   
     }
 322   
 
 323  369
     public void setAllowBody(boolean value)
 324   
     {
 325  369
         _allowBody = value;
 326   
     }
 327   
 
 328  369
     public void setAllowInformalParameters(boolean value)
 329   
     {
 330  369
         _allowInformalParameters = value;
 331   
     }
 332   
 
 333  419
     public void setComponentClassName(String value)
 334   
     {
 335  419
         _componentClassName = value;
 336   
     }
 337   
 
 338   
     /**
 339   
      * @since 1.0.4
 340   
      * @throws IllegalArgumentException
 341   
      *             if the bean already has a specification.
 342   
      */
 343   
 
 344  46
     public void addBeanSpecification(String name, IBeanSpecification specification)
 345   
     {
 346  46
         if (_beans == null)
 347  40
             _beans = new HashMap();
 348   
 
 349  6
         else if (_beans.containsKey(name))
 350  0
             throw new IllegalArgumentException(Tapestry.format(
 351   
                     "ComponentSpecification.duplicate-bean",
 352   
                     this,
 353   
                     name));
 354   
 
 355  46
         _beans.put(name, specification);
 356   
     }
 357   
 
 358   
     /**
 359   
      * Returns the {@link IBeanSpecification}for the given name, or null if not such specification
 360   
      * exists.
 361   
      * 
 362   
      * @since 1.0.4
 363   
      */
 364   
 
 365  190
     public IBeanSpecification getBeanSpecification(String name)
 366   
     {
 367  190
         if (_beans == null)
 368  0
             return null;
 369   
 
 370  190
         return (IBeanSpecification) _beans.get(name);
 371   
     }
 372   
 
 373   
     /**
 374   
      * Returns an unmodifiable collection of the names of all beans.
 375   
      */
 376   
 
 377  487
     public Collection getBeanNames()
 378   
     {
 379  487
         if (_beans == null)
 380  431
             return Collections.EMPTY_LIST;
 381   
 
 382  56
         return Collections.unmodifiableCollection(_beans.keySet());
 383   
     }
 384   
 
 385   
     /**
 386   
      * Adds the value as a reserved name. Reserved names are not allowed as the names of informal
 387   
      * parameters. Since the comparison is caseless, the value is converted to lowercase before
 388   
      * being stored.
 389   
      * 
 390   
      * @since 1.0.5
 391   
      */
 392   
 
 393  1280
     public void addReservedParameterName(String value)
 394   
     {
 395  1280
         if (_reservedParameterNames == null)
 396  317
             _reservedParameterNames = new HashSet();
 397   
 
 398  1280
         _reservedParameterNames.add(value.toLowerCase());
 399   
     }
 400   
 
 401   
     /**
 402   
      * Returns true if the value specified is in the reserved name list. The comparison is caseless.
 403   
      * All formal parameters are automatically in the reserved name list, as well as any additional
 404   
      * reserved names specified in the component specification. The latter refer to HTML attributes
 405   
      * generated directly by the component.
 406   
      * 
 407   
      * @since 1.0.5
 408   
      */
 409   
 
 410  95
     public boolean isReservedParameterName(String value)
 411   
     {
 412  95
         if (_reservedParameterNames == null)
 413  0
             return false;
 414   
 
 415  95
         return _reservedParameterNames.contains(value.toLowerCase());
 416   
     }
 417   
 
 418  1
     public String toString()
 419   
     {
 420  1
         ToStringBuilder builder = new ToStringBuilder(this);
 421   
 
 422  1
         builder.append("componentClassName", _componentClassName);
 423  1
         builder.append("pageSpecification", _pageSpecification);
 424  1
         builder.append("specificationLocation", _specificationLocation);
 425  1
         builder.append("allowBody", _allowBody);
 426  1
         builder.append("allowInformalParameter", _allowInformalParameters);
 427   
 
 428  1
         return builder.toString();
 429   
     }
 430   
 
 431   
     /**
 432   
      * Returns the documentation for this component.
 433   
      * 
 434   
      * @since 1.0.9
 435   
      */
 436   
 
 437  1
     public String getDescription()
 438   
     {
 439  1
         return _description;
 440   
     }
 441   
 
 442   
     /**
 443   
      * Sets the documentation for this component.
 444   
      * 
 445   
      * @since 1.0.9
 446   
      */
 447   
 
 448  314
     public void setDescription(String description)
 449   
     {
 450  314
         _description = description;
 451   
     }
 452   
 
 453   
     /**
 454   
      * Returns the XML Public Id for the specification file, or null if not applicable.
 455   
      * <p>
 456   
      * This method exists as a convienience for the Spindle plugin. A previous method used an
 457   
      * arbitrary version string, the public id is more useful and less ambiguous.
 458   
      * 
 459   
      * @since 2.2
 460   
      */
 461   
 
 462  0
     public String getPublicId()
 463   
     {
 464  0
         return _publicId;
 465   
     }
 466   
 
 467   
     /** @since 2.2 * */
 468   
 
 469  0
     public void setPublicId(String publicId)
 470   
     {
 471  0
         _publicId = publicId;
 472   
     }
 473   
 
 474   
     /**
 475   
      * Returns true if the specification is known to be a page specification and not a component
 476   
      * specification. Earlier versions of the framework did not distinguish between the two, but
 477   
      * starting in 2.2, there are seperate XML entities for pages and components. Pages omit several
 478   
      * attributes and entities related to parameters, as parameters only make sense for components.
 479   
      * 
 480   
      * @since 2.2
 481   
      */
 482   
 
 483  51
     public boolean isPageSpecification()
 484   
     {
 485  51
         return _pageSpecification;
 486   
     }
 487   
 
 488   
     /** @since 2.2 * */
 489   
 
 490  136
     public void setPageSpecification(boolean pageSpecification)
 491   
     {
 492  136
         _pageSpecification = pageSpecification;
 493   
     }
 494   
 
 495   
     /** @since 2.2 * */
 496   
 
 497  6444
     private List sortedKeys(Map input)
 498   
     {
 499  6444
         if (input == null)
 500  3899
             return Collections.EMPTY_LIST;
 501   
 
 502  2545
         List result = new ArrayList(input.keySet());
 503   
 
 504  2545
         Collections.sort(result);
 505   
 
 506  2545
         return result;
 507   
     }
 508   
 
 509   
     /** @since 2.2 * */
 510   
 
 511  17433
     private Object get(Map map, Object key)
 512   
     {
 513  17433
         if (map == null)
 514  560
             return null;
 515   
 
 516  16873
         return map.get(key);
 517   
     }
 518   
 
 519   
     /** @since 3.0 * */
 520   
 
 521  1155
     public Resource getSpecificationLocation()
 522   
     {
 523  1155
         return _specificationLocation;
 524   
     }
 525   
 
 526   
     /** @since 3.0 * */
 527   
 
 528  521
     public void setSpecificationLocation(Resource specificationLocation)
 529   
     {
 530  521
         _specificationLocation = specificationLocation;
 531   
     }
 532   
 
 533   
     /**
 534   
      * Adds a new property specification. The name of the property must not already be defined (and
 535   
      * must not change after being added).
 536   
      * 
 537   
      * @since 3.0
 538   
      */
 539   
 
 540  115
     public void addPropertySpecification(IPropertySpecification spec)
 541   
     {
 542  115
         if (_propertySpecifications == null)
 543  54
             _propertySpecifications = new HashMap();
 544   
 
 545  115
         String name = spec.getName();
 546   
 
 547  115
         if (_propertySpecifications.containsKey(name))
 548  1
             throw new IllegalArgumentException(Tapestry.format(
 549   
                     "ComponentSpecification.duplicate-property-specification",
 550   
                     this,
 551   
                     name));
 552   
 
 553  114
         _propertySpecifications.put(name, spec);
 554   
     }
 555   
 
 556   
     /**
 557   
      * Returns a sorted, immutable list of the names of all
 558   
      * {@link org.apache.tapestry.spec.IPropertySpecification}s.
 559   
      * 
 560   
      * @since 3.0
 561   
      */
 562   
 
 563  466
     public List getPropertySpecificationNames()
 564   
     {
 565  466
         return sortedKeys(_propertySpecifications);
 566   
     }
 567   
 
 568   
     /**
 569   
      * Returns the named {@link org.apache.tapestry.spec.IPropertySpecification}, or null if no
 570   
      * such specification exist.
 571   
      * 
 572   
      * @since 3.0
 573   
      * @see #addPropertySpecification(IPropertySpecification)
 574   
      */
 575   
 
 576  143
     public IPropertySpecification getPropertySpecification(String name)
 577   
     {
 578  143
         return (IPropertySpecification) get(_propertySpecifications, name);
 579   
     }
 580   
 
 581  349
     public void addInjectSpecification(InjectSpecification spec)
 582   
     {
 583  349
         if (_injectSpecifications == null)
 584  153
             _injectSpecifications = new ArrayList();
 585   
 
 586   
         // Note: we could check for property name collisions here, but since properties, parameters
 587   
         // and injects can all collide, best to do that inside the component class enhancer.
 588   
 
 589  349
         _injectSpecifications.add(spec);
 590   
     }
 591   
 
 592  465
     public List getInjectSpecifications()
 593   
     {
 594  465
         return safeList(_injectSpecifications);
 595   
     }
 596   
 
 597  1
     public void addInjectStateSpecification(InjectStateSpecification spec)
 598   
     {
 599  1
         if (_injectStateSpecifications == null)
 600  1
             _injectStateSpecifications = new ArrayList();
 601   
 
 602  1
         _injectStateSpecifications.add(spec);
 603   
     }
 604   
 
 605  465
     public List getInjectStateSpecifications()
 606   
     {
 607  465
         return safeList(_injectStateSpecifications);
 608   
     }
 609   
 
 610  930
     private List safeList(List input)
 611   
     {
 612  930
         if (input == null)
 613  776
             return Collections.EMPTY_LIST;
 614   
 
 615  154
         return Collections.unmodifiableList(input);
 616   
     }
 617   
 }