Clover coverage report - Code Coverage for tapestry release 4.0-beta-1
Coverage timestamp: Fri Jun 24 2005 14:32:46 EDT
file stats: LOC: 596   Methods: 42
NCLOC: 308   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
AbstractPage.java 80% 91.3% 92.9% 88.6%
coverage coverage
 1    // Copyright 2004, 2005 The Apache Software Foundation
 2    //
 3    // Licensed under the Apache License, Version 2.0 (the "License");
 4    // you may not use this file except in compliance with the License.
 5    // You may obtain a copy of the License at
 6    //
 7    // http://www.apache.org/licenses/LICENSE-2.0
 8    //
 9    // Unless required by applicable law or agreed to in writing, software
 10    // distributed under the License is distributed on an "AS IS" BASIS,
 11    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    // See the License for the specific language governing permissions and
 13    // limitations under the License.
 14   
 15    package org.apache.tapestry;
 16   
 17    import java.util.EventListener;
 18    import java.util.Locale;
 19   
 20    import javax.swing.event.EventListenerList;
 21   
 22    import org.apache.commons.logging.Log;
 23    import org.apache.commons.logging.LogFactory;
 24    import org.apache.hivemind.ApplicationRuntimeException;
 25    import org.apache.tapestry.event.ChangeObserver;
 26    import org.apache.tapestry.event.PageBeginRenderListener;
 27    import org.apache.tapestry.event.PageDetachListener;
 28    import org.apache.tapestry.event.PageEndRenderListener;
 29    import org.apache.tapestry.event.PageEvent;
 30    import org.apache.tapestry.event.PageAttachListener;
 31    import org.apache.tapestry.event.PageRenderListener;
 32    import org.apache.tapestry.event.PageValidateListener;
 33    import org.apache.tapestry.util.StringSplitter;
 34   
 35    /**
 36    * Abstract base class implementing the {@link IPage}interface.
 37    *
 38    * @author Howard Lewis Ship, David Solis
 39    * @since 0.2.9
 40    */
 41   
 42    public abstract class AbstractPage extends BaseComponent implements IPage
 43    {
 44    private static final Log LOG = LogFactory.getLog(AbstractPage.class);
 45   
 46    /**
 47    * Object to be notified when a observered property changes. Observered properties are the ones
 48    * that will be persisted between request cycles. Unobserved properties are reconstructed.
 49    */
 50   
 51    private ChangeObserver _changeObserver;
 52   
 53    /**
 54    * The {@link IEngine}the page is currently attached to.
 55    */
 56   
 57    private IEngine _engine;
 58   
 59    /**
 60    * The visit object, if any, for the application. Set inside {@link #attach(IEngine)}and
 61    * cleared by {@link #detach()}.
 62    */
 63   
 64    private Object _visit;
 65   
 66    /**
 67    * The qualified name of the page, which may be prefixed by the namespace.
 68    *
 69    * @since 2.3
 70    */
 71   
 72    private String _pageName;
 73   
 74    /**
 75    * Set when the page is attached to the engine.
 76    */
 77   
 78    private IRequestCycle _requestCycle;
 79   
 80    /**
 81    * The locale of the page, initially determined from the {@link IEngine engine}.
 82    */
 83   
 84    private Locale _locale;
 85   
 86    /**
 87    * A list of listeners for the page.
 88    *
 89    * @see PageRenderListener
 90    * @see PageDetachListener
 91    * @since 1.0.5
 92    */
 93   
 94    private EventListenerList _listenerList;
 95   
 96    /**
 97    * The output encoding to be used when rendering this page. This value is cached from the
 98    * engine.
 99    *
 100    * @since 3.0
 101    */
 102    private String _outputEncoding;
 103   
 104    /**
 105    * Standard constructor; invokes {@link #initialize()}to configure initial values for
 106    * properties of the page.
 107    *
 108    * @since 2.2
 109    */
 110   
 111  157 public AbstractPage()
 112    {
 113  157 initialize();
 114    }
 115   
 116    /**
 117    * Prepares the page to be returned to the pool.
 118    * <ul>
 119    * <li>Clears the changeObserved property
 120    * <li>Invokes {@link PageDetachListener#pageDetached(PageEvent)}on all listeners
 121    * <li>Invokes {@link #initialize()}to clear/reset any properties
 122    * <li>Clears the engine, visit and requestCycle properties
 123    * </ul>
 124    * <p>
 125    * Subclasses may override this method, but must invoke this implementation (usually, last).
 126    * @see PageDetachListener
 127    */
 128   
 129  190 public void detach()
 130    {
 131  190 Tapestry.addMethodInvocation(Tapestry.ABSTRACTPAGE_DETACH_METHOD_ID);
 132   
 133    // Do this first,so that any changes to persistent properties do not
 134    // cause errors.
 135   
 136  190 _changeObserver = null;
 137   
 138  190 firePageDetached();
 139   
 140  190 initialize();
 141   
 142  190 _engine = null;
 143  190 _visit = null;
 144  190 _requestCycle = null;
 145    }
 146   
 147    /**
 148    * Method invoked from the constructor, and from {@link #detach()}to (re-)initialize properties
 149    * of the page. This is most useful when properties have non-null initial values.
 150    * <p>
 151    * Subclasses may override this implementation (which is empty).
 152    *
 153    * @since 2.2
 154    * @deprecated To be removed in 4.1 with no replacement.
 155    * @see PageDetachListener
 156    * @see PageAttachListener
 157    */
 158   
 159  334 protected void initialize()
 160    {
 161    // Does nothing.
 162    }
 163   
 164  79 public IEngine getEngine()
 165    {
 166  79 return _engine;
 167    }
 168   
 169  31 public ChangeObserver getChangeObserver()
 170    {
 171  31 return _changeObserver;
 172    }
 173   
 174    /**
 175    * Returns the name of the page.
 176    */
 177   
 178  22 public String getExtendedId()
 179    {
 180  22 return _pageName;
 181    }
 182   
 183    /**
 184    * Pages always return null for idPath.
 185    */
 186   
 187  236 public String getIdPath()
 188    {
 189  236 return null;
 190    }
 191   
 192    /**
 193    * Returns the locale for the page, which may be null if the locale is not known (null
 194    * corresponds to the "default locale").
 195    */
 196   
 197  472 public Locale getLocale()
 198    {
 199  472 return _locale;
 200    }
 201   
 202  144 public void setLocale(Locale value)
 203    {
 204  144 if (_locale != null)
 205  0 throw new ApplicationRuntimeException(Tapestry
 206    .getMessage("AbstractPage.attempt-to-change-locale"));
 207   
 208  144 _locale = value;
 209    }
 210   
 211  55 public IComponent getNestedComponent(String path)
 212    {
 213  55 StringSplitter splitter;
 214  55 IComponent current;
 215  55 String[] elements;
 216  55 int i;
 217   
 218  55 if (path == null)
 219  0 return this;
 220   
 221  55 splitter = new StringSplitter('.');
 222  55 current = this;
 223   
 224  55 elements = splitter.splitToArray(path);
 225  55 for (i = 0; i < elements.length; i++)
 226    {
 227  55 current = current.getComponent(elements[i]);
 228    }
 229   
 230  55 return current;
 231   
 232    }
 233   
 234    /**
 235    * Called by the {@link IEngine engine}to attach the page to itself. Does <em>not</em> change
 236    * the locale, but since a page is selected from the
 237    * {@link org.apache.tapestry.engine.IPageSource}pool based on its locale matching the engine's
 238    * locale, they should match anyway.
 239    */
 240   
 241  191 public void attach(IEngine engine, IRequestCycle cycle)
 242    {
 243  191 if (_engine != null)
 244  0 LOG.error(this + " attach(" + engine + "), but engine = " + _engine);
 245   
 246  191 _engine = engine;
 247  191 _requestCycle = cycle;
 248   
 249  191 firePageAttached();
 250    }
 251   
 252    /**
 253    * <ul>
 254    * <li>Invokes {@link PageRenderListener#pageBeginRender(PageEvent)}
 255    * <li>Invokes {@link #beginResponse(IMarkupWriter, IRequestCycle)}
 256    * <li>Invokes {@link IRequestCycle#commitPageChanges()}(if not rewinding)
 257    * <li>Invokes {@link #render(IMarkupWriter, IRequestCycle)}
 258    * <li>Invokes {@link PageRenderListener#pageEndRender(PageEvent)}(this occurs even if a
 259    * previous step throws an exception)
 260    */
 261   
 262  151 public void renderPage(IMarkupWriter writer, IRequestCycle cycle)
 263    {
 264  151 try
 265    {
 266  151 firePageBeginRender();
 267   
 268  151 beginResponse(writer, cycle);
 269   
 270  151 if (!cycle.isRewinding())
 271  140 cycle.commitPageChanges();
 272   
 273  151 render(writer, cycle);
 274    }
 275    finally
 276    {
 277  151 firePageEndRender();
 278    }
 279    }
 280   
 281  187 public void setChangeObserver(ChangeObserver value)
 282    {
 283  187 _changeObserver = value;
 284    }
 285   
 286    /** @since 3.0 * */
 287   
 288  130 public void setPageName(String pageName)
 289    {
 290  130 if (_pageName != null)
 291  0 throw new ApplicationRuntimeException(Tapestry
 292    .getMessage("AbstractPage.attempt-to-change-name"));
 293   
 294  130 _pageName = pageName;
 295    }
 296   
 297    /**
 298    * By default, pages are not protected and this method does nothing.
 299    */
 300   
 301  188 public void validate(IRequestCycle cycle)
 302    {
 303  188 Tapestry.addMethodInvocation(Tapestry.ABSTRACTPAGE_VALIDATE_METHOD_ID);
 304   
 305  188 firePageValidate();
 306    }
 307   
 308    /**
 309    * Does nothing, subclasses may override as needed.
 310    *
 311    * @deprecated To be removed in 4.0. Implement {@link PageRenderListener}instead.
 312    */
 313   
 314  151 public void beginResponse(IMarkupWriter writer, IRequestCycle cycle)
 315    {
 316    }
 317   
 318  3 public IRequestCycle getRequestCycle()
 319    {
 320  3 return _requestCycle;
 321    }
 322   
 323    /**
 324    * Returns the visit object obtained from the engine via {@link IEngine#getVisit(IRequestCycle)}.
 325    */
 326   
 327  1 public Object getVisit()
 328    {
 329  1 if (_visit == null)
 330  1 _visit = _engine.getVisit(_requestCycle);
 331   
 332  1 return _visit;
 333    }
 334   
 335    /**
 336    * Convienience methods, simply invokes {@link IEngine#getGlobal()}.
 337    *
 338    * @since 2.3
 339    */
 340   
 341  1 public Object getGlobal()
 342    {
 343  1 return _engine.getGlobal();
 344    }
 345   
 346  123 public void addPageDetachListener(PageDetachListener listener)
 347    {
 348  123 addListener(PageDetachListener.class, listener);
 349    }
 350   
 351  131 private void addListener(Class listenerClass, EventListener listener)
 352    {
 353  131 if (_listenerList == null)
 354  66 _listenerList = new EventListenerList();
 355   
 356  131 _listenerList.add(listenerClass, listener);
 357    }
 358   
 359    /**
 360    * @since 2.1-beta-2
 361    */
 362   
 363  5 private void removeListener(Class listenerClass, EventListener listener)
 364    {
 365  5 if (_listenerList != null)
 366  5 _listenerList.remove(listenerClass, listener);
 367    }
 368   
 369  0 public void addPageRenderListener(PageRenderListener listener)
 370    {
 371  0 addPageBeginRenderListener(listener);
 372  0 addPageEndRenderListener(listener);
 373    }
 374   
 375    /** @since 4.0 */
 376  1 public void addPageBeginRenderListener(PageBeginRenderListener listener)
 377    {
 378  1 addListener(PageBeginRenderListener.class, listener);
 379    }
 380   
 381    /** @since 4.0 */
 382  1 public void addPageEndRenderListener(PageEndRenderListener listener)
 383    {
 384  1 addListener(PageEndRenderListener.class, listener);
 385    }
 386   
 387    /** @since 4.0 */
 388  1 public void removePageBeginRenderListener(PageBeginRenderListener listener)
 389    {
 390  1 removeListener(PageBeginRenderListener.class, listener);
 391    }
 392   
 393    /** @since 4.0 */
 394  1 public void removePageEndRenderListener(PageEndRenderListener listener)
 395    {
 396  1 removeListener(PageEndRenderListener.class, listener);
 397    }
 398   
 399    /**
 400    * @since 4.0
 401    */
 402   
 403  191 protected void firePageAttached()
 404    {
 405  191 if (_listenerList == null)
 406  93 return;
 407   
 408  98 PageEvent event = null;
 409  98 Object[] listeners = _listenerList.getListenerList();
 410   
 411  98 for (int i = 0; i < listeners.length; i += 2)
 412    {
 413  166 if (listeners[i] == PageAttachListener.class)
 414    {
 415  1 PageAttachListener l = (PageAttachListener) listeners[i + 1];
 416   
 417  1 if (event == null)
 418  1 event = new PageEvent(this, _requestCycle);
 419   
 420  1 l.pageAttached(event);
 421    }
 422    }
 423    }
 424   
 425    /**
 426    * @since 1.0.5
 427    */
 428   
 429  190 protected void firePageDetached()
 430    {
 431  190 if (_listenerList == null)
 432  83 return;
 433   
 434  107 PageEvent event = null;
 435  107 Object[] listeners = _listenerList.getListenerList();
 436   
 437  107 for (int i = 0; i < listeners.length; i += 2)
 438    {
 439  211 if (listeners[i] == PageDetachListener.class)
 440    {
 441  205 PageDetachListener l = (PageDetachListener) listeners[i + 1];
 442   
 443  205 if (event == null)
 444  100 event = new PageEvent(this, _requestCycle);
 445   
 446  205 l.pageDetached(event);
 447    }
 448    }
 449    }
 450   
 451    /**
 452    * @since 1.0.5
 453    */
 454   
 455  171 protected void firePageBeginRender()
 456    {
 457  171 if (_listenerList == null)
 458  73 return;
 459   
 460  98 PageEvent event = null;
 461  98 Object[] listeners = _listenerList.getListenerList();
 462   
 463  98 for (int i = 0; i < listeners.length; i += 2)
 464    {
 465  179 if (listeners[i] == PageBeginRenderListener.class)
 466    {
 467  1 PageBeginRenderListener l = (PageBeginRenderListener) listeners[i + 1];
 468   
 469  1 if (event == null)
 470  1 event = new PageEvent(this, _requestCycle);
 471   
 472  1 l.pageBeginRender(event);
 473    }
 474    }
 475    }
 476   
 477    /**
 478    * @since 1.0.5
 479    */
 480   
 481  171 protected void firePageEndRender()
 482    {
 483  171 if (_listenerList == null)
 484  64 return;
 485   
 486  107 PageEvent event = null;
 487  107 Object[] listeners = _listenerList.getListenerList();
 488   
 489  107 for (int i = 0; i < listeners.length; i += 2)
 490    {
 491  224 if (listeners[i] == PageEndRenderListener.class)
 492    {
 493  1 PageEndRenderListener l = (PageEndRenderListener) listeners[i + 1];
 494   
 495  1 if (event == null)
 496  1 event = new PageEvent(this, _requestCycle);
 497   
 498  1 l.pageEndRender(event);
 499    }
 500    }
 501    }
 502   
 503    /**
 504    * @since 2.1-beta-2
 505    */
 506   
 507  1 public void removePageDetachListener(PageDetachListener listener)
 508    {
 509  1 removeListener(PageDetachListener.class, listener);
 510    }
 511   
 512  0 public void removePageRenderListener(PageRenderListener listener)
 513    {
 514  0 removePageBeginRenderListener(listener);
 515  0 removePageEndRenderListener(listener);
 516    }
 517   
 518    /** @since 2.2 * */
 519   
 520  20 public void beginPageRender()
 521    {
 522  20 firePageBeginRender();
 523    }
 524   
 525    /** @since 2.2 * */
 526   
 527  20 public void endPageRender()
 528    {
 529  20 firePageEndRender();
 530    }
 531   
 532    /** @since 3.0 * */
 533   
 534  832 public String getPageName()
 535    {
 536  832 return _pageName;
 537    }
 538   
 539  5 public void addPageValidateListener(PageValidateListener listener)
 540    {
 541  5 addListener(PageValidateListener.class, listener);
 542    }
 543   
 544  1 public void removePageValidateListener(PageValidateListener listener)
 545    {
 546  1 removeListener(PageValidateListener.class, listener);
 547    }
 548   
 549    /** @since 4.0 */
 550  1 public void addPageAttachListener(PageAttachListener listener)
 551    {
 552  1 addListener(PageAttachListener.class, listener);
 553    }
 554   
 555    /** @since 4.0 */
 556  1 public void removePageAttachListener(PageAttachListener listener)
 557    {
 558  1 removeListener(PageAttachListener.class, listener);
 559    }
 560   
 561  188 protected void firePageValidate()
 562    {
 563  188 if (_listenerList == null)
 564  91 return;
 565   
 566  97 PageEvent event = null;
 567  97 Object[] listeners = _listenerList.getListenerList();
 568   
 569  97 for (int i = 0; i < listeners.length; i += 2)
 570    {
 571  165 if (listeners[i] == PageValidateListener.class)
 572    {
 573  8 PageValidateListener l = (PageValidateListener) listeners[i + 1];
 574   
 575  8 if (event == null)
 576  8 event = new PageEvent(this, _requestCycle);
 577   
 578  8 l.pageValidate(event);
 579    }
 580    }
 581    }
 582   
 583    /**
 584    * Returns the output encoding to be used when rendering this page. This value is usually cached
 585    * from the Engine.
 586    *
 587    * @since 3.0
 588    */
 589  0 protected String getOutputEncoding()
 590    {
 591  0 if (_outputEncoding == null)
 592  0 _outputEncoding = getEngine().getOutputEncoding();
 593   
 594  0 return _outputEncoding;
 595    }
 596    }