Clover coverage report - Code Coverage for tapestry release 4.0-rc-2
Coverage timestamp: Sat Dec 17 2005 09:39:46 PST
file stats: LOC: 700   Methods: 43
NCLOC: 299   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ComponentSpecification.java 96.2% 96.8% 95.3% 96.4%
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.Iterator;
 23    import java.util.List;
 24    import java.util.Map;
 25    import java.util.Set;
 26   
 27    import org.apache.hivemind.ApplicationRuntimeException;
 28    import org.apache.hivemind.HiveMind;
 29    import org.apache.hivemind.Resource;
 30    import org.apache.hivemind.util.ToStringBuilder;
 31   
 32    /**
 33    * A specification for a component, as read from an XML specification file.
 34    * <p>
 35    * A specification consists of
 36    * <ul>
 37    * <li>An implementing class
 38    * <li>An optional description
 39    * <li>A set of contained components
 40    * <li>Bindings for the properties of each contained component
 41    * <li>A set of named assets
 42    * <li>Definitions for managed beans
 43    * <li>Any reserved names (used for HTML attributes)
 44    * <li>Declared properties
 45    * <li>Property injections
 46    * </ul>
 47    * <p>
 48    * From this information, an actual component may be instantiated and initialized. Instantiating a
 49    * component is usually a recursive process, since to initialize a container component, it is
 50    * necessary to instantiate and initialize its contained components as well.
 51    *
 52    * @see org.apache.tapestry.IComponent
 53    * @see IContainedComponent
 54    * @see org.apache.tapestry.engine.IPageLoader
 55    * @author Howard Lewis Ship
 56    */
 57   
 58    public class ComponentSpecification extends LocatablePropertyHolder implements
 59    IComponentSpecification
 60    {
 61    private String _componentClassName;
 62   
 63    /** @since 1.0.9 * */
 64   
 65    private String _description;
 66   
 67    /**
 68    * Keyed on component id, value is {@link IContainedComponent}.
 69    */
 70   
 71    protected Map _components;
 72   
 73    /**
 74    * Keyed on asset name, value is {@link IAssetSpecification}.
 75    */
 76   
 77    protected Map _assets;
 78   
 79    /**
 80    * Defines all formal parameters. Keyed on parameter name, value is
 81    * {@link IParameterSpecification}.
 82    */
 83   
 84    protected Map _parameters;
 85   
 86    /**
 87    * Defines all helper beans. Keyed on name, value is {@link IBeanSpecification}.
 88    *
 89    * @since 1.0.4
 90    */
 91   
 92    protected Map _beans;
 93   
 94    /**
 95    * The names of all reserved informal parameter names (as lower-case). This allows the page
 96    * loader to filter out any informal parameters during page load, rather than during render.
 97    *
 98    * @since 1.0.5
 99    */
 100   
 101    protected Set _reservedParameterNames;
 102   
 103    /**
 104    * Is the component allowed to have a body (that is, wrap other elements?).
 105    */
 106   
 107    private boolean _allowBody = true;
 108   
 109    /**
 110    * Is the component allow to have informal parameter specified.
 111    */
 112   
 113    private boolean _allowInformalParameters = true;
 114   
 115    /**
 116    * The XML Public Id used when the page or component specification was read (if applicable).
 117    *
 118    * @since 2.2
 119    */
 120   
 121    private String _publicId;
 122   
 123    /**
 124    * Indicates that the specification is for a page, not a component.
 125    *
 126    * @since 2.2
 127    */
 128   
 129    private boolean _pageSpecification;
 130   
 131    /**
 132    * The location from which the specification was obtained.
 133    *
 134    * @since 3.0
 135    */
 136   
 137    private Resource _specificationLocation;
 138   
 139    /**
 140    * A Map of {@link IPropertySpecification}keyed on the name of the property.
 141    *
 142    * @since 3.0
 143    */
 144   
 145    private Map _propertySpecifications;
 146   
 147    /**
 148    * List of {@link InjectSpecification}.
 149    *
 150    * @since 4.0
 151    */
 152   
 153    private List _injectSpecifications;
 154   
 155    /**
 156    * Keyed on property name, value is some other object (such as an IAssetSpecification) that has
 157    * claimed a property of the page.
 158    *
 159    * @since 4.0
 160    */
 161   
 162    private Map _claimedProperties;
 163   
 164    /**
 165    * @since 4.0
 166    */
 167   
 168    private boolean _deprecated = false;
 169   
 170    /**
 171    * @throws ApplicationRuntimeException
 172    * if the name already exists.
 173    */
 174   
 175  44 public void addAsset(String name, IAssetSpecification asset)
 176    {
 177  44 if (_assets == null)
 178  36 _assets = new HashMap();
 179   
 180  44 IAssetSpecification existing = (IAssetSpecification) _assets.get(name);
 181   
 182  44 if (existing != null)
 183  1 throw new ApplicationRuntimeException(SpecMessages.duplicateAsset(name, existing),
 184    asset.getLocation(), null);
 185   
 186  43 claimProperty(asset.getPropertyName(), asset);
 187   
 188  43 _assets.put(name, asset);
 189   
 190    }
 191   
 192    /**
 193    * @throws ApplicationRuntimeException
 194    * if the id is already defined.
 195    */
 196   
 197  251 public void addComponent(String id, IContainedComponent component)
 198    {
 199  251 if (_components == null)
 200  82 _components = new HashMap();
 201   
 202  251 IContainedComponent existing = (IContainedComponent) _components.get(id);
 203   
 204  251 if (existing != null)
 205  1 throw new ApplicationRuntimeException(SpecMessages.duplicateComponent(id, existing),
 206    component.getLocation(), null);
 207   
 208  250 _components.put(id, component);
 209   
 210  250 claimProperty(component.getPropertyName(), component);
 211    }
 212   
 213    /**
 214    * Adds the parameter. The name is added as a reserved name.
 215    *
 216    * @throws ApplicationRuntimeException
 217    * if the name already exists.
 218    */
 219   
 220  1092 public void addParameter(IParameterSpecification spec)
 221    {
 222  1092 if (_parameters == null)
 223  273 _parameters = new HashMap();
 224   
 225  1092 String name = spec.getParameterName();
 226   
 227  1092 addParameterByName(name, spec);
 228   
 229  1091 Iterator i = spec.getAliasNames().iterator();
 230  1091 while (i.hasNext())
 231    {
 232  8 String alias = (String) i.next();
 233   
 234  8 addParameterByName(alias, spec);
 235    }
 236   
 237  1091 claimProperty(spec.getPropertyName(), spec);
 238    }
 239   
 240  1100 private void addParameterByName(String name, IParameterSpecification spec)
 241    {
 242  1100 IParameterSpecification existing = (IParameterSpecification) _parameters.get(name);
 243   
 244  1100 if (existing != null)
 245  1 throw new ApplicationRuntimeException(SpecMessages.duplicateParameter(name, existing),
 246    spec.getLocation(), null);
 247   
 248  1099 _parameters.put(name, spec);
 249   
 250  1099 addReservedParameterName(name);
 251    }
 252   
 253    /**
 254    * Returns true if the component is allowed to wrap other elements (static HTML or other
 255    * components). The default is true.
 256    *
 257    * @see #setAllowBody(boolean)
 258    */
 259   
 260  2260 public boolean getAllowBody()
 261    {
 262  2260 return _allowBody;
 263    }
 264   
 265    /**
 266    * Returns true if the component allows informal parameters (parameters not formally defined).
 267    * Informal parameters are generally used to create additional HTML attributes for an HTML tag
 268    * rendered by the component. This is often used to specify JavaScript event handlers or the
 269    * class of the component (for Cascarding Style Sheets).
 270    * <p>
 271    * The default value is true.
 272    *
 273    * @see #setAllowInformalParameters(boolean)
 274    */
 275   
 276  389 public boolean getAllowInformalParameters()
 277    {
 278  389 return _allowInformalParameters;
 279    }
 280   
 281    /**
 282    * Returns the {@link IAssetSpecification}with the given name, or null if no such specification
 283    * exists.
 284    *
 285    * @see #addAsset(String,IAssetSpecification)
 286    */
 287   
 288  94 public IAssetSpecification getAsset(String name)
 289    {
 290   
 291  94 return (IAssetSpecification) get(_assets, name);
 292    }
 293   
 294    /**
 295    * Returns a <code>List</code> of the String names of all assets, in alphabetical order
 296    */
 297   
 298  1392 public List getAssetNames()
 299    {
 300  1392 return sortedKeys(_assets);
 301    }
 302   
 303    /**
 304    * Returns the specification of a contained component with the given id, or null if no such
 305    * contained component exists.
 306    *
 307    * @see #addComponent(String, IContainedComponent)
 308    */
 309   
 310  1365 public IContainedComponent getComponent(String id)
 311    {
 312  1365 return (IContainedComponent) get(_components, id);
 313    }
 314   
 315  1012 public String getComponentClassName()
 316    {
 317  1012 return _componentClassName;
 318    }
 319   
 320    /**
 321    * Returns an <code>List</code> of the String names of the {@link IContainedComponent}s for
 322    * this component.
 323    *
 324    * @see #addComponent(String, IContainedComponent)
 325    */
 326   
 327  1393 public List getComponentIds()
 328    {
 329  1393 return sortedKeys(_components);
 330    }
 331   
 332    /**
 333    * Returns the specification of a parameter with the given name, or null if no such parameter
 334    * exists.
 335    *
 336    * @see #addParameter(String, IParameterSpecification)
 337    */
 338   
 339  10848 public IParameterSpecification getParameter(String name)
 340    {
 341  10848 return (IParameterSpecification) get(_parameters, name);
 342    }
 343   
 344  983 public Collection getRequiredParameters()
 345    {
 346  983 if (_parameters == null)
 347  162 return Collections.EMPTY_LIST;
 348   
 349  821 Collection result = new ArrayList();
 350   
 351  821 Iterator i = _parameters.entrySet().iterator();
 352  821 while (i.hasNext())
 353    {
 354  3151 Map.Entry entry = (Map.Entry) i.next();
 355  3151 String name = (String) entry.getKey();
 356  3151 IParameterSpecification spec = (IParameterSpecification) entry.getValue();
 357   
 358  3151 if (!spec.isRequired())
 359  2620 continue;
 360   
 361  531 if (!name.equals(spec.getParameterName()))
 362  2 continue;
 363   
 364  529 result.add(spec);
 365    }
 366   
 367  821 return result;
 368    }
 369   
 370    /**
 371    * Returns a List of of String names of all parameters. This list is in alphabetical order.
 372    *
 373    * @see #addParameter(String, IParameterSpecification)
 374    */
 375   
 376  1370 public List getParameterNames()
 377    {
 378  1370 return sortedKeys(_parameters);
 379    }
 380   
 381  315 public void setAllowBody(boolean value)
 382    {
 383  315 _allowBody = value;
 384    }
 385   
 386  315 public void setAllowInformalParameters(boolean value)
 387    {
 388  315 _allowInformalParameters = value;
 389    }
 390   
 391  350 public void setComponentClassName(String value)
 392    {
 393  350 _componentClassName = value;
 394    }
 395   
 396    /**
 397    * @since 1.0.4
 398    * @throws ApplicationRuntimeException
 399    * if the bean already has a specification.
 400    */
 401   
 402  32 public void addBeanSpecification(String name, IBeanSpecification specification)
 403    {
 404  32 if (_beans == null)
 405  31 _beans = new HashMap();
 406   
 407  32 IBeanSpecification existing = (IBeanSpecification) _beans.get(name);
 408   
 409  32 if (existing != null)
 410  1 throw new ApplicationRuntimeException(SpecMessages.duplicateBean(name, existing),
 411    specification.getLocation(), null);
 412   
 413  31 claimProperty(specification.getPropertyName(), specification);
 414   
 415  31 _beans.put(name, specification);
 416    }
 417   
 418    /**
 419    * Returns the {@link IBeanSpecification}for the given name, or null if not such specification
 420    * exists.
 421    *
 422    * @since 1.0.4
 423    */
 424   
 425  188 public IBeanSpecification getBeanSpecification(String name)
 426    {
 427  188 return (IBeanSpecification) get(_beans, name);
 428    }
 429   
 430    /**
 431    * Returns an unmodifiable collection of the names of all beans.
 432    */
 433   
 434  403 public Collection getBeanNames()
 435    {
 436  403 if (_beans == null)
 437  367 return Collections.EMPTY_LIST;
 438   
 439  36 return Collections.unmodifiableCollection(_beans.keySet());
 440    }
 441   
 442    /**
 443    * Adds the value as a reserved name. Reserved names are not allowed as the names of informal
 444    * parameters. Since the comparison is caseless, the value is converted to lowercase before
 445    * being stored.
 446    *
 447    * @since 1.0.5
 448    */
 449   
 450  1208 public void addReservedParameterName(String value)
 451    {
 452  1208 if (_reservedParameterNames == null)
 453  273 _reservedParameterNames = new HashSet();
 454   
 455  1208 _reservedParameterNames.add(value.toLowerCase());
 456    }
 457   
 458    /**
 459    * Returns true if the value specified is in the reserved name list. The comparison is caseless.
 460    * All formal parameters are automatically in the reserved name list, as well as any additional
 461    * reserved names specified in the component specification. The latter refer to HTML attributes
 462    * generated directly by the component.
 463    *
 464    * @since 1.0.5
 465    */
 466   
 467  80 public boolean isReservedParameterName(String value)
 468    {
 469  80 if (_reservedParameterNames == null)
 470  0 return false;
 471   
 472  80 return _reservedParameterNames.contains(value.toLowerCase());
 473    }
 474   
 475  261 public String toString()
 476    {
 477  261 ToStringBuilder builder = new ToStringBuilder(this);
 478   
 479  261 builder.append("componentClassName", _componentClassName);
 480  261 builder.append("pageSpecification", _pageSpecification);
 481  261 builder.append("specificationLocation", _specificationLocation);
 482  261 builder.append("allowBody", _allowBody);
 483  261 builder.append("allowInformalParameter", _allowInformalParameters);
 484   
 485  261 return builder.toString();
 486    }
 487   
 488    /**
 489    * Returns the documentation for this component.
 490    *
 491    * @since 1.0.9
 492    */
 493   
 494  1 public String getDescription()
 495    {
 496  1 return _description;
 497    }
 498   
 499    /**
 500    * Sets the documentation for this component.
 501    *
 502    * @since 1.0.9
 503    */
 504   
 505  260 public void setDescription(String description)
 506    {
 507  260 _description = description;
 508    }
 509   
 510    /**
 511    * Returns the XML Public Id for the specification file, or null if not applicable.
 512    * <p>
 513    * This method exists as a convienience for the Spindle plugin. A previous method used an
 514    * arbitrary version string, the public id is more useful and less ambiguous.
 515    *
 516    * @since 2.2
 517    */
 518   
 519  0 public String getPublicId()
 520    {
 521  0 return _publicId;
 522    }
 523   
 524    /** @since 2.2 * */
 525   
 526  0 public void setPublicId(String publicId)
 527    {
 528  0 _publicId = publicId;
 529    }
 530   
 531    /**
 532    * Returns true if the specification is known to be a page specification and not a component
 533    * specification. Earlier versions of the framework did not distinguish between the two, but
 534    * starting in 2.2, there are seperate XML entities for pages and components. Pages omit several
 535    * attributes and entities related to parameters, as parameters only make sense for components.
 536    *
 537    * @since 2.2
 538    */
 539   
 540  60 public boolean isPageSpecification()
 541    {
 542  60 return _pageSpecification;
 543    }
 544   
 545    /** @since 2.2 * */
 546   
 547  118 public void setPageSpecification(boolean pageSpecification)
 548    {
 549  118 _pageSpecification = pageSpecification;
 550    }
 551   
 552    /** @since 2.2 * */
 553   
 554  4546 private List sortedKeys(Map input)
 555    {
 556  4546 if (input == null)
 557  3169 return Collections.EMPTY_LIST;
 558   
 559  1377 List result = new ArrayList(input.keySet());
 560   
 561  1377 Collections.sort(result);
 562   
 563  1377 return result;
 564    }
 565   
 566    /** @since 2.2 * */
 567   
 568  12634 private Object get(Map map, Object key)
 569    {
 570  12634 if (map == null)
 571  530 return null;
 572   
 573  12104 return map.get(key);
 574    }
 575   
 576    /** @since 3.0 * */
 577   
 578  2272 public Resource getSpecificationLocation()
 579    {
 580  2272 return _specificationLocation;
 581    }
 582   
 583    /** @since 3.0 * */
 584   
 585  451 public void setSpecificationLocation(Resource specificationLocation)
 586    {
 587  451 _specificationLocation = specificationLocation;
 588    }
 589   
 590    /**
 591    * Adds a new property specification. The name of the property must not already be defined (and
 592    * must not change after being added).
 593    *
 594    * @since 3.0
 595    */
 596   
 597  117 public void addPropertySpecification(IPropertySpecification spec)
 598    {
 599  117 if (_propertySpecifications == null)
 600  58 _propertySpecifications = new HashMap();
 601   
 602  117 String name = spec.getName();
 603  117 IPropertySpecification existing = (IPropertySpecification) _propertySpecifications
 604    .get(name);
 605   
 606  117 if (existing != null)
 607  0 throw new ApplicationRuntimeException(SpecMessages.duplicateProperty(name, existing),
 608    spec.getLocation(), null);
 609   
 610  117 claimProperty(name, spec);
 611   
 612  117 _propertySpecifications.put(name, spec);
 613    }
 614   
 615    /**
 616    * Returns a sorted, immutable list of the names of all
 617    * {@link org.apache.tapestry.spec.IPropertySpecification}s.
 618    *
 619    * @since 3.0
 620    */
 621   
 622  391 public List getPropertySpecificationNames()
 623    {
 624  391 return sortedKeys(_propertySpecifications);
 625    }
 626   
 627    /**
 628    * Returns the named {@link org.apache.tapestry.spec.IPropertySpecification}, or null if no
 629    * such specification exist.
 630    *
 631    * @since 3.0
 632    * @see #addPropertySpecification(IPropertySpecification)
 633    */
 634   
 635  139 public IPropertySpecification getPropertySpecification(String name)
 636    {
 637  139 return (IPropertySpecification) get(_propertySpecifications, name);
 638    }
 639   
 640  360 public void addInjectSpecification(InjectSpecification spec)
 641    {
 642  360 if (_injectSpecifications == null)
 643  159 _injectSpecifications = new ArrayList();
 644   
 645  360 claimProperty(spec.getProperty(), spec);
 646   
 647  359 _injectSpecifications.add(spec);
 648    }
 649   
 650  392 public List getInjectSpecifications()
 651    {
 652  392 return safeList(_injectSpecifications);
 653    }
 654   
 655  392 private List safeList(List input)
 656    {
 657  392 if (input == null)
 658  233 return Collections.EMPTY_LIST;
 659   
 660  159 return Collections.unmodifiableList(input);
 661    }
 662   
 663  1892 private void claimProperty(String propertyName, Object subSpecification)
 664    {
 665  1892 if (propertyName == null)
 666  326 return;
 667   
 668  1566 if (_claimedProperties == null)
 669  310 _claimedProperties = new HashMap();
 670   
 671  1566 Object existing = _claimedProperties.get(propertyName);
 672   
 673  1566 if (existing != null)
 674  1 throw new ApplicationRuntimeException(SpecMessages.claimedProperty(
 675    propertyName,
 676    existing), HiveMind.getLocation(subSpecification), null);
 677   
 678  1565 _claimedProperties.put(propertyName, subSpecification);
 679    }
 680   
 681    /** @since 4.0 */
 682  889 public boolean isDeprecated()
 683    {
 684  889 return _deprecated;
 685    }
 686   
 687    /** @since 4.0 */
 688  315 public void setDeprecated(boolean deprecated)
 689    {
 690  315 _deprecated = deprecated;
 691    }
 692   
 693  4 public Set getReservedParameterNames()
 694    {
 695  4 if (_reservedParameterNames == null)
 696  1 return Collections.EMPTY_SET;
 697   
 698  3 return Collections.unmodifiableSet(_reservedParameterNames);
 699    }
 700    }