Clover coverage report - Code Coverage for tapestry release 4.0-beta-2
Coverage timestamp: Sat Jul 9 2005 22:02:17 EDT
file stats: LOC: 428   Methods: 24
NCLOC: 172   Classes: 2
30 day Evaluation License registered to hlship@comcast.net Your 30 day evaluation period has expired. Please visit http://www.cenqua.com to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
Form.java 88.9% 89.1% 79.2% 86.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.form;
 16   
 17    import org.apache.hivemind.ApplicationRuntimeException;
 18    import org.apache.hivemind.Location;
 19    import org.apache.tapestry.AbstractComponent;
 20    import org.apache.tapestry.IActionListener;
 21    import org.apache.tapestry.IComponent;
 22    import org.apache.tapestry.IDirect;
 23    import org.apache.tapestry.IForm;
 24    import org.apache.tapestry.IMarkupWriter;
 25    import org.apache.tapestry.IRender;
 26    import org.apache.tapestry.IRequestCycle;
 27    import org.apache.tapestry.RenderRewoundException;
 28    import org.apache.tapestry.Tapestry;
 29    import org.apache.tapestry.TapestryUtils;
 30    import org.apache.tapestry.engine.ActionServiceParameter;
 31    import org.apache.tapestry.engine.DirectServiceParameter;
 32    import org.apache.tapestry.engine.IEngineService;
 33    import org.apache.tapestry.engine.ILink;
 34    import org.apache.tapestry.listener.ListenerInvoker;
 35    import org.apache.tapestry.valid.IValidationDelegate;
 36    import org.apache.tapestry.web.WebResponse;
 37   
 38    /**
 39    * Component which contains form element components. Forms use the action or direct services to
 40    * handle the form submission. A Form will wrap other components and static HTML, including form
 41    * components such as {@link TextArea},{@link TextField},{@link Checkbox}, etc. [ <a
 42    * href="../../../../../ComponentReference/Form.html">Component Reference </a>]
 43    * <p>
 44    * When a form is submitted, it continues through the rewind cycle until <em>after</em> all of its
 45    * wrapped elements have renderred. As the form component render (in the rewind cycle), they will be
 46    * updating properties of the containing page and notifying thier listeners. Again: each form
 47    * component is responsible not only for rendering HTML (to present the form), but for handling it's
 48    * share of the form submission.
 49    * <p>
 50    * Only after all that is done will the Form notify its listener.
 51    * <p>
 52    * Starting in release 1.0.2, a Form can use either the direct service or the action service. The
 53    * default is the direct service, even though in earlier releases, only the action service was
 54    * available.
 55    * <p>
 56    * Release 4.0 adds two new listener, {@link #getCancel()} and {@link #getRefresh()} and
 57    * corresponding client-side behavior to force a form to refresh (update, bypassing input field
 58    * validation) or cancel (update immediately).
 59    *
 60    * @author Howard Lewis Ship, David Solis
 61    */
 62   
 63    public abstract class Form extends AbstractComponent implements IForm, IDirect
 64    {
 65    private String _name;
 66   
 67    private FormSupport _formSupport;
 68   
 69    private class RenderInformalParameters implements IRender
 70    {
 71  42 public void render(IMarkupWriter writer, IRequestCycle cycle)
 72    {
 73  42 renderInformalParameters(writer, cycle);
 74    }
 75    }
 76   
 77    private IRender _renderInformalParameters;
 78   
 79    /**
 80    * Returns the currently active {@link IForm}, or null if no form is active. This is a
 81    * convienience method, the result will be null, or an instance of {@link IForm}, but not
 82    * necessarily a <code>Form</code>.
 83    *
 84    * @deprecated Use {@link TapestryUtils#getForm(IRequestCycle, IComponent)}&nbsp;instead.
 85    */
 86   
 87  0 public static IForm get(IRequestCycle cycle)
 88    {
 89  0 return (IForm) cycle.getAttribute(ATTRIBUTE_NAME);
 90    }
 91   
 92    /**
 93    * Indicates to any wrapped form components that they should respond to the form submission.
 94    *
 95    * @throws ApplicationRuntimeException
 96    * if not rendering.
 97    */
 98   
 99  145 public boolean isRewinding()
 100    {
 101  145 if (!isRendering())
 102  0 throw Tapestry.createRenderOnlyPropertyException(this, "rewinding");
 103   
 104  145 return _formSupport.isRewinding();
 105    }
 106   
 107    /**
 108    * Injected.
 109    *
 110    * @since 4.0
 111    */
 112   
 113    public abstract IEngineService getDirectService();
 114   
 115    /**
 116    * Injected.
 117    *
 118    * @since 4.0
 119    */
 120   
 121    public abstract IEngineService getActionService();
 122   
 123    /**
 124    * Returns true if this Form is configured to use the direct service.
 125    * <p>
 126    * This is derived from the direct parameter, and defaults to true if not bound.
 127    *
 128    * @since 1.0.2
 129    */
 130   
 131    public abstract boolean isDirect();
 132   
 133    /**
 134    * Returns true if the stateful parameter is bound to a true value. If stateful is not bound,
 135    * also returns the default, true.
 136    *
 137    * @since 1.0.1
 138    */
 139   
 140  1 public boolean getRequiresSession()
 141    {
 142  1 return isStateful();
 143    }
 144   
 145    /**
 146    * Constructs a unique identifier (within the Form). The identifier consists of the component's
 147    * id, with an index number added to ensure uniqueness.
 148    * <p>
 149    * Simply invokes
 150    * {@link #getElementId(org.apache.tapestry.form.IFormComponent, java.lang.String)}with the
 151    * component's id.
 152    *
 153    * @since 1.0.2
 154    */
 155   
 156  80 public String getElementId(IFormComponent component)
 157    {
 158  80 return _formSupport.getElementId(component, component.getId());
 159    }
 160   
 161    /**
 162    * Constructs a unique identifier from the base id. If possible, the id is used as-is.
 163    * Otherwise, a unique identifier is appended to the id.
 164    * <p>
 165    * This method is provided simply so that some components ({@link ImageSubmit}) have more
 166    * specific control over their names.
 167    *
 168    * @since 1.0.3
 169    */
 170   
 171  0 public String getElementId(IFormComponent component, String baseId)
 172    {
 173  0 return _formSupport.getElementId(component, baseId);
 174    }
 175   
 176    /**
 177    * Returns the name generated for the form. This is used to faciliate components that write
 178    * JavaScript and need to access the form or its contents.
 179    * <p>
 180    * This value is generated when the form renders, and is not cleared. If the Form is inside a
 181    * {@link org.apache.tapestry.components.Foreach}, this will be the most recently generated
 182    * name for the Form.
 183    * <p>
 184    * This property is exposed so that sophisticated applications can write JavaScript handlers for
 185    * the form and components within the form.
 186    *
 187    * @see AbstractFormComponent#getName()
 188    */
 189   
 190  81 public String getName()
 191    {
 192  81 return _name;
 193    }
 194   
 195    /** @since 3.0 * */
 196   
 197  71 protected void prepareForRender(IRequestCycle cycle)
 198    {
 199  71 super.prepareForRender(cycle);
 200   
 201  71 TapestryUtils.storeForm(cycle, this);
 202    }
 203   
 204  71 protected void cleanupAfterRender(IRequestCycle cycle)
 205    {
 206  71 _formSupport = null;
 207   
 208  71 TapestryUtils.removeForm(cycle);
 209   
 210  71 IValidationDelegate delegate = getDelegate();
 211   
 212  71 if (delegate != null)
 213  71 delegate.setFormComponent(null);
 214   
 215  71 super.cleanupAfterRender(cycle);
 216    }
 217   
 218  71 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
 219    {
 220  71 String actionId = cycle.getNextActionId();
 221   
 222  71 _formSupport = newFormSupport(writer, cycle);
 223   
 224  71 if (isRewinding())
 225    {
 226  25 String submitType = _formSupport.rewind();
 227   
 228  23 IActionListener listener = findListener(submitType);
 229   
 230  23 getListenerInvoker().invokeListener(listener, this, cycle);
 231   
 232    // Abort the rewind render.
 233   
 234  23 throw new RenderRewoundException(this);
 235    }
 236   
 237    // Note: not safe to invoke getNamespace() in Portlet world
 238    // except during a RenderRequest.
 239   
 240  46 String baseName = isDirect() ? constructFormNameForDirectService(cycle)
 241    : constructFormNameForActionService(actionId);
 242   
 243  46 _name = baseName + getResponse().getNamespace();
 244   
 245  46 if (_renderInformalParameters == null)
 246  25 _renderInformalParameters = new RenderInformalParameters();
 247   
 248  46 ILink link = getLink(cycle, actionId);
 249   
 250  46 _formSupport.render(getMethod(), _renderInformalParameters, link);
 251    }
 252   
 253  28 IActionListener findListener(String mode)
 254    {
 255  28 IActionListener result = null;
 256   
 257  28 if (mode.equals(FormConstants.SUBMIT_CANCEL))
 258  2 result = getCancel();
 259  26 else if (mode.equals(FormConstants.SUBMIT_REFRESH))
 260  2 result = getRefresh();
 261   
 262    // If not cancel or refresh, or the corresponding listener
 263    // is itself null, then use the default listener
 264    // (which may be null as well!).
 265   
 266  28 if (result == null)
 267  26 result = getListener();
 268   
 269  28 return result;
 270    }
 271   
 272    /**
 273    * Construct a form name for use with the action service. This implementation returns "Form"
 274    * appended with the actionId.
 275    *
 276    * @since 4.0
 277    */
 278   
 279  8 protected String constructFormNameForActionService(String actionId)
 280    {
 281  8 return "Form" + actionId;
 282    }
 283   
 284    /**
 285    * Constructs a form name for use with the direct service. This implementation bases the form
 286    * name on the form component's id (but ensures it is unique). Remember that Tapestry assigns an
 287    * "ugly" id if an explicit component id is not provided.
 288    *
 289    * @since 4.0
 290    */
 291   
 292  35 private String constructFormNameForDirectService(IRequestCycle cycle)
 293    {
 294  35 return cycle.getUniqueId(getId());
 295    }
 296   
 297    /**
 298    * Returns a new instance of {@link FormSupportImpl}.
 299    */
 300   
 301  61 protected FormSupport newFormSupport(IMarkupWriter writer, IRequestCycle cycle)
 302    {
 303  61 return new FormSupportImpl(writer, cycle, this);
 304    }
 305   
 306    /**
 307    * Adds an additional event handler.
 308    *
 309    * @since 1.0.2
 310    */
 311   
 312  0 public void addEventHandler(FormEventType type, String functionName)
 313    {
 314  0 _formSupport.addEventHandler(type, functionName);
 315    }
 316   
 317    /**
 318    * Simply invokes {@link #render(IMarkupWriter, IRequestCycle)}.
 319    *
 320    * @since 1.0.2
 321    */
 322   
 323  20 public void rewind(IMarkupWriter writer, IRequestCycle cycle)
 324    {
 325  20 render(writer, cycle);
 326    }
 327   
 328    /**
 329    * Method invoked by the direct service.
 330    *
 331    * @since 1.0.2
 332    */
 333   
 334  20 public void trigger(IRequestCycle cycle)
 335    {
 336  20 cycle.rewindForm(this);
 337    }
 338   
 339    /**
 340    * Builds the EngineServiceLink for the form, using either the direct or action service.
 341    *
 342    * @since 1.0.3
 343    */
 344   
 345  46 private ILink getLink(IRequestCycle cycle, String actionId)
 346    {
 347  46 if (isDirect())
 348    {
 349  35 Object parameter = new DirectServiceParameter(this);
 350  35 return getDirectService().getLink(cycle, parameter);
 351    }
 352   
 353    // I'd love to pull out support for the action service entirely!
 354   
 355  11 Object parameter = new ActionServiceParameter(this, actionId);
 356   
 357  11 return getActionService().getLink(cycle, parameter);
 358    }
 359   
 360    /** Injected */
 361   
 362    public abstract WebResponse getResponse();
 363   
 364    /**
 365    * delegate parameter, which has a default (starting in release 4.0).
 366    */
 367   
 368    public abstract IValidationDelegate getDelegate();
 369   
 370    /** listener parameter, may be null */
 371    public abstract IActionListener getListener();
 372   
 373    /** cancel parameter, may be null */
 374    public abstract IActionListener getCancel();
 375   
 376    /** refresh parameter, may be null */
 377    public abstract IActionListener getRefresh();
 378   
 379    /** method parameter */
 380    public abstract String getMethod();
 381   
 382    /** stateful parameter */
 383    public abstract boolean isStateful();
 384   
 385  2 public void setEncodingType(String encodingType)
 386    {
 387  2 _formSupport.setEncodingType(encodingType);
 388    }
 389   
 390    /** @since 3.0 */
 391   
 392  17 public void addHiddenValue(String name, String value)
 393    {
 394  17 _formSupport.addHiddenValue(name, value);
 395    }
 396   
 397    /** @since 3.0 */
 398   
 399  4 public void addHiddenValue(String name, String id, String value)
 400    {
 401  4 _formSupport.addHiddenValue(name, id, value);
 402    }
 403   
 404  0 public void prerenderField(IMarkupWriter writer, IComponent field, Location location)
 405    {
 406  0 _formSupport.prerenderField(writer, field, location);
 407    }
 408   
 409  75 public boolean wasPrerendered(IMarkupWriter writer, IComponent field)
 410    {
 411  75 return _formSupport.wasPrerendered(writer, field);
 412    }
 413   
 414    /** @since 4.0 */
 415   
 416  0 public void addDeferredRunnable(Runnable runnable)
 417    {
 418  0 _formSupport.addDeferredRunnable(runnable);
 419    }
 420   
 421    /**
 422    * Injected
 423    *
 424    * @since 4.0
 425    */
 426   
 427    public abstract ListenerInvoker getListenerInvoker();
 428    }