Clover coverage report - Code Coverage for tapestry release 4.0.3
Coverage timestamp: Fri May 5 2006 21:17:42 CDT
file stats: LOC: 606   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.PageAttachListener;
 27    import org.apache.tapestry.event.PageBeginRenderListener;
 28    import org.apache.tapestry.event.PageDetachListener;
 29    import org.apache.tapestry.event.PageEndRenderListener;
 30    import org.apache.tapestry.event.PageEvent;
 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 PageBeginRenderListener
 90    * @see PageEndRenderListener
 91    * @see PageDetachListener
 92    * @since 1.0.5
 93    */
 94   
 95    private EventListenerList _listenerList;
 96   
 97    /**
 98    * The output encoding to be used when rendering this page. This value is cached from the
 99    * engine.
 100    *
 101    * @since 3.0
 102    */
 103    private String _outputEncoding;
 104   
 105    /**
 106    * Standard constructor; invokes {@link #initialize()}to configure initial values for
 107    * properties of the page.
 108    *
 109    * @since 2.2
 110    */
 111   
 112  450 public AbstractPage()
 113    {
 114  450 initialize();
 115    }
 116   
 117    /**
 118    * Prepares the page to be returned to the pool.
 119    * <ul>
 120    * <li>Clears the changeObserved property
 121    * <li>Invokes {@link PageDetachListener#pageDetached(PageEvent)}on all listeners
 122    * <li>Invokes {@link #initialize()}to clear/reset any properties
 123    * <li>Clears the engine, visit and requestCycle properties
 124    * </ul>
 125    * <p>
 126    * Subclasses may override this method, but must invoke this implementation (usually, last).
 127    *
 128    * @see PageDetachListener
 129    */
 130   
 131  534 public void detach()
 132    {
 133  534 Tapestry.addMethodInvocation(Tapestry.ABSTRACTPAGE_DETACH_METHOD_ID);
 134   
 135    // Do this first,so that any changes to persistent properties do not
 136    // cause errors.
 137   
 138  534 _changeObserver = null;
 139   
 140  534 firePageDetached();
 141   
 142  534 initialize();
 143   
 144  534 _engine = null;
 145  534 _visit = null;
 146  534 _requestCycle = null;
 147    }
 148   
 149    /**
 150    * Method invoked from the constructor, and from {@link #detach()}to (re-)initialize properties
 151    * of the page. This is most useful when properties have non-null initial values.
 152    * <p>
 153    * Subclasses may override this implementation (which is empty).
 154    * <p>
 155    * Deprecation note: Pages should implement {@link PageBeginRenderListener} and perform all initialization
 156    * in pageBeginRender. This combined with not having instance variables ensures a pristine Page being
 157    * put back into the pool and re-initialized properly prior to being rendered.
 158    * @since 2.2
 159    * @deprecated To be removed in 4.1 with no replacement.
 160    * @see PageDetachListener
 161    * @see PageAttachListener
 162    */
 163   
 164  966 protected void initialize()
 165    {
 166    // Does nothing.
 167    }
 168   
 169  99 public IEngine getEngine()
 170    {
 171  99 return _engine;
 172    }
 173   
 174  93 public ChangeObserver getChangeObserver()
 175    {
 176  93 return _changeObserver;
 177    }
 178   
 179    /**
 180    * Returns the name of the page.
 181    */
 182   
 183  45 public String getExtendedId()
 184    {
 185  45 return _pageName;
 186    }
 187   
 188    /**
 189    * Pages always return null for idPath.
 190    */
 191   
 192  639 public String getIdPath()
 193    {
 194  639 return null;
 195    }
 196   
 197    /**
 198    * Returns the locale for the page, which may be null if the locale is not known (null
 199    * corresponds to the "default locale").
 200    */
 201   
 202  1302 public Locale getLocale()
 203    {
 204  1302 return _locale;
 205    }
 206   
 207  414 public void setLocale(Locale value)
 208    {
 209  414 if (_locale != null)
 210  0 throw new ApplicationRuntimeException(Tapestry
 211    .getMessage("AbstractPage.attempt-to-change-locale"));
 212   
 213  414 _locale = value;
 214    }
 215   
 216  156 public IComponent getNestedComponent(String path)
 217    {
 218  156 StringSplitter splitter;
 219  156 IComponent current;
 220  156 String[] elements;
 221  156 int i;
 222   
 223  156 if (path == null)
 224  0 return this;
 225   
 226  156 splitter = new StringSplitter('.');
 227  156 current = this;
 228   
 229  156 elements = splitter.splitToArray(path);
 230  156 for (i = 0; i < elements.length; i++)
 231    {
 232  156 current = current.getComponent(elements[i]);
 233    }
 234   
 235  156 return current;
 236   
 237    }
 238   
 239    /**
 240    * Called by the {@link IEngine engine}to attach the page to itself. Does <em>not</em> change
 241    * the locale, but since a page is selected from the
 242    * {@link org.apache.tapestry.engine.IPageSource}pool based on its locale matching the engine's
 243    * locale, they should match anyway.
 244    */
 245   
 246  558 public void attach(IEngine engine, IRequestCycle cycle)
 247    {
 248  558 if (_engine != null)
 249  0 LOG.error(this + " attach(" + engine + "), but engine = " + _engine);
 250   
 251  558 _engine = engine;
 252  558 _requestCycle = cycle;
 253   
 254  558 firePageAttached();
 255    }
 256   
 257    /**
 258    * <ul>
 259    * <li>Invokes {@link PageBeginRenderListener#pageBeginRender(PageEvent)}
 260    * <li>Invokes {@link #beginResponse(IMarkupWriter, IRequestCycle)}
 261    * <li>Invokes {@link IRequestCycle#commitPageChanges()}(if not rewinding)
 262    * <li>Invokes {@link #render(IMarkupWriter, IRequestCycle)}
 263    * <li>Invokes {@link PageEndRenderListener#pageEndRender(PageEvent)}(this occurs even if a
 264    * previous step throws an exception)
 265    */
 266   
 267  423 public void renderPage(IMarkupWriter writer, IRequestCycle cycle)
 268    {
 269  423 try
 270    {
 271  423 firePageBeginRender();
 272   
 273  423 beginResponse(writer, cycle);
 274   
 275  423 if (!cycle.isRewinding())
 276  390 cycle.commitPageChanges();
 277   
 278  423 render(writer, cycle);
 279    }
 280    finally
 281    {
 282  423 firePageEndRender();
 283    }
 284    }
 285   
 286  525 public void setChangeObserver(ChangeObserver value)
 287    {
 288  525 _changeObserver = value;
 289    }
 290   
 291    /** @since 3.0 * */
 292   
 293  366 public void setPageName(String pageName)
 294    {
 295  366 if (_pageName != null)
 296  0 throw new ApplicationRuntimeException(Tapestry
 297    .getMessage("AbstractPage.attempt-to-change-name"));
 298   
 299  366 _pageName = pageName;
 300    }
 301   
 302    /**
 303    * By default, pages are not protected and this method does nothing.
 304    */
 305   
 306  528 public void validate(IRequestCycle cycle)
 307    {
 308  528 Tapestry.addMethodInvocation(Tapestry.ABSTRACTPAGE_VALIDATE_METHOD_ID);
 309   
 310  528 firePageValidate();
 311    }
 312   
 313    /**
 314    * Does nothing, subclasses may override as needed.
 315    *
 316    * @deprecated To be removed in 4.0. Implement {@link PageRenderListener}instead.
 317    */
 318   
 319  423 public void beginResponse(IMarkupWriter writer, IRequestCycle cycle)
 320    {
 321    }
 322   
 323  321 public IRequestCycle getRequestCycle()
 324    {
 325  321 return _requestCycle;
 326    }
 327   
 328    /**
 329    * Returns the visit object obtained from the engine via {@link IEngine#getVisit(IRequestCycle)}.
 330    *
 331    * @deprecated
 332    */
 333   
 334  3 public Object getVisit()
 335    {
 336  3 if (_visit == null)
 337  3 _visit = _engine.getVisit(_requestCycle);
 338   
 339  3 return _visit;
 340    }
 341   
 342    /**
 343    * Convienience methods, simply invokes {@link IEngine#getGlobal()}.
 344    *
 345    * @since 2.3
 346    * @deprecated
 347    */
 348   
 349  3 public Object getGlobal()
 350    {
 351  3 return _engine.getGlobal();
 352    }
 353   
 354  624 public void addPageDetachListener(PageDetachListener listener)
 355    {
 356  624 addListener(PageDetachListener.class, listener);
 357    }
 358   
 359  648 private void addListener(Class listenerClass, EventListener listener)
 360    {
 361  648 if (_listenerList == null)
 362  189 _listenerList = new EventListenerList();
 363   
 364  648 _listenerList.add(listenerClass, listener);
 365    }
 366   
 367    /**
 368    * @since 2.1-beta-2
 369    */
 370   
 371  15 private void removeListener(Class listenerClass, EventListener listener)
 372    {
 373  15 if (_listenerList != null)
 374  15 _listenerList.remove(listenerClass, listener);
 375    }
 376   
 377    /** @deprecated */
 378  0 public void addPageRenderListener(PageRenderListener listener)
 379    {
 380  0 addPageBeginRenderListener(listener);
 381  0 addPageEndRenderListener(listener);
 382    }
 383   
 384    /** @since 4.0 */
 385  3 public void addPageBeginRenderListener(PageBeginRenderListener listener)
 386    {
 387  3 addListener(PageBeginRenderListener.class, listener);
 388    }
 389   
 390    /** @since 4.0 */
 391  3 public void addPageEndRenderListener(PageEndRenderListener listener)
 392    {
 393  3 addListener(PageEndRenderListener.class, listener);
 394    }
 395   
 396    /** @since 4.0 */
 397  3 public void removePageBeginRenderListener(PageBeginRenderListener listener)
 398    {
 399  3 removeListener(PageBeginRenderListener.class, listener);
 400    }
 401   
 402    /** @since 4.0 */
 403  3 public void removePageEndRenderListener(PageEndRenderListener listener)
 404    {
 405  3 removeListener(PageEndRenderListener.class, listener);
 406    }
 407   
 408    /**
 409    * @since 4.0
 410    */
 411   
 412  897 public void firePageAttached()
 413    {
 414  897 if (_listenerList == null)
 415  588 return;
 416   
 417  309 PageEvent event = null;
 418  309 Object[] listeners = _listenerList.getListenerList();
 419   
 420  309 for(int i = listeners.length-2; i >= 0; i -= 2)
 421    {
 422  942 if (listeners[i] == PageAttachListener.class)
 423    {
 424  3 PageAttachListener l = (PageAttachListener) listeners[i + 1];
 425   
 426  3 if (event == null)
 427  3 event = new PageEvent(this, _requestCycle);
 428   
 429  3 l.pageAttached(event);
 430    }
 431    }
 432    }
 433   
 434    /**
 435    * @since 1.0.5
 436    */
 437   
 438  534 protected void firePageDetached()
 439    {
 440  534 if (_listenerList == null)
 441  219 return;
 442   
 443  315 PageEvent event = null;
 444  315 Object[] listeners = _listenerList.getListenerList();
 445   
 446  315 for (int i = 0; i < listeners.length; i += 2)
 447    {
 448  1068 if (listeners[i] == PageDetachListener.class)
 449    {
 450  1050 PageDetachListener l = (PageDetachListener) listeners[i + 1];
 451   
 452  1050 if (event == null)
 453  294 event = new PageEvent(this, _requestCycle);
 454   
 455  1050 l.pageDetached(event);
 456    }
 457    }
 458    }
 459   
 460    /**
 461    * @since 1.0.5
 462    */
 463   
 464  486 protected void firePageBeginRender()
 465    {
 466  486 if (_listenerList == null)
 467  174 return;
 468   
 469  312 PageEvent event = null;
 470  312 Object[] listeners = _listenerList.getListenerList();
 471   
 472  312 for(int i = listeners.length-2; i >= 0; i -= 2)
 473    {
 474  1041 if (listeners[i] == PageBeginRenderListener.class)
 475    {
 476  3 PageBeginRenderListener l = (PageBeginRenderListener)listeners[i + 1];
 477   
 478  3 if (event == null)
 479  3 event = new PageEvent(this, _requestCycle);
 480   
 481  3 l.pageBeginRender(event);
 482    }
 483    }
 484    }
 485   
 486    /**
 487    * @since 1.0.5
 488    */
 489   
 490  486 protected void firePageEndRender()
 491    {
 492  486 if (_listenerList == null)
 493  168 return;
 494   
 495  318 PageEvent event = null;
 496  318 Object[] listeners = _listenerList.getListenerList();
 497   
 498  318 for (int i = 0; i < listeners.length; i += 2)
 499    {
 500  1167 if (listeners[i] == PageEndRenderListener.class)
 501    {
 502  3 PageEndRenderListener l = (PageEndRenderListener) listeners[i + 1];
 503   
 504  3 if (event == null)
 505  3 event = new PageEvent(this, _requestCycle);
 506   
 507  3 l.pageEndRender(event);
 508    }
 509    }
 510    }
 511   
 512    /**
 513    * @since 2.1-beta-2
 514    */
 515   
 516  3 public void removePageDetachListener(PageDetachListener listener)
 517    {
 518  3 removeListener(PageDetachListener.class, listener);
 519    }
 520   
 521    /** @deprecated */
 522  0 public void removePageRenderListener(PageRenderListener listener)
 523    {
 524  0 removePageBeginRenderListener(listener);
 525  0 removePageEndRenderListener(listener);
 526    }
 527   
 528    /** @since 2.2 * */
 529   
 530  63 public void beginPageRender()
 531    {
 532  63 firePageBeginRender();
 533    }
 534   
 535    /** @since 2.2 * */
 536   
 537  63 public void endPageRender()
 538    {
 539  63 firePageEndRender();
 540    }
 541   
 542    /** @since 3.0 * */
 543   
 544  2346 public String getPageName()
 545    {
 546  2346 return _pageName;
 547    }
 548   
 549  15 public void addPageValidateListener(PageValidateListener listener)
 550    {
 551  15 addListener(PageValidateListener.class, listener);
 552    }
 553   
 554  3 public void removePageValidateListener(PageValidateListener listener)
 555    {
 556  3 removeListener(PageValidateListener.class, listener);
 557    }
 558   
 559    /** @since 4.0 */
 560  3 public void addPageAttachListener(PageAttachListener listener)
 561    {
 562  3 addListener(PageAttachListener.class, listener);
 563    }
 564   
 565    /** @since 4.0 */
 566  3 public void removePageAttachListener(PageAttachListener listener)
 567    {
 568  3 removeListener(PageAttachListener.class, listener);
 569    }
 570   
 571  528 protected void firePageValidate()
 572    {
 573  528 if (_listenerList == null)
 574  222 return;
 575   
 576  306 PageEvent event = null;
 577  306 Object[] listeners = _listenerList.getListenerList();
 578   
 579  306 for (int i = 0; i < listeners.length; i += 2)
 580    {
 581  939 if (listeners[i] == PageValidateListener.class)
 582    {
 583  24 PageValidateListener l = (PageValidateListener) listeners[i + 1];
 584   
 585  24 if (event == null)
 586  24 event = new PageEvent(this, _requestCycle);
 587   
 588  24 l.pageValidate(event);
 589    }
 590    }
 591    }
 592   
 593    /**
 594    * Returns the output encoding to be used when rendering this page. This value is usually cached
 595    * from the Engine.
 596    *
 597    * @since 3.0
 598    */
 599  0 protected String getOutputEncoding()
 600    {
 601  0 if (_outputEncoding == null)
 602  0 _outputEncoding = getEngine().getOutputEncoding();
 603   
 604  0 return _outputEncoding;
 605    }
 606    }