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: 769   Methods: 44
NCLOC: 339   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
AbstractComponent.java 75% 89% 93.2% 86.2%
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;
 16   
 
 17   
 import java.util.Collection;
 18   
 import java.util.Collections;
 19   
 import java.util.HashMap;
 20   
 import java.util.HashSet;
 21   
 import java.util.Iterator;
 22   
 import java.util.List;
 23   
 import java.util.Map;
 24   
 
 25   
 import org.apache.hivemind.ApplicationRuntimeException;
 26   
 import org.apache.hivemind.Messages;
 27   
 import org.apache.hivemind.impl.BaseLocatable;
 28   
 import org.apache.hivemind.util.Defense;
 29   
 import org.apache.hivemind.util.PropertyUtils;
 30   
 import org.apache.tapestry.bean.BeanProvider;
 31   
 import org.apache.tapestry.engine.IPageLoader;
 32   
 import org.apache.tapestry.event.PageEvent;
 33   
 import org.apache.tapestry.listener.ListenerMap;
 34   
 import org.apache.tapestry.spec.IComponentSpecification;
 35   
 
 36   
 /**
 37   
  * Abstract base class implementing the {@link IComponent}interface.
 38   
  * 
 39   
  * @author Howard Lewis Ship
 40   
  */
 41   
 
 42   
 public abstract class AbstractComponent extends BaseLocatable implements IComponent
 43   
 {
 44   
     /**
 45   
      * The page that contains the component, possibly itself (if the component is in fact, a page).
 46   
      */
 47   
 
 48   
     private IPage _page;
 49   
 
 50   
     /**
 51   
      * The component which contains the component. This will only be null if the component is
 52   
      * actually a page.
 53   
      */
 54   
 
 55   
     private IComponent _container;
 56   
 
 57   
     /**
 58   
      * The simple id of this component.
 59   
      */
 60   
 
 61   
     private String _id;
 62   
 
 63   
     /**
 64   
      * The fully qualified id of this component. This is calculated the first time it is needed,
 65   
      * then cached for later.
 66   
      */
 67   
 
 68   
     private String _idPath;
 69   
 
 70   
     private static final int MAP_SIZE = 5;
 71   
 
 72   
     /**
 73   
      * A {@link Map}of all bindings (for which there isn't a corresponding JavaBeans property); the
 74   
      * keys are the names of formal and informal parameters.
 75   
      */
 76   
 
 77   
     private Map _bindings;
 78   
 
 79   
     private Map _components;
 80   
 
 81   
     private static final int BODY_INIT_SIZE = 5;
 82   
 
 83   
     private INamespace _namespace;
 84   
 
 85   
     /**
 86   
      * Used in place of JDK 1.3's Collections.EMPTY_MAP (which is not available in JDK 1.2).
 87   
      */
 88   
 
 89   
     private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap(1));
 90   
 
 91   
     /**
 92   
      * The number of {@link IRender}objects in the body of this component.
 93   
      */
 94   
 
 95   
     private int _bodyCount = 0;
 96   
 
 97   
     /**
 98   
      * An aray of elements in the body of this component.
 99   
      */
 100   
 
 101   
     private IRender[] _body;
 102   
 
 103   
     /**
 104   
      * The components' asset map.
 105   
      */
 106   
 
 107   
     private Map _assets;
 108   
 
 109   
     /**
 110   
      * A mapping that allows public instance methods to be dressed up as {@link IActionListener}
 111   
      * listener objects.
 112   
      * 
 113   
      * @since 1.0.2
 114   
      */
 115   
 
 116   
     private ListenerMap _listeners;
 117   
 
 118   
     /**
 119   
      * A bean provider; these are lazily created as needed.
 120   
      * 
 121   
      * @since 1.0.4
 122   
      */
 123   
 
 124   
     private IBeanProvider _beans;
 125   
 
 126   
     /**
 127   
      * Returns true if the component is currently rendering.
 128   
      * 
 129   
      * @see #prepareForRender(IRequestCycle)
 130   
      * @see #cleanupAfterRender(IRequestCycle)
 131   
      * @since 4.0
 132   
      */
 133   
 
 134   
     private boolean _rendering;
 135   
 
 136   
     /**
 137   
      * @since 4.0
 138   
      */
 139   
 
 140   
     private boolean _active;
 141   
 
 142  60
     public void addAsset(String name, IAsset asset)
 143   
     {
 144  60
         Defense.notNull(name, "name");
 145  60
         Defense.notNull(asset, "asset");
 146   
 
 147  60
         checkActiveLock();
 148   
 
 149  60
         if (_assets == null)
 150  56
             _assets = new HashMap(MAP_SIZE);
 151   
 
 152  60
         _assets.put(name, asset);
 153   
     }
 154   
 
 155  1024
     public void addComponent(IComponent component)
 156   
     {
 157  1024
         Defense.notNull(component, "component");
 158   
 
 159  1024
         checkActiveLock();
 160   
 
 161  1024
         if (_components == null)
 162  219
             _components = new HashMap(MAP_SIZE);
 163   
 
 164  1024
         _components.put(component.getId(), component);
 165   
     }
 166   
 
 167   
     /**
 168   
      * Adds an element (which may be static text or a component) as a body element of this
 169   
      * component. Such elements are rendered by {@link #renderBody(IMarkupWriter, IRequestCycle)}.
 170   
      * 
 171   
      * @since 2.2
 172   
      */
 173   
 
 174  1871
     public void addBody(IRender element)
 175   
     {
 176  1871
         Defense.notNull(element, "element");
 177   
 
 178   
         // TODO: Tweak the ordering of operations inside the PageLoader so that this
 179   
         // check is allowable. Currently, the component is entering active state
 180   
         // before it loads its template.
 181   
 
 182   
         // checkActiveLock();
 183   
 
 184   
         // Should check the specification to see if this component
 185   
         // allows body. Curently, this is checked by the component
 186   
         // in render(), which is silly.
 187   
 
 188  1871
         if (_body == null)
 189   
         {
 190  521
             _body = new IRender[BODY_INIT_SIZE];
 191  521
             _body[0] = element;
 192   
 
 193  521
             _bodyCount = 1;
 194  521
             return;
 195   
         }
 196   
 
 197   
         // No more room? Make the array bigger.
 198   
 
 199  1350
         if (_bodyCount == _body.length)
 200   
         {
 201  110
             IRender[] newWrapped;
 202   
 
 203  110
             newWrapped = new IRender[_body.length * 2];
 204   
 
 205  110
             System.arraycopy(_body, 0, newWrapped, 0, _bodyCount);
 206   
 
 207  110
             _body = newWrapped;
 208   
         }
 209   
 
 210  1350
         _body[_bodyCount++] = element;
 211   
     }
 212   
 
 213   
     /**
 214   
      * Invokes {@link #finishLoad()}. Subclasses may overide as needed, but must invoke this
 215   
      * implementation. {@link BaseComponent}loads its HTML template.
 216   
      */
 217   
 
 218  1151
     public void finishLoad(IRequestCycle cycle, IPageLoader loader,
 219   
             IComponentSpecification specification)
 220   
     {
 221  1151
         finishLoad();
 222   
     }
 223   
 
 224   
     /**
 225   
      * Converts informal parameters into additional attributes on the curently open tag.
 226   
      * <p>
 227   
      * Invoked from subclasses to allow additional attributes to be specified within a tag (this
 228   
      * works best when there is a one-to-one corespondence between an {@link IComponent}and a HTML
 229   
      * element.
 230   
      * <p>
 231   
      * Iterates through the bindings for this component. Filters out bindings for formal parameters.
 232   
      * <p>
 233   
      * For each acceptible key, the value is extracted using {@link IBinding#getObject()}. If the
 234   
      * value is null, no attribute is written.
 235   
      * <p>
 236   
      * If the value is an instance of {@link IAsset}, then {@link IAsset#buildURL(IRequestCycle)}
 237   
      * is invoked to convert the asset to a URL.
 238   
      * <p>
 239   
      * Finally, {@link IMarkupWriter#attribute(String,String)}is invoked with the value (or the
 240   
      * URL).
 241   
      * <p>
 242   
      * The most common use for informal parameters is to support the HTML class attribute (for use
 243   
      * with cascading style sheets) and to specify JavaScript event handlers.
 244   
      * <p>
 245   
      * Components are only required to generate attributes on the result phase; this can be skipped
 246   
      * during the rewind phase.
 247   
      */
 248   
 
 249  1772
     protected void renderInformalParameters(IMarkupWriter writer, IRequestCycle cycle)
 250   
     {
 251  1772
         String attribute;
 252   
 
 253  1772
         if (_bindings == null)
 254  98
             return;
 255   
 
 256  1674
         Iterator i = _bindings.entrySet().iterator();
 257   
 
 258  1674
         while (i.hasNext())
 259   
         {
 260  4765
             Map.Entry entry = (Map.Entry) i.next();
 261  4765
             String name = (String) entry.getKey();
 262   
 
 263  4765
             if (isFormalParameter(name))
 264  4676
                 continue;
 265   
 
 266  89
             IBinding binding = (IBinding) entry.getValue();
 267   
 
 268  89
             Object value = binding.getObject();
 269  89
             if (value == null)
 270  0
                 continue;
 271   
 
 272  89
             if (value instanceof IAsset)
 273   
             {
 274  0
                 IAsset asset = (IAsset) value;
 275   
 
 276   
                 // Get the URL of the asset and insert that.
 277   
 
 278  0
                 attribute = asset.buildURL(cycle);
 279   
             }
 280   
             else
 281  89
                 attribute = value.toString();
 282   
 
 283  89
             writer.attribute(name, attribute);
 284   
         }
 285   
 
 286   
     }
 287   
 
 288   
     /** @since 4.0 */
 289  4765
     private boolean isFormalParameter(String name)
 290   
     {
 291  4765
         Defense.notNull(name, "name");
 292   
 
 293  4765
         return getSpecification().getParameter(name) != null;
 294   
     }
 295   
 
 296   
     /**
 297   
      * Returns the named binding, or null if it doesn't exist.
 298   
      * <p>
 299   
      * In Tapestry 3.0, it was possible to force a binding to be stored in a component property by
 300   
      * defining a concrete or abstract property named "nameBinding" of type {@link IBinding}. This
 301   
      * has been removed in release 4.0 and bindings are always stored inside a Map of the component.
 302   
      * 
 303   
      * @see #setBinding(String,IBinding)
 304   
      */
 305   
 
 306  21921
     public IBinding getBinding(String name)
 307   
     {
 308  21921
         Defense.notNull(name, "name");
 309   
 
 310  21921
         if (_bindings == null)
 311  748
             return null;
 312   
 
 313  21173
         return (IBinding) _bindings.get(name);
 314   
     }
 315   
 
 316   
     /**
 317   
      * Returns true if the specified parameter is bound.
 318   
      * 
 319   
      * @since 4.0
 320   
      */
 321   
 
 322  190
     public boolean isParameterBound(String parameterName)
 323   
     {
 324  190
         Defense.notNull(parameterName, "parameterName");
 325   
 
 326  190
         return _bindings != null && _bindings.containsKey(parameterName);
 327   
     }
 328   
 
 329  776
     public IComponent getComponent(String id)
 330   
     {
 331  776
         Defense.notNull(id, "id");
 332   
 
 333  776
         IComponent result = null;
 334   
 
 335  776
         if (_components != null)
 336  776
             result = (IComponent) _components.get(id);
 337   
 
 338  776
         if (result == null)
 339  0
             throw new ApplicationRuntimeException(Tapestry.format("no-such-component", this, id),
 340   
                     this, null, null);
 341   
 
 342  776
         return result;
 343   
     }
 344   
 
 345  34
     public IComponent getContainer()
 346   
     {
 347  34
         return _container;
 348   
     }
 349   
 
 350  1027
     public void setContainer(IComponent value)
 351   
     {
 352  1027
         checkActiveLock();
 353   
 
 354  1027
         if (_container != null)
 355  0
             throw new ApplicationRuntimeException(Tapestry
 356   
                     .getMessage("AbstractComponent.attempt-to-change-container"));
 357   
 
 358  1027
         _container = value;
 359   
     }
 360   
 
 361   
     /**
 362   
      * Returns the name of the page, a slash, and this component's id path. Pages are different,
 363   
      * they override this method to simply return their page name.
 364   
      * 
 365   
      * @see #getIdPath()
 366   
      */
 367   
 
 368  196
     public String getExtendedId()
 369   
     {
 370  196
         if (_page == null)
 371  37
             return null;
 372   
 
 373  159
         return _page.getPageName() + "/" + getIdPath();
 374   
     }
 375   
 
 376  1192
     public String getId()
 377   
     {
 378  1192
         return _id;
 379   
     }
 380   
 
 381  1027
     public void setId(String value)
 382   
     {
 383  1027
         if (_id != null)
 384  0
             throw new ApplicationRuntimeException(Tapestry
 385   
                     .getMessage("AbstractComponent.attempt-to-change-component-id"));
 386   
 
 387  1027
         _id = value;
 388   
     }
 389   
 
 390  283
     public String getIdPath()
 391   
     {
 392  283
         String containerIdPath;
 393   
 
 394  283
         if (_container == null)
 395  0
             throw new NullPointerException(Tapestry
 396   
                     .format("AbstractComponent.null-container", this));
 397   
 
 398  283
         containerIdPath = _container.getIdPath();
 399   
 
 400  283
         if (containerIdPath == null)
 401  275
             _idPath = _id;
 402   
         else
 403  8
             _idPath = containerIdPath + "." + _id;
 404   
 
 405  283
         return _idPath;
 406   
     }
 407   
 
 408  1470
     public IPage getPage()
 409   
     {
 410  1470
         return _page;
 411   
     }
 412   
 
 413  1181
     public void setPage(IPage value)
 414   
     {
 415  1181
         if (_page != null)
 416  0
             throw new ApplicationRuntimeException(Tapestry
 417   
                     .getMessage("AbstractComponent.attempt-to-change-page"));
 418   
 
 419  1181
         _page = value;
 420   
     }
 421   
 
 422   
     /**
 423   
      * Renders all elements wrapped by the receiver.
 424   
      */
 425   
 
 426  2000
     public void renderBody(IMarkupWriter writer, IRequestCycle cycle)
 427   
     {
 428  2000
         for (int i = 0; i < _bodyCount; i++)
 429  5337
             _body[i].render(writer, cycle);
 430   
     }
 431   
 
 432   
     /**
 433   
      * Adds the binding with the given name, replacing any existing binding with that name.
 434   
      * <p>
 435   
      * 
 436   
      * @see #getBinding(String)
 437   
      */
 438   
 
 439  1637
     public void setBinding(String name, IBinding binding)
 440   
     {
 441  1637
         Defense.notNull(name, "name");
 442  1637
         Defense.notNull(binding, "binding");
 443   
 
 444  1637
         if (_bindings == null)
 445  903
             _bindings = new HashMap(MAP_SIZE);
 446   
 
 447  1637
         _bindings.put(name, binding);
 448   
     }
 449   
 
 450  86
     public String toString()
 451   
     {
 452  86
         StringBuffer buffer;
 453   
 
 454  86
         buffer = new StringBuffer(super.toString());
 455   
 
 456  86
         buffer.append('[');
 457   
 
 458  86
         buffer.append(getExtendedId());
 459   
 
 460  86
         buffer.append(']');
 461   
 
 462  86
         return buffer.toString();
 463   
     }
 464   
 
 465   
     /**
 466   
      * Returns an unmodifiable {@link Map}of components, keyed on component id. Never returns null,
 467   
      * but may return an empty map. The returned map is immutable.
 468   
      */
 469   
 
 470  2523
     public Map getComponents()
 471   
     {
 472  2523
         if (_components == null)
 473  1859
             return EMPTY_MAP;
 474   
 
 475  664
         return Collections.unmodifiableMap(_components);
 476   
 
 477   
     }
 478   
 
 479  32
     public Map getAssets()
 480   
     {
 481  32
         if (_assets == null)
 482  0
             return EMPTY_MAP;
 483   
 
 484  32
         return Collections.unmodifiableMap(_assets);
 485   
     }
 486   
 
 487  211
     public IAsset getAsset(String name)
 488   
     {
 489  211
         if (_assets == null)
 490  151
             return null;
 491   
 
 492  60
         return (IAsset) _assets.get(name);
 493   
     }
 494   
 
 495  1
     public Collection getBindingNames()
 496   
     {
 497   
         // If no conainer, i.e. a page, then no bindings.
 498   
 
 499  1
         if (_container == null)
 500  0
             return null;
 501   
 
 502  1
         HashSet result = new HashSet();
 503   
 
 504   
         // All the informal bindings go into the bindings Map.
 505   
 
 506  1
         if (_bindings != null)
 507  1
             result.addAll(_bindings.keySet());
 508   
 
 509   
         // Now, iterate over the formal parameters and add the formal parameters
 510   
         // that have a binding.
 511   
 
 512  1
         List names = getSpecification().getParameterNames();
 513   
 
 514  1
         int count = names.size();
 515   
 
 516  1
         for (int i = 0; i < count; i++)
 517   
         {
 518  1
             String name = (String) names.get(i);
 519   
 
 520  1
             if (result.contains(name))
 521  1
                 continue;
 522   
 
 523  0
             if (getBinding(name) != null)
 524  0
                 result.add(name);
 525   
         }
 526   
 
 527  1
         return result;
 528   
     }
 529   
 
 530   
     /**
 531   
      * Returns an unmodifiable {@link Map}of all bindings for this component.
 532   
      * 
 533   
      * @since 1.0.5
 534   
      */
 535   
 
 536  3
     public Map getBindings()
 537   
     {
 538  3
         if (_bindings == null)
 539  0
             return Collections.EMPTY_MAP;
 540   
 
 541  3
         return Collections.unmodifiableMap(_bindings);
 542   
     }
 543   
 
 544   
     /**
 545   
      * Returns a {@link ListenerMap}&nbsp;for the component. A ListenerMap contains a number of
 546   
      * synthetic read-only properties that implement the {@link IActionListener}interface, but in
 547   
      * fact, cause public instance methods to be invoked.
 548   
      * 
 549   
      * @since 1.0.2
 550   
      */
 551   
 
 552  34
     public ListenerMap getListeners()
 553   
     {
 554   
         // This is what's called a violation of the Law of Demeter!
 555   
         // This should probably be converted over to some kind of injection, as with
 556   
         // getMessages(), etc.
 557   
 
 558  34
         if (_listeners == null)
 559  28
             _listeners = getPage().getEngine().getInfrastructure().getListenerMapSource()
 560   
                     .getListenerMapForObject(this);
 561   
 
 562  34
         return _listeners;
 563   
     }
 564   
 
 565   
     /**
 566   
      * Returns the {@link IBeanProvider}for this component. This is lazily created the first time
 567   
      * it is needed.
 568   
      * 
 569   
      * @since 1.0.4
 570   
      */
 571   
 
 572  142
     public IBeanProvider getBeans()
 573   
     {
 574  142
         if (_beans == null)
 575  55
             _beans = new BeanProvider(this);
 576   
 
 577  142
         return _beans;
 578   
     }
 579   
 
 580   
     /**
 581   
      * Invoked, as a convienience, from
 582   
      * {@link #finishLoad(IRequestCycle, IPageLoader, IComponentSpecification)}. This implemenation
 583   
      * does nothing. Subclasses may override without invoking this implementation.
 584   
      * 
 585   
      * @since 1.0.5
 586   
      */
 587   
 
 588  1002
     protected void finishLoad()
 589   
     {
 590   
     }
 591   
 
 592   
     /**
 593   
      * The main method used to render the component. Invokes
 594   
      * {@link #prepareForRender(IRequestCycle)}, then
 595   
      * {@link #renderComponent(IMarkupWriter, IRequestCycle)}.
 596   
      * {@link #cleanupAfterRender(IRequestCycle)}is invoked in a <code>finally</code> block.
 597   
      * <p>
 598   
      * Subclasses should not override this method; instead they will implement
 599   
      * {@link #renderComponent(IMarkupWriter, IRequestCycle)}.
 600   
      * 
 601   
      * @since 2.0.3
 602   
      */
 603   
 
 604  2941
     public final void render(IMarkupWriter writer, IRequestCycle cycle)
 605   
     {
 606  2941
         try
 607   
         {
 608  2941
             _rendering = true;
 609   
 
 610  2941
             prepareForRender(cycle);
 611   
 
 612  2941
             renderComponent(writer, cycle);
 613   
         }
 614   
         finally
 615   
         {
 616  2941
             _rendering = false;
 617   
 
 618  2941
             cleanupAfterRender(cycle);
 619   
         }
 620   
     }
 621   
 
 622   
     /**
 623   
      * Invoked by {@link #render(IMarkupWriter, IRequestCycle)}to prepare the component to render.
 624   
      * This implementation sets JavaBeans properties from matching bound parameters. This
 625   
      * implementation does nothing.
 626   
      * 
 627   
      * @since 2.0.3
 628   
      */
 629   
 
 630  2853
     protected void prepareForRender(IRequestCycle cycle)
 631   
     {
 632   
     }
 633   
 
 634   
     /**
 635   
      * Invoked by {@link #render(IMarkupWriter, IRequestCycle)}to actually render the component
 636   
      * (with any parameter values already set). This is the method that subclasses must implement.
 637   
      * 
 638   
      * @since 2.0.3
 639   
      */
 640   
 
 641   
     protected abstract void renderComponent(IMarkupWriter writer, IRequestCycle cycle);
 642   
 
 643   
     /**
 644   
      * Invoked by {@link #render(IMarkupWriter, IRequestCycle)}after the component renders. This
 645   
      * implementation does nothing.
 646   
      * 
 647   
      * @since 2.0.3
 648   
      */
 649   
 
 650  2853
     protected void cleanupAfterRender(IRequestCycle cycle)
 651   
     {
 652   
     }
 653   
 
 654  1495
     public INamespace getNamespace()
 655   
     {
 656  1495
         return _namespace;
 657   
     }
 658   
 
 659  1178
     public void setNamespace(INamespace namespace)
 660   
     {
 661  1178
         _namespace = namespace;
 662   
     }
 663   
 
 664   
     /**
 665   
      * Returns the body of the component, the element (which may be static HTML or components) that
 666   
      * the component immediately wraps. May return null. Do not modify the returned array. The array
 667   
      * may be padded with nulls.
 668   
      * 
 669   
      * @since 2.3
 670   
      * @see #getBodyCount()
 671   
      */
 672   
 
 673  0
     public IRender[] getBody()
 674   
     {
 675  0
         return _body;
 676   
     }
 677   
 
 678   
     /**
 679   
      * Returns the active number of elements in the the body, which may be zero.
 680   
      * 
 681   
      * @since 2.3
 682   
      * @see #getBody()
 683   
      */
 684   
 
 685  0
     public int getBodyCount()
 686   
     {
 687  0
         return _bodyCount;
 688   
     }
 689   
 
 690   
     /**
 691   
      * Empty implementation of
 692   
      * {@link org.apache.tapestry.event.PageRenderListener#pageEndRender(PageEvent)}. This allows
 693   
      * classes to implement {@link org.apache.tapestry.event.PageRenderListener}and only implement
 694   
      * the {@link org.apache.tapestry.event.PageRenderListener#pageBeginRender(PageEvent)}method.
 695   
      * 
 696   
      * @since 3.0
 697   
      */
 698   
 
 699  0
     public void pageEndRender(PageEvent event)
 700   
     {
 701   
     }
 702   
 
 703   
     /**
 704   
      * Sets a property of a component.
 705   
      * 
 706   
      * @see IComponent
 707   
      * @since 3.0
 708   
      */
 709  28
     public void setProperty(String propertyName, Object value)
 710   
     {
 711  28
         PropertyUtils.write(this, propertyName, value);
 712   
     }
 713   
 
 714   
     /**
 715   
      * Gets a property of a component.
 716   
      * 
 717   
      * @see IComponent
 718   
      * @since 3.0
 719   
      */
 720  2
     public Object getProperty(String propertyName)
 721   
     {
 722  2
         return PropertyUtils.read(this, propertyName);
 723   
     }
 724   
 
 725   
     /**
 726   
      * @since 4.0
 727   
      */
 728   
 
 729  4430
     public boolean isRendering()
 730   
     {
 731  4430
         return _rendering;
 732   
     }
 733   
 
 734   
     /**
 735   
      * Returns true if the component has been transitioned into its active state by invoking
 736   
      * {@link #enterActiveState()}
 737   
      * 
 738   
      * @since 4.0
 739   
      */
 740   
 
 741  1567
     protected boolean isInActiveState()
 742   
     {
 743  1567
         return _active;
 744   
     }
 745   
 
 746   
     /** @since 4.0 */
 747  1151
     public void enterActiveState()
 748   
     {
 749  1151
         _active = true;
 750   
     }
 751   
 
 752   
     /** @since 4.0 */
 753   
 
 754  2111
     protected void checkActiveLock()
 755   
     {
 756  2111
         if (_active)
 757  0
             throw new UnsupportedOperationException(TapestryMessages.componentIsLocked(this));
 758   
     }
 759   
 
 760  1
     public Messages getMessages()
 761   
     {
 762  1
         throw new IllegalStateException(TapestryMessages.providedByEnhancement("getMessages"));
 763   
     }
 764   
 
 765  1
     public IComponentSpecification getSpecification()
 766   
     {
 767  1
         throw new IllegalStateException(TapestryMessages.providedByEnhancement("getSpecification"));
 768   
     }
 769   
 }