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