Coverage Report - org.apache.tapestry.spec.ComponentSpecification
 
Classes in this File Line Coverage Branch Coverage Complexity
ComponentSpecification
0%
0/224
0%
0/108
2.527
 
 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 org.apache.hivemind.ApplicationRuntimeException;
 18  
 import org.apache.hivemind.HiveMind;
 19  
 import org.apache.hivemind.Resource;
 20  
 import org.apache.hivemind.util.Defense;
 21  
 import org.apache.hivemind.util.ToStringBuilder;
 22  
 import org.apache.tapestry.IComponent;
 23  
 import org.apache.tapestry.IForm;
 24  
 import org.apache.tapestry.event.BrowserEvent;
 25  
 import org.apache.tapestry.internal.event.ComponentEventProperty;
 26  
 import org.apache.tapestry.internal.event.EventBoundListener;
 27  
 
 28  
 import java.util.*;
 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 description
 37  
  * <li>A set of contained components
 38  
  * <li>Bindings for the properties of each contained component
 39  
  * <li>A set of named assets
 40  
  * <li>Definitions for managed beans
 41  
  * <li>Any reserved names (used for HTML attributes)
 42  
  * <li>Declared properties
 43  
  * <li>Property injections
 44  
  * </ul>
 45  
  * <p>
 46  
  * From this information, an actual component may be instantiated and initialized. Instantiating a
 47  
  * component is usually a recursive process, since to initialize a container component, it is
 48  
  * necessary to instantiate and initialize its contained components as well.
 49  
  * 
 50  
  * @see org.apache.tapestry.IComponent
 51  
  * @see IContainedComponent
 52  
  * @see org.apache.tapestry.engine.IPageLoader
 53  
  * @author Howard Lewis Ship
 54  
  */
 55  
 
 56  0
 public class ComponentSpecification extends LocatablePropertyHolder implements IComponentSpecification
 57  
 {
 58  
     /**
 59  
      * Keyed on component id, value is {@link IContainedComponent}.
 60  
      */
 61  
 
 62  
     protected Map _components;
 63  
 
 64  
     /**
 65  
      * Keyed on asset name, value is {@link IAssetSpecification}.
 66  
      */
 67  
 
 68  
     protected Map _assets;
 69  
 
 70  
     /**
 71  
      * Defines all formal parameters. Keyed on parameter name, value is
 72  
      * {@link IParameterSpecification}.
 73  
      */
 74  
 
 75  
     protected Map _parameters;
 76  
 
 77  
     /**
 78  
      * Defines all helper beans. Keyed on name, value is {@link IBeanSpecification}.
 79  
      * 
 80  
      * @since 1.0.4
 81  
      */
 82  
 
 83  
     protected Map _beans;
 84  
 
 85  
     /**
 86  
      * The names of all reserved informal parameter names (as lower-case). This allows the page
 87  
      * loader to filter out any informal parameters during page load, rather than during render.
 88  
      * 
 89  
      * @since 1.0.5
 90  
      */
 91  
 
 92  
     protected Set _reservedParameterNames;
 93  
 
 94  
     private String _componentClassName;
 95  
 
 96  
     /** @since 1.0.9 * */
 97  
 
 98  
     private String _description;
 99  
     
 100  
     /**
 101  
      * Is the component allowed to have a body (that is, wrap other elements?).
 102  
      */
 103  
 
 104  0
     private boolean _allowBody = true;
 105  
 
 106  
     /**
 107  
      * Is the component allow to have informal parameter specified.
 108  
      */
 109  
 
 110  0
     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  
      * Keyed on property name, value is some other object (such as an IAssetSpecification) that has
 154  
      * claimed a property of the page.
 155  
      * 
 156  
      * @since 4.0
 157  
      */
 158  
 
 159  
     private Map _claimedProperties;
 160  
 
 161  
     /**
 162  
      * @since 4.0
 163  
      */
 164  
 
 165  0
     private boolean _deprecated = false;
 166  
     
 167  0
     private Map _componentEvents = new HashMap();
 168  0
     private Map _elementEvents = new HashMap();
 169  
 
 170  
     /**
 171  
      * @throws ApplicationRuntimeException
 172  
      *             if the name already exists.
 173  
      */
 174  
 
 175  
     public void addAsset(String name, IAssetSpecification asset)
 176  
     {
 177  0
         if (_assets == null)
 178  0
             _assets = new HashMap();
 179  
 
 180  0
         IAssetSpecification existing = (IAssetSpecification) _assets.get(name);
 181  
 
 182  0
         if (existing != null)
 183  0
             throw new ApplicationRuntimeException(SpecMessages.duplicateAsset(name, existing),
 184  
                     asset.getLocation(), null);
 185  
 
 186  0
         claimProperty(asset.getPropertyName(), asset);
 187  
 
 188  0
         _assets.put(name, asset);
 189  0
     }
 190  
 
 191  
     /**
 192  
      * @throws ApplicationRuntimeException if the id is already defined.
 193  
      */
 194  
 
 195  
     public void addComponent(String id, IContainedComponent component)
 196  
     {
 197  0
         if (_components == null)
 198  0
             _components = new HashMap();
 199  
 
 200  0
         IContainedComponent existing = (IContainedComponent) _components.get(id);
 201  
 
 202  0
         if (existing != null)
 203  0
             throw new ApplicationRuntimeException(SpecMessages.duplicateComponent(id, existing),
 204  
                     component.getLocation(), null);
 205  
 
 206  0
         _components.put(id, component);
 207  
 
 208  0
         claimProperty(component.getPropertyName(), component);
 209  0
     }
 210  
 
 211  
     /**
 212  
      * Adds the parameter. The name is added as a reserved name.
 213  
      * 
 214  
      * @throws ApplicationRuntimeException if the name already exists.
 215  
      */
 216  
 
 217  
     public void addParameter(IParameterSpecification spec)
 218  
     {
 219  0
         if (_parameters == null)
 220  0
             _parameters = new HashMap();
 221  
 
 222  0
         String name = spec.getParameterName();
 223  
 
 224  0
         addParameterByName(name, spec);
 225  
 
 226  0
         Iterator i = spec.getAliasNames().iterator();
 227  0
         while (i.hasNext())
 228  
         {
 229  0
             String alias = (String) i.next();
 230  
 
 231  0
             addParameterByName(alias, spec);
 232  0
         }
 233  
 
 234  0
         claimProperty(spec.getPropertyName(), spec);
 235  0
     }
 236  
 
 237  
     private void addParameterByName(String name, IParameterSpecification spec)
 238  
     {
 239  0
         IParameterSpecification existing = (IParameterSpecification) _parameters.get(name);
 240  
 
 241  0
         if (existing != null)
 242  0
             throw new ApplicationRuntimeException(SpecMessages.duplicateParameter(name, existing),
 243  
                     spec.getLocation(), null);
 244  
 
 245  0
         _parameters.put(name, spec);
 246  
 
 247  0
         addReservedParameterName(name);
 248  0
     }
 249  
 
 250  
     /**
 251  
      * Returns true if the component is allowed to wrap other elements (static HTML or other
 252  
      * components). The default is true.
 253  
      * 
 254  
      * @see #setAllowBody(boolean)
 255  
      */
 256  
 
 257  
     public boolean getAllowBody()
 258  
     {
 259  0
         return _allowBody;
 260  
     }
 261  
 
 262  
     /**
 263  
      * Returns true if the component allows informal parameters (parameters not formally defined).
 264  
      * Informal parameters are generally used to create additional HTML attributes for an HTML tag
 265  
      * rendered by the component. This is often used to specify JavaScript event handlers or the
 266  
      * class of the component (for Cascarding Style Sheets).
 267  
      * <p>
 268  
      * The default value is true.
 269  
      * 
 270  
      * @see #setAllowInformalParameters(boolean)
 271  
      */
 272  
 
 273  
     public boolean getAllowInformalParameters()
 274  
     {
 275  0
         return _allowInformalParameters;
 276  
     }
 277  
 
 278  
     /**
 279  
      * Returns the {@link IAssetSpecification}with the given name, or null if no such specification
 280  
      * exists.
 281  
      * 
 282  
      * @see #addAsset(String,IAssetSpecification)
 283  
      */
 284  
 
 285  
     public IAssetSpecification getAsset(String name)
 286  
     {
 287  0
         return (IAssetSpecification) get(_assets, name);
 288  
     }
 289  
 
 290  
     /**
 291  
      * Returns a <code>List</code> of the String names of all assets, in alphabetical order.
 292  
      */
 293  
 
 294  
     public List getAssetNames()
 295  
     {
 296  0
         return sortedKeys(_assets);
 297  
     }
 298  
 
 299  
     /**
 300  
      * Returns the specification of a contained component with the given id, or null if no such
 301  
      * contained component exists.
 302  
      * 
 303  
      * @see #addComponent(String, IContainedComponent)
 304  
      */
 305  
 
 306  
     public IContainedComponent getComponent(String id)
 307  
     {
 308  0
         return (IContainedComponent) get(_components, id);
 309  
     }
 310  
 
 311  
     
 312  
     public String getComponentClassName()
 313  
     {
 314  0
         return _componentClassName;
 315  
     }
 316  
 
 317  
     /**
 318  
      * Returns an <code>List</code> of the String names of the {@link IContainedComponent}s for
 319  
      * this component.
 320  
      * 
 321  
      * @see #addComponent(String, IContainedComponent)
 322  
      */
 323  
 
 324  
     public List getComponentIds()
 325  
     {
 326  0
         return sortedKeys(_components);
 327  
     }
 328  
 
 329  
     /**
 330  
      * Returns the specification of a parameter with the given name, or null if no such parameter
 331  
      * exists.
 332  
      * 
 333  
      * @see #addParameterByName(String, IParameterSpecification)
 334  
      */
 335  
 
 336  
     public IParameterSpecification getParameter(String name)
 337  
     {
 338  0
         return (IParameterSpecification) get(_parameters, name);
 339  
     }
 340  
 
 341  
     public Collection getRequiredParameters()
 342  
     {
 343  0
         if (_parameters == null)
 344  0
             return Collections.EMPTY_LIST;
 345  
 
 346  0
         Collection result = new ArrayList();
 347  
 
 348  0
         Iterator i = _parameters.entrySet().iterator();
 349  0
         while (i.hasNext())
 350  
         {
 351  0
             Map.Entry entry = (Map.Entry) i.next();
 352  0
             String name = (String) entry.getKey();
 353  0
             IParameterSpecification spec = (IParameterSpecification) entry.getValue();
 354  
 
 355  0
             if (!spec.isRequired())
 356  0
                 continue;
 357  
 
 358  0
             if (!name.equals(spec.getParameterName()))
 359  0
                 continue;
 360  
 
 361  0
             result.add(spec);
 362  0
         }
 363  
 
 364  0
         return result;
 365  
     }
 366  
 
 367  
     /**
 368  
      * Returns a List of of String names of all parameters. This list is in alphabetical order.
 369  
      * 
 370  
      * @see #addParameterByName(String, IParameterSpecification)
 371  
      */
 372  
 
 373  
     public List getParameterNames()
 374  
     {
 375  0
         return sortedKeys(_parameters);
 376  
     }
 377  
 
 378  
     public void setAllowBody(boolean value)
 379  
     {
 380  0
         _allowBody = value;
 381  0
     }
 382  
 
 383  
     public void setAllowInformalParameters(boolean value)
 384  
     {
 385  0
         _allowInformalParameters = value;
 386  0
     }
 387  
 
 388  
     public void setComponentClassName(String value)
 389  
     {
 390  0
         _componentClassName = value;
 391  0
     }
 392  
 
 393  
     /**
 394  
      * @since 1.0.4
 395  
      * @throws ApplicationRuntimeException
 396  
      *             if the bean already has a specification.
 397  
      */
 398  
 
 399  
     public void addBeanSpecification(String name, IBeanSpecification specification)
 400  
     {
 401  0
         if (_beans == null)
 402  0
             _beans = new HashMap();
 403  
 
 404  0
         IBeanSpecification existing = (IBeanSpecification) _beans.get(name);
 405  
 
 406  0
         if (existing != null)
 407  0
             throw new ApplicationRuntimeException(SpecMessages.duplicateBean(name, existing),
 408  
                     specification.getLocation(), null);
 409  
 
 410  0
         claimProperty(specification.getPropertyName(), specification);
 411  
 
 412  0
         _beans.put(name, specification);
 413  0
     }
 414  
 
 415  
     /**
 416  
      * Returns the {@link IBeanSpecification}for the given name, or null if not such specification
 417  
      * exists.
 418  
      * 
 419  
      * @since 1.0.4
 420  
      */
 421  
 
 422  
     public IBeanSpecification getBeanSpecification(String name)
 423  
     {
 424  0
         return (IBeanSpecification) get(_beans, name);
 425  
     }
 426  
 
 427  
     /**
 428  
      * Returns an unmodifiable collection of the names of all beans.
 429  
      */
 430  
 
 431  
     public Collection getBeanNames()
 432  
     {
 433  0
         if (_beans == null)
 434  0
             return Collections.EMPTY_LIST;
 435  
 
 436  0
         return Collections.unmodifiableCollection(_beans.keySet());
 437  
     }
 438  
 
 439  
     /**
 440  
      * Adds the value as a reserved name. Reserved names are not allowed as the names of informal
 441  
      * parameters. Since the comparison is caseless, the value is converted to lowercase before
 442  
      * being stored.
 443  
      * 
 444  
      * @since 1.0.5
 445  
      */
 446  
 
 447  
     public void addReservedParameterName(String value)
 448  
     {
 449  0
         if (_reservedParameterNames == null)
 450  0
             _reservedParameterNames = new HashSet();
 451  
 
 452  0
         _reservedParameterNames.add(value.toLowerCase());
 453  0
     }
 454  
 
 455  
     /**
 456  
      * Returns true if the value specified is in the reserved name list. The comparison is caseless.
 457  
      * All formal parameters are automatically in the reserved name list, as well as any additional
 458  
      * reserved names specified in the component specification. The latter refer to HTML attributes
 459  
      * generated directly by the component.
 460  
      * 
 461  
      * @since 1.0.5
 462  
      */
 463  
 
 464  
     public boolean isReservedParameterName(String value)
 465  
     {
 466  0
         if (_reservedParameterNames == null)
 467  0
             return false;
 468  
 
 469  0
         return _reservedParameterNames.contains(value.toLowerCase());
 470  
     }
 471  
 
 472  
     public String toString()
 473  
     {
 474  0
         ToStringBuilder builder = new ToStringBuilder(this);
 475  
 
 476  0
         builder.append("componentClassName", _componentClassName);
 477  0
         builder.append("pageSpecification", _pageSpecification);
 478  0
         builder.append("specificationLocation", _specificationLocation);
 479  0
         builder.append("allowBody", _allowBody);
 480  0
         builder.append("allowInformalParameter", _allowInformalParameters);
 481  
 
 482  0
         return builder.toString();
 483  
     }
 484  
 
 485  
     /**
 486  
      * Returns the documentation for this component.
 487  
      * 
 488  
      * @since 1.0.9
 489  
      */
 490  
 
 491  
     public String getDescription()
 492  
     {
 493  0
         return _description;
 494  
     }
 495  
 
 496  
     /**
 497  
      * Sets the documentation for this component.
 498  
      * 
 499  
      * @since 1.0.9
 500  
      */
 501  
 
 502  
     public void setDescription(String description)
 503  
     {
 504  0
         _description = description;
 505  0
     }
 506  
 
 507  
     /**
 508  
      * Returns the XML Public Id for the specification file, or null if not applicable.
 509  
      * <p>
 510  
      * This method exists as a convienience for the Spindle plugin. A previous method used an
 511  
      * arbitrary version string, the public id is more useful and less ambiguous.
 512  
      * 
 513  
      * @since 2.2
 514  
      */
 515  
 
 516  
     public String getPublicId()
 517  
     {
 518  0
         return _publicId;
 519  
     }
 520  
 
 521  
     /** @since 2.2 * */
 522  
 
 523  
     public void setPublicId(String publicId)
 524  
     {
 525  0
         _publicId = publicId;
 526  0
     }
 527  
 
 528  
     /**
 529  
      * Returns true if the specification is known to be a page specification and not a component
 530  
      * specification. Earlier versions of the framework did not distinguish between the two, but
 531  
      * starting in 2.2, there are seperate XML entities for pages and components. Pages omit several
 532  
      * attributes and entities related to parameters, as parameters only make sense for components.
 533  
      * 
 534  
      * @since 2.2
 535  
      */
 536  
 
 537  
     public boolean isPageSpecification()
 538  
     {
 539  0
         return _pageSpecification;
 540  
     }
 541  
 
 542  
     /** @since 2.2 * */
 543  
 
 544  
     public void setPageSpecification(boolean pageSpecification)
 545  
     {
 546  0
         _pageSpecification = pageSpecification;
 547  0
     }
 548  
 
 549  
     /** @since 2.2 * */
 550  
 
 551  
     private List sortedKeys(Map input)
 552  
     {
 553  0
         if (input == null)
 554  0
             return Collections.EMPTY_LIST;
 555  
 
 556  0
         List result = new ArrayList(input.keySet());
 557  
 
 558  0
         Collections.sort(result);
 559  
 
 560  0
         return result;
 561  
     }
 562  
 
 563  
     /** @since 2.2 * */
 564  
 
 565  
     private Object get(Map map, Object key)
 566  
     {
 567  0
         if (map == null)
 568  0
             return null;
 569  
 
 570  0
         return map.get(key);
 571  
     }
 572  
 
 573  
     /** @since 3.0 * */
 574  
 
 575  
     public Resource getSpecificationLocation()
 576  
     {
 577  0
         return _specificationLocation;
 578  
     }
 579  
 
 580  
     /** @since 3.0 * */
 581  
 
 582  
     public void setSpecificationLocation(Resource specificationLocation)
 583  
     {
 584  0
         _specificationLocation = specificationLocation;
 585  0
     }
 586  
 
 587  
     /**
 588  
      * Adds a new property specification. The name of the property must not already be defined (and
 589  
      * must not change after being added).
 590  
      * 
 591  
      * @since 3.0
 592  
      */
 593  
 
 594  
     public void addPropertySpecification(IPropertySpecification spec)
 595  
     {
 596  0
         if (_propertySpecifications == null)
 597  0
             _propertySpecifications = new HashMap();
 598  
 
 599  0
         String name = spec.getName();
 600  0
         IPropertySpecification existing = (IPropertySpecification) _propertySpecifications
 601  
                 .get(name);
 602  
 
 603  0
         if (existing != null)
 604  0
             throw new ApplicationRuntimeException(SpecMessages.duplicateProperty(name, existing), spec.getLocation(), null);
 605  
 
 606  0
         claimProperty(name, spec);
 607  
 
 608  0
         _propertySpecifications.put(name, spec);
 609  0
     }
 610  
 
 611  
     /**
 612  
      * Returns a sorted, immutable list of the names of all
 613  
      * {@link org.apache.tapestry.spec.IPropertySpecification}s.
 614  
      * 
 615  
      * @since 3.0
 616  
      */
 617  
 
 618  
     public List getPropertySpecificationNames()
 619  
     {
 620  0
         return sortedKeys(_propertySpecifications);
 621  
     }
 622  
 
 623  
     /**
 624  
      * Returns the named {@link org.apache.tapestry.spec.IPropertySpecification}, or null if no
 625  
      * such specification exist.
 626  
      * 
 627  
      * @since 3.0
 628  
      * @see #addPropertySpecification(IPropertySpecification)
 629  
      */
 630  
 
 631  
     public IPropertySpecification getPropertySpecification(String name)
 632  
     {
 633  0
         return (IPropertySpecification) get(_propertySpecifications, name);
 634  
     }
 635  
 
 636  
     public void addInjectSpecification(InjectSpecification spec)
 637  
     {
 638  0
         if (_injectSpecifications == null)
 639  0
             _injectSpecifications = new ArrayList();
 640  
 
 641  0
         claimProperty(spec.getProperty(), spec);
 642  
 
 643  0
         _injectSpecifications.add(spec);
 644  0
     }
 645  
 
 646  
     public List getInjectSpecifications()
 647  
     {
 648  0
         return safeList(_injectSpecifications);
 649  
     }
 650  
 
 651  
     private List safeList(List input)
 652  
     {
 653  0
         if (input == null)
 654  0
             return Collections.EMPTY_LIST;
 655  
 
 656  0
         return Collections.unmodifiableList(input);
 657  
     }
 658  
 
 659  
     private void claimProperty(String propertyName, Object subSpecification)
 660  
     {
 661  0
         if (propertyName == null)
 662  0
             return;
 663  
 
 664  0
         if (_claimedProperties == null)
 665  0
             _claimedProperties = new HashMap();
 666  
 
 667  0
         Object existing = _claimedProperties.get(propertyName);
 668  
 
 669  0
         if (existing != null)
 670  0
             throw new ApplicationRuntimeException(SpecMessages.claimedProperty(
 671  
                     propertyName,
 672  
                     existing), HiveMind.getLocation(subSpecification), null);
 673  
 
 674  0
         _claimedProperties.put(propertyName, subSpecification);
 675  0
     }
 676  
 
 677  
     /** @since 4.0 */
 678  
     public boolean isDeprecated()
 679  
     {
 680  0
         return _deprecated;
 681  
     }
 682  
 
 683  
     /** @since 4.0 */
 684  
     public void setDeprecated(boolean deprecated)
 685  
     {
 686  0
         _deprecated = deprecated;
 687  0
     }
 688  
 
 689  
     public Set getReservedParameterNames()
 690  
     {
 691  0
         if (_reservedParameterNames == null)
 692  0
             return Collections.EMPTY_SET;
 693  
 
 694  0
         return Collections.unmodifiableSet(_reservedParameterNames);
 695  
     }
 696  
     
 697  
     /**
 698  
      * {@inheritDoc}
 699  
      */
 700  
     public void addEventListener(String componentId, String[] events, 
 701  
             String methodName, String formId, boolean validateForm, boolean async, boolean focus, boolean autoSubmit)
 702  
     {
 703  0
         ComponentEventProperty property = getComponentEvents(componentId);
 704  0
         if (property == null) {
 705  0
             property = new ComponentEventProperty(componentId);
 706  0
             _componentEvents.put(componentId, property);
 707  
         }
 708  
 
 709  0
         property.addListener(events, methodName, formId, validateForm, async, focus, autoSubmit);
 710  0
     }
 711  
     
 712  
     /**
 713  
      * {@inheritDoc}
 714  
      */
 715  
     public void addElementEventListener(String elementId, String[] events, 
 716  
             String methodName, String formId, boolean validateForm, boolean async, boolean focus)
 717  
     {
 718  0
         ComponentEventProperty property = getElementEvents(elementId);
 719  0
         if (property == null) {
 720  0
             property = new ComponentEventProperty(elementId);
 721  0
             _elementEvents.put(elementId, property);
 722  
         }
 723  
 
 724  0
         property.addListener(events, methodName, formId, validateForm, async, focus, true);
 725  0
     }
 726  
 
 727  
     public void connectAutoSubmitEvents(IComponent component, IForm form)
 728  
     {
 729  0
         Defense.notNull(form, "form");
 730  
         
 731  0
         ComponentEventProperty property = getComponentEvents(component.getExtendedId());
 732  
         
 733  0
         if (property == null)
 734  0
             return;
 735  
 
 736  0
         property.connectAutoSubmitEvents(form.getExtendedId());
 737  0
     }
 738  
 
 739  
     public void rewireComponentId(String componentId, String extendedId, String idPath)
 740  
     {
 741  0
         ComponentEventProperty prop = getComponentEvents(componentId);
 742  0
         if (prop == null)
 743  0
             return;
 744  
 
 745  0
         if (_componentEvents.containsKey(extendedId))
 746  0
             return;
 747  
 
 748  
         try {
 749  
 
 750  0
             ComponentEventProperty clone = (ComponentEventProperty) prop.clone();
 751  
 
 752  0
             clone.rewireComponentId(extendedId, idPath);
 753  
 
 754  0
             _componentEvents.put(extendedId, clone);
 755  
 
 756  0
         } catch (CloneNotSupportedException e) {
 757  
 
 758  0
             throw new ApplicationRuntimeException(e);
 759  0
         }
 760  0
     }
 761  
 
 762  
     /**
 763  
      * {@inheritDoc}
 764  
      */
 765  
     public ComponentEventProperty getComponentEvents(String id)
 766  
     {
 767  0
         return (ComponentEventProperty)_componentEvents.get(id);
 768  
     }
 769  
 
 770  
     public Map getComponentEvents()
 771  
     {
 772  0
         return _componentEvents;
 773  
     }
 774  
 
 775  
     /**
 776  
      * {@inheritDoc}
 777  
      */
 778  
     public ComponentEventProperty getElementEvents(String id)
 779  
     {
 780  0
         return (ComponentEventProperty)_elementEvents.get(id);
 781  
     }
 782  
     
 783  
     /**
 784  
      * {@inheritDoc}
 785  
      */
 786  
     public Map getElementEvents()
 787  
     {
 788  0
         return _elementEvents;
 789  
     }
 790  
     
 791  
     /**
 792  
      * {@inheritDoc}
 793  
      */
 794  
     public EventBoundListener[] getFormEvents(String formId, BrowserEvent event)
 795  
     {
 796  0
         List ret = new ArrayList();
 797  
         
 798  0
         Iterator it = _componentEvents.keySet().iterator();
 799  0
         while (it.hasNext()) {
 800  
             
 801  0
             String compId = (String)it.next();
 802  0
             ComponentEventProperty prop = (ComponentEventProperty)_componentEvents.get(compId);
 803  
 
 804  0
             ret.addAll(prop.getFormEventListeners(formId, event, null));
 805  0
         }
 806  
         
 807  0
         it = _elementEvents.keySet().iterator();
 808  0
         while (it.hasNext()) {
 809  
             
 810  0
             String compId = (String)it.next();
 811  0
             ComponentEventProperty prop = (ComponentEventProperty)_elementEvents.get(compId);
 812  
 
 813  0
             ret.addAll(prop.getFormEventListeners(formId, event, null));
 814  0
         }
 815  
         
 816  0
         return (EventBoundListener[])ret.toArray(new EventBoundListener[ret.size()]);
 817  
     }
 818  
     
 819  
     /**
 820  
      * {@inheritDoc}
 821  
      */
 822  
     public boolean hasElementEvents()
 823  
     {
 824  0
         return _elementEvents.size() > 0;
 825  
     }
 826  
 
 827  
     /**
 828  
      * {@inheritDoc}
 829  
      */
 830  
     public int hashCode()
 831  
     {
 832  0
         final int prime = 31;
 833  0
         int result = 1;
 834  0
         result = prime * result + ((_componentClassName == null) ? 0 : _componentClassName.hashCode());
 835  0
         result = prime * result + ((_description == null) ? 0 : _description.hashCode());
 836  0
         result = prime * result + (_pageSpecification ? 1231 : 1237);
 837  0
         result = prime * result + ((_publicId == null) ? 0 : _publicId.hashCode());
 838  0
         return result;
 839  
     }
 840  
 
 841  
     /**
 842  
      * {@inheritDoc}
 843  
      */
 844  
     public boolean equals(Object obj)
 845  
     {
 846  0
         if (this == obj) return true;
 847  0
         if (obj == null) return false;
 848  0
         if (getClass() != obj.getClass()) return false;
 849  0
         final ComponentSpecification other = (ComponentSpecification) obj;
 850  0
         if (_componentClassName == null) {
 851  0
             if (other._componentClassName != null) return false;
 852  0
         } else if (!_componentClassName.equals(other._componentClassName)) return false;
 853  0
         if (_description == null) {
 854  0
             if (other._description != null) return false;
 855  0
         } else if (!_description.equals(other._description)) return false;
 856  0
         if (_pageSpecification != other._pageSpecification) return false;
 857  0
         if (_publicId == null) {
 858  0
             if (other._publicId != null) return false;
 859  0
         } else if (!_publicId.equals(other._publicId)) return false;
 860  0
         if (_specificationLocation == null) {
 861  0
             if (other._specificationLocation != null) return false;
 862  0
         } else if (!_specificationLocation.getPath().equals(other._specificationLocation.getPath())) return false;
 863  0
         return true;
 864  
     }
 865  
     
 866  
     
 867  
 }