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