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