Clover coverage report - Code Coverage for tapestry release 4.0.1
Coverage timestamp: Fri Mar 31 2006 09:12:14 EST
file stats: LOC: 445   Methods: 25
NCLOC: 182   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
Form.java 90% 87.9% 76% 85.4%
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 listeners, {@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  86 public void render(IMarkupWriter writer, IRequestCycle cycle)
 72    {
 73  86 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)} 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  314 public boolean isRewinding()
 100    {
 101  314 if (!isRendering())
 102  0 throw Tapestry.createRenderOnlyPropertyException(this, "rewinding");
 103   
 104  314 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  2 public boolean getRequiresSession()
 141    {
 142  2 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  192 public String getElementId(IFormComponent component)
 157    {
 158  192 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  94 public String getName()
 191    {
 192  94 return _name;
 193    }
 194   
 195    /** @since 3.0 * */
 196   
 197  152 protected void prepareForRender(IRequestCycle cycle)
 198    {
 199  152 super.prepareForRender(cycle);
 200   
 201  152 TapestryUtils.storeForm(cycle, this);
 202    }
 203   
 204  152 protected void cleanupAfterRender(IRequestCycle cycle)
 205    {
 206  152 _formSupport = null;
 207   
 208  152 TapestryUtils.removeForm(cycle);
 209   
 210  152 IValidationDelegate delegate = getDelegate();
 211   
 212  152 if (delegate != null)
 213  152 delegate.setFormComponent(null);
 214   
 215  152 super.cleanupAfterRender(cycle);
 216    }
 217   
 218  152 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
 219    {
 220  152 String actionId = cycle.getNextActionId();
 221   
 222  152 _formSupport = newFormSupport(writer, cycle);
 223   
 224  152 if (isRewinding())
 225    {
 226  54 String submitType = _formSupport.rewind();
 227   
 228  50 IActionListener listener = findListener(submitType);
 229   
 230  50 getListenerInvoker().invokeListener(listener, this, cycle);
 231   
 232    // Abort the rewind render.
 233   
 234  50 throw new RenderRewoundException(this);
 235    }
 236   
 237    // Note: not safe to invoke getNamespace() in Portlet world
 238    // except during a RenderRequest.
 239   
 240  98 String baseName = isDirect() ? constructFormNameForDirectService(cycle)
 241    : constructFormNameForActionService(actionId);
 242   
 243  98 _name = baseName + getResponse().getNamespace();
 244   
 245  98 if (_renderInformalParameters == null)
 246  54 _renderInformalParameters = new RenderInformalParameters();
 247   
 248  98 ILink link = getLink(cycle, actionId);
 249   
 250  98 _formSupport.render(getMethod(), _renderInformalParameters, link, getScheme(), getPort());
 251    }
 252   
 253  62 IActionListener findListener(String mode)
 254    {
 255  62 IActionListener result = null;
 256   
 257  62 if (mode.equals(FormConstants.SUBMIT_CANCEL))
 258  4 result = getCancel();
 259  58 else if (mode.equals(FormConstants.SUBMIT_REFRESH))
 260  4 result = getRefresh();
 261  54 else if (!getDelegate().getHasErrors())
 262  52 result = getSuccess();
 263   
 264    // If not success, cancel or refresh, or the corresponding listener
 265    // is itself null, then use the default listener
 266    // (which may be null as well!).
 267   
 268  62 if (result == null)
 269  56 result = getListener();
 270   
 271  62 return result;
 272    }
 273   
 274    /**
 275    * Construct a form name for use with the action service. This implementation returns "Form"
 276    * appended with the actionId.
 277    *
 278    * @since 4.0
 279    */
 280   
 281  16 protected String constructFormNameForActionService(String actionId)
 282    {
 283  16 return "Form" + actionId;
 284    }
 285   
 286    /**
 287    * Constructs a form name for use with the direct service. This implementation bases the form
 288    * name on the form component's id (but ensures it is unique). Remember that Tapestry assigns an
 289    * "ugly" id if an explicit component id is not provided.
 290    *
 291    * @since 4.0
 292    */
 293   
 294  76 private String constructFormNameForDirectService(IRequestCycle cycle)
 295    {
 296  76 return cycle.getUniqueId(TapestryUtils.convertTapestryIdToNMToken(getId()));
 297    }
 298   
 299    /**
 300    * Returns a new instance of {@link FormSupportImpl}.
 301    */
 302   
 303  126 protected FormSupport newFormSupport(IMarkupWriter writer, IRequestCycle cycle)
 304    {
 305  126 return new FormSupportImpl(writer, cycle, this);
 306    }
 307   
 308    /**
 309    * Adds an additional event handler.
 310    *
 311    * @since 1.0.2
 312    */
 313   
 314  0 public void addEventHandler(FormEventType type, String functionName)
 315    {
 316  0 _formSupport.addEventHandler(type, functionName);
 317    }
 318   
 319    /**
 320    * Simply invokes {@link #render(IMarkupWriter, IRequestCycle)}.
 321    *
 322    * @since 1.0.2
 323    */
 324   
 325  42 public void rewind(IMarkupWriter writer, IRequestCycle cycle)
 326    {
 327  42 render(writer, cycle);
 328    }
 329   
 330    /**
 331    * Method invoked by the direct service.
 332    *
 333    * @since 1.0.2
 334    */
 335   
 336  42 public void trigger(IRequestCycle cycle)
 337    {
 338  42 cycle.rewindForm(this);
 339    }
 340   
 341    /**
 342    * Builds the EngineServiceLink for the form, using either the direct or action service.
 343    *
 344    * @since 1.0.3
 345    */
 346   
 347  98 protected ILink getLink(IRequestCycle cycle, String actionId)
 348    {
 349  98 if (isDirect())
 350    {
 351  76 Object parameter = new DirectServiceParameter(this);
 352  76 return getDirectService().getLink(true, parameter);
 353    }
 354   
 355    // I'd love to pull out support for the action service entirely!
 356   
 357  22 Object parameter = new ActionServiceParameter(this, actionId);
 358   
 359  22 return getActionService().getLink(true, parameter);
 360    }
 361   
 362    /** Injected */
 363   
 364    public abstract WebResponse getResponse();
 365   
 366    /**
 367    * delegate parameter, which has a default (starting in release 4.0).
 368    */
 369   
 370    public abstract IValidationDelegate getDelegate();
 371   
 372    /** listener parameter, may be null */
 373    public abstract IActionListener getListener();
 374   
 375    /** success parameter, may be null */
 376    public abstract IActionListener getSuccess();
 377   
 378    /** cancel parameter, may be null */
 379    public abstract IActionListener getCancel();
 380   
 381    /** refresh parameter, may be null */
 382    public abstract IActionListener getRefresh();
 383   
 384    /** method parameter */
 385    public abstract String getMethod();
 386   
 387    /** stateful parameter */
 388    public abstract boolean isStateful();
 389   
 390    /** scheme parameter, may be null */
 391    public abstract String getScheme();
 392   
 393    /** port , may be null */
 394    public abstract Integer getPort();
 395   
 396  4 public void setEncodingType(String encodingType)
 397    {
 398  4 _formSupport.setEncodingType(encodingType);
 399    }
 400   
 401    /** @since 3.0 */
 402   
 403  60 public void addHiddenValue(String name, String value)
 404    {
 405  60 _formSupport.addHiddenValue(name, value);
 406    }
 407   
 408    /** @since 3.0 */
 409   
 410  8 public void addHiddenValue(String name, String id, String value)
 411    {
 412  8 _formSupport.addHiddenValue(name, id, value);
 413    }
 414   
 415  0 public void prerenderField(IMarkupWriter writer, IComponent field, Location location)
 416    {
 417  0 _formSupport.prerenderField(writer, field, location);
 418    }
 419   
 420  150 public boolean wasPrerendered(IMarkupWriter writer, IComponent field)
 421    {
 422  150 return _formSupport.wasPrerendered(writer, field);
 423    }
 424   
 425    /** @since 4.0 */
 426   
 427  0 public void addDeferredRunnable(Runnable runnable)
 428    {
 429  0 _formSupport.addDeferredRunnable(runnable);
 430    }
 431   
 432    /**
 433    * Injected
 434    *
 435    * @since 4.0
 436    */
 437   
 438    public abstract ListenerInvoker getListenerInvoker();
 439   
 440  0 public void registerForFocus(IFormComponent field, int priority)
 441    {
 442  0 _formSupport.registerForFocus(field, priority);
 443    }
 444   
 445    }