Tuesday, September 14, 2010

Apache Click 2.2.0: Explicit Binding

In this three part series I'll blog about some of the new features added in 2.2.0, namely:

  1. DataProviders (Japanese version)
  2. Explicit binding (Japanese version)
  3. Dynamic Form Validation ( Japanese version)

    In this second installment I'll cover explicit binding which allows developers to bind, or set, a control's value to incoming request parameters. Not all controls support binding though. The most common bindable controls include Field, Form and Abstractlink. Explicit binding simplifies dynamic Page and Form behavior as it allows you to bind and query control values whenever you need to, for example in the onInit event or the Page constructor.

    When talking about explicit binding it is also worth mentioning implicit binding.
    Implicit binding occurs automatically every request as part of the onProcess event. So Control values will automatically be set once the onProcess event has occurred.Click Controls uses a convention of handling bind logic in a method called bindRequestValue().

    A typical bindRequestValue() implementation looks like this:

    public void bindRequestValue() {
        Context context = getContext();
        String controlName = getName();
        String value = context.getRequestParameter(controlName);
        if(value != null) {
            setValue(value);
        }
    }
    
    // For completeness sake we show the onProcess implementation as well.
    // onProcess delegates the binding logic to bindRequestValue
    public void onProcess() {
        bindRequestValue();
        ...
    }
    
    

    Generally the control name is used to lookup the incoming request parameter, but
    other conventions can be used as well.

    Under most circumstances, implicit binding is all you need. But sometimes you might want to know the value of a control before the onProcess event occurs. For example, within the onInit()
    event, you might want to check which drop-down value a user selected in order to
    add another Field to the Form. Remember, only Controls that are created and
    attached to their parent page/container partakes in the onProcess event. That's why it's important to create and attach Controls to their parents prior to the onProcess event.

    As you probably know already, the onInit event occurs before onProcess, and because implicit binding only occurs during onProcess, the Control value is not available for querying from onInit.

    So how can you find out the value of a Control during the onInit event? This is
    where explicit binding comes into play. Explicit binding allows developers to
    dictate when the Control value is bound. So how can one explicitly bind the Control value?
    By invoking the Control method, bindRequestValue(). (Recall that not all Controls
    support binding and might not provide a bindRequestValue() method.)

    There are a couple of caveats to be aware of when invoking bindRequestValue
    directly.

    • Fields should only be bound if their parent Form has been submitted, otherwise if you have multiple forms on the page, you might end up in a situation where form1 fields could be bound to form2 fields.
    • Forwarded requests have already been processed and should not be used for binding purposes.

    To make things easier, Click provides a couple of helper methods that takes care
    of the caveats mentioned above. These helper methods are available from the
    ClickUtils class which sports a variety of bind() and bindAndValidate() methods.
    You can even pass in Containers such as Form to these methods and all child
    controls will be bound.

    The bindAndValidate() method will both bind and validate a Field or Form.



    It's worth mentioning that it's also possible to lookup request parameters directly through the Context object instead of having to bind the control value.

    Let's look at some examples next.

    In this first example we will look at a dynamic Form where a Checkbox determines
    whether a TextField should be added to the Form or not.


    public class DynamicFormDemo extends Page {
    
        @Override
        public void onInit() {
            super.onInit();
            Form form = new Form("form");
            addControl(form);
            Checkbox chk = new Checkbox("chk");
            form.add(chk);
    
            Submit ok = new Submit("ok");
            form.add(ok);
    
            // Explicitly bind the checkbox in the onInit event which allows us to query
            // whether the Checkbox was checked or not.
            ClickUtils.bind(chk);
            if(chk.isChecked()) {
                form.add(new TextField("name"));
            }
        }
    }
    

    We use the ClickUtils.bind() method to explicitly bind the Checkbox value so we
    can query whether it is checked or not.

    In this second example we expand the first by adding a Select field as well.



    public class DynamicFormDemo extends Page {
    
        @Override
        public void onInit() {
            super.onInit();
            Form form = new Form("form");
            addControl(form);
            Checkbox chk = new Checkbox("chk");
            form.add(chk);
            Select countries = new CountrySelect("countries");
            countries.getOptionList().add(Option.EMPTY_OPTION);
            form.add(countries);
    
            Submit ok = new Submit("ok");
            form.add(ok);
    
            // Explicitly bind the Form (and all it's child controls) in the onInit
            // event, allowing us to query whether he user checked the Checkbox and
            // which country was selected.
            ClickUtils.bind(form);
            if (chk.isChecked()) {
                form.add(new TextField("name"));
            }
    
            if (StringUtils.isNotBlank(countries.getValue())) {
                form.add(new TextField("location"));
            }
        }
    }
    

    Note, instead of binding the Checkbox and Select separately we pass the Form to
    the ClickUtils.bind() method. When passing a container such as a Form to the
    ClickUtils.bind() methods, all bindable controls in the container will have their
    values bound. This provides an easy shortcut to quickly bind multiple controls.

    In this third and final example we show how to both bind and validate a form.

    public class DynamicFormDemo extends BorderPage {
    
        @Override
        public void onInit() {
            super.onInit();
            Form form = new Form("form");
            addControl(form);
            Checkbox chk = new Checkbox("chk");
            form.add(chk);
            Select countries = new CountrySelect("countries", true);
            countries.getOptionList().add(Option.EMPTY_OPTION);
            form.add(countries);
    
            Submit ok = new Submit("ok");
            form.add(ok);
    
            // Explicitly bind and check that the Form (and all it's child
            // controls) is valid in the onInit event, allowing us to safely
            // query whether he user checked the Checkbox and
            // which country was selected.
            if (ClickUtils.bindAndValidate(form)) {
                if (chk.isChecked()) {
                    form.add(new TextField("name"));
                }
    
                // The form validation passed and since the countries field is required
                // we can safely assume that a valid country has been selected
                form.add(new TextField("location"));
            }
        }
    }
    

    The ClickUtils.bindAndValidate() methods will bind and validate the field/s and return true if the field/s are valid, false otherwise.

    Friday, September 10, 2010

    ClickIDE 2.2.0.0 has been released!

    ClickIDE 2.2.0.0 is now available! ClickIDE is an Eclipse plug-in for the developing Click web applications.

    This version supports Apache Click 2.2.0 and fixes some minor issues.

    For details about ClickIDE see:
    http://click.apache.org/docs/click-ide.html

    Download is available here:
    http://click.apache.org/docs/click-ide-downloads.html
     

    Enjoy Click

    Saturday, July 24, 2010

    SD Times interview with Apache Click vice president

    Malcolm Edgar, Apache Click Vice President, recently had a chat with SD Times editor in chief, David Rubinstein. Great to see Click getting some much deserved exposure.

    Full interview can be viewed here.

    Wednesday, July 14, 2010

    Apache Click 2.2.0: DataProvider

    In this three part series I'll blog about some of the new features added in 2.2.0, namely:

    1. DataProviders (Japanese version)
    2. Explicit binding (Japanese version)
    3. Dynamic Form Validation ( Japanese version)
      In this first installment I'll cover DataProviders and how they simplify Click Page implementations.

      To understand the benefits of DataProviders, we need to look at the problem they are trying to solve. To start off with let's do a quick recap of the major life cycle events of a Click Page. Below we list the events in the order they are executed:
      • <<init>>: page is created
      • onInit: page controls are created and added to the page
      • onProcess: control values are bound to request parameters, control values are validated and action listeners are fired
      • onRender: database intensive operations are performed here
      Click allows certain events to be skipped depending on the outcome of a previous event. onRender for example, will be skipped if a Control action returns false. This together with the fact that onRender is the last event exposed by Click makes onRender ideal for database intensive operations. If a control action listener decides to redirect to a different page, it can return false to bypass the slow onRender method.

      For example:
      public class CustomerPage extends BorderPage {
      
          private Table table = new Table("table");
          private ActionLink editLink = new EditLink("edit");
      
          @Override
          public void onInit() {
              super.onInit();
      
              table.add(new Column("firstname"));
      
              ...
      
              editLink.setActionListener(new ActionListener() {
                  public boolean onAction(Control source) {
                      Map params = Collections.singletonMap("id", editLink.getValue());
      
                     // Redirect to edit customer page and pass the selected customer ID
                     setRedirect(EditCustomerPage.class, params);
                     return false;
                  }
              });
          }
      
          @Override
          public void onRender() {
              // Database intensive operation: retrieving all customers from the database
              List<Customer> customers = getCustomerService.getCustomers();
              table.setRows(customers);
          }
      }
      
      In the example above you can see that we don't want to hit the database and retrieve all the customers only to be redirected to another page that does not render the customers we retrieved. In other words, because the customers won't be rendered by the page we redirect to, we don't want to pay for the database hit. Since the onRender event is skipped if an action listener returns false, it makes sense to place database intensive code there.

      Inconsistent

      Unfortunately this pattern cannot be applied to all controls. Some controls need their values populated before the onProcess event, either for validation or parameter binding purposes. For example, the Select control validation depends on its values to determines whether or not a valid selection was made. FormTable needs to have it's rows set  in order to update its entity values against incoming request parameters.

      Having some of the controls populated in onInit and others in onRender is inconsistent and a common pitfall for new users as they have to figure out which controls should be populated in which event.

      DataProvider

      The solution used in Click was to add a DataProvider interface to enable on demand data loading. A DataProvider has a single method, "public List getData()", that the control can invoke when it needs it's data. For example, a Table will invoke getData when it is rendered, a Select will invoke getData when it is validated and a FormTable will invoke getData when it is processed.

      DataProviders leads to a more consistent Page implementation where all control creation logic can be encapsulated in the onInit event or even the page constructor. For example:

      public class CustomerPage extends BorderPage {
      
          private Table table = new Table("table");
          private Select select = new Select("markets");
      
          @Override
          public void onInit() {
              super.onInit();
      
              table.add(new Column("firstname"));
      
              ...
      
              table.setDataProvider(new DataProvider() {
                  public List<Customer> getData() {
                      return getCustomerService().getCustomers();
                  }
              });
      
              select.setDataProvider(new DataProvider() {
                  public List<Option> getData() {
                      List options = new ArrayList();
                      for (Market market : getMarketService().getMarkets()) {
                          options.add(new Option(market.getId(), market.getName());
                      }
                      return options;
                  }
              });
          }
      }
      
      In the example above we use DataProviders for both the Table and Select control. The Table data is only retrieved when the Table is rendered, so in the event of a redirect, the database operation is skipped. The Page is now consistent as all control setup logic is placed inside the onInit event.

      Is onRender still necessary?

      Absolutely. While DataProviders allow control creation logic to be encapsulated within the onInit event, not all data needs to be represented with controls. The Page template (Velocity) for example can be used to render markup for the customers passed from the page. onRender could still be used to retrieve the customers and make it available to the template. For example:

      public class CustomerPage extends BorderPage {
      
          public void onRender() {
              addModel("customers", getCustomerService().getCustomers());
          }
      } 

      <table>
      ...
      
      #foreach($customer in $customers)
        <tr>
          <td>
            $customer.name
          <td>
          <td>
            $customer.holdings
          <td>
        </tr>
      #end
      </table> 

      If an action listener returns false, onRender is skipped and the database operation won't be performed, which is exactly the behavior we want.

      Hope this overview was helpful. In the next installment I'll cover Explicit binding and Dynamic Form Validation, which both simplifies dynamic form creation.

      Saturday, May 15, 2010

      Apache Click v2.2.0 has been released

      Click 2.2.0 final is available for download. Major new features include DataProviders for on-demand data loading and a Page interceptor facility for implementing cross cutting concerns such as security and transaction handling. There are also improved support for dynamic forms and stateful pages.

      New features and improvements:
      • Added DataProvider support for Table, Select, PickList and CheckList providing on demand loading of data. With DataProviders, users won't have to be concerned about which page event (onInit or onRender) to set the data on the control [CLK-640].
      • Added PagingDataProvider interface to support large paginated result sets for Tables [CLK-640].
      • Added a MenuFactory for creating and loading Menus from configuration files. All the static Menu methods have been deprecated and will be removed in a future release.
      • Added an option for MenuFactory to not statically cache menus. This allows developers to cache menus in different scopes such as HttpSession. [CLK-405].
      • Added i18n support for Menus loaded from menu.xml. The menu DTD now includes a new name attribute. By specifying a name attribute in menu.xml, the Menu will attempt to load its label and title from resource bundles [CLK-591].
      • Added a Page Interceptor facility that provides an extension point for code which can listen to key page events and also interrupt normal page processing flow. [CLK-598].
      • Added improved dynamic Form support. Forms can now optionally bypass validation for JavaScript based submissions using the new JavaScript function "Click.submit(formName, validate)" [CLK-638].
      • Added improved dynamic Page and Form behaviour through new helper methods that can bind and validate Forms and Fields before the onProcess page event e.g. in the Page constructor or "onInit" event. The new methods are:
      • Added improved disabled behavior through the following changes:
        • Disabled fields are not processed or validated
        • Disabled field values are not copied to domain objects
        • Disabled fields are automatically enabled if the field has an incoming request parameter, indicating that the field was enabled on the client using JavaScript. Please note that this behavior does not apply to Checkbox or Radio fields. See the setDisabled() javadoc for details [CLK-646].
      • Added new method Container.replace for replacing an existing control with a new control. In previous releases, an exception would be raised if a page or container already contained a control with the same name as the newly added control. In 2.2.0 the replace method is automatically called when adding a control which name matches that of an existing control in the page or container. This behavior will likely only benefit stateful pages since stateless pages are recreated each request [CLK-666].
      • Added methods to Fields for styling their labels. See new methods Field.setLabelStyle(String) and Field.setLabelStyleClass(String). This issue was raised by Stefax [CLK-595].
      • Added methods to Fields for providing styling hints to their containing elements. See new methods Field.setParentStyleHint(String) and Field.setParentStyleClassHint(String). This issue was raised by Stefax [CLK-595].
      • Added trim property to Field for controlling if the Field request parameter is trimmed or not. See new method Field.setTrim(boolean). This issue was raised by Andrey Rybin [CLK-627].
      • Added new Context methods Context.hasRequestParameter(String) and Context.hasRequestAttribute(String).
      • Added support to Select for a default option that can be used to validate non selection against and allows the Select to only populate its optionList at rendering time, instead of during onProcess event. [CLK-641].
      • Improved default autobinding mode to bind both public fields and fields annotated with @Bindable. In previous versions the default autobinding mode only binded public Page fields [CLK-648].
      • Added mock support for user principals and roles. This issue was raised and fixed by Sven Pfeiffer [CLK-585].
      • Added localized Date format pattern support. This issue was raised by Andrey Rybin [CLK-610].
      • Added Polish resource bundle for DateField. This issue was raised and fixed by Rafal Rusin [CLK-624].
      • Migrated controls to import resources through Elements and the getHeadElements method [CLK-647].
      • Improved SpringClickServlet to re-inject transient beans after stateful page deserialization. This feature is only supported when the stateful page instance is created by Click, not Spring [CLK-667].
      • Replaced Page and Control getMessage methods with varargs equivalents [CLK-604].
      • Removed Click core's dependency on Velocity. This issue was raised by by Andrey Rybin [CLK-606].
      • Replaced multiple ClickUtils close methods with a single method accepting a Closeable. This issue was raised by Andrey Rybin [CLK-620].
      • Improved ClickServlet to use the response's OutputStream if the Writer cannot be retrieved [CLK-644].
      • Fixed issue where RadioGroup label referenced a non-existing ID. RadioGroup is now wrapped inside a span tag with the given ID. This issue was raised and fixed by Finn Bock [CLK-577].
      • Fixed DateField to set seconds back to zero. This issue was raised by Andrey Rybin [CLK-664].
      • The menu.dtd has been published to http://click.apache.org/dtds/menu-2.2.dtd. If you want your configuration to conform to the menu.dtd, include the following declaration in your menu.xml:
        <!DOCTYPE menu PUBLIC
        "-//Apache Software Foundation//DTD Click Menu 2.2//EN"
        "http://click.apache.org/dtds/menu-2.2.dtd">
        
      • The new click-2.2.dtd has been published to http://click.apache.org/dtds/click-2.2.dtd. If you want your configuration to conform to the click.dtd, include the following declaration in your click.xml:
        <!DOCTYPE click-app PUBLIC
        "-//Apache Software Foundation//DTD Click Configuration 2.2//EN"
        "http://click.apache.org/dtds/click-2.2.dtd">
        
      New examples:
      • Dynamic Form demonstrates how to dynamically add new Fields at runtime.
      • Dynamic FieldSet demonstrates how to dynamically add a FieldSet at runtime.
      • Dynamic Select demonstrates how to dynamically add fields based on a Select field value.
      • Disabled Demo demonstrates the behavior of disabled fields.
      Enjoy.

      - The Click team

      Saturday, May 1, 2010

      Apache Click v2.2.0-RC1 now available

      Click 2.2.0-RC1 is now available. Major new features include DataProviders for on-demand data loading and a Page interceptor facility for implementing cross cutting concerns such as security and transaction handling. There are also improved support for dynamic forms and stateful pages.

      New features and improvements:
      • Added DataProvider support for Table, Select, PickList and CheckList providing on demand loading of data. With DataProviders, users won't have to be concerned about which page event (onInit or onRender) to set the data on the control [CLK-640].
      • Added PagingDataProvider interface to support large paginated result sets for Tables [CLK-640].
      • Added a MenuFactory for creating and loading Menus from configuration files. All the static Menu methods have been deprecated and will be removed in a future release.
      • Added an option for MenuFactory to not statically cache menus. This allows developers to cache menus in different scopes such as HttpSession. [CLK-405].
      • Added i18n support for Menus loaded from menu.xml. The menu DTD now includes a new name attribute. By specifying a name attribute in menu.xml, the Menu will attempt to load its label and title from resource bundles [CLK-591].
      • Added a Page Interceptor facility that provides an extension point for code which can listen to key page events and also interrupt normal page processing flow. [CLK-598].
      • Added improved dynamic Form support. Forms can now optionally bypass validation for JavaScript based submissions using the new JavaScript function "Click.submit(formName, validate)" [CLK-638].
      • Added improved dynamic Page and Form behaviour through new helper methods that can bind and validate Forms and Fields before the onProcess page event e.g. in the Page constructor or "onInit" event. The new methods are:
      • Added improved disabled behavior through the following changes:
        • Disabled fields are not processed or validated
        • Disabled field values are not copied to domain objects
        • Disabled fields are automatically enabled if the field has an incoming request parameter, indicating that the field was enabled on the client using JavaScript. Please note that this behavior does not apply to Checkbox or Radio fields. See the setDisabled() javadoc for details [CLK-646].
      • Added new method Container.replace for replacing an existing control with a new control. In previous releases, an exception would be raised if a page or container already contained a control with the same name as the newly added control. In 2.2.0 the replace method is automatically called when adding a control which name matches that of an existing control in the page or container. This behavior will likely only benefit stateful pages since stateless pages are recreated each request [CLK-666].
      • Added methods to Fields for styling their labels. See new methods Field.setLabelStyle(String) and Field.setLabelStyleClass(String). This issue was raised by Stefax [CLK-595].
      • Added methods to Fields for providing styling hints to their containing elements. See new methods Field.setParentStyleHint(String) and Field.setParentStyleClassHint(String). This issue was raised by Stefax [CLK-595].
      • Added trim property to Field for controlling if the Field request parameter is trimmed or not. See new method Field.setTrim(boolean). This issue was raised by Andrey Rybin [CLK-627].
      • Added new Context methods Context.hasRequestParameter(String) and Context.hasRequestAttribute(String).
      • Added support to Select for a default option that can be used to validate non selection against and allows the Select to only populate its optionList at rendering time, instead of during onProcess event. [CLK-641].
      • Improved default autobinding mode to bind both public fields and fields annotated with @Bindable. In previous versions the default autobinding mode only binded public Page fields [CLK-648].
      • Added mock support for user principals and roles. This issue was raised and fixed by Sven Pfeiffer [CLK-585].
      • Added localized Date format pattern support. This issue was raised by Andrey Rybin [CLK-610].
      • Added Polish resource bundle for DateField. This issue was raised and fixed by Rafal Rusin [CLK-624].
      • Migrated controls to import resources through Elements and the getHeadElements method [CLK-647].
      • Improved SpringClickServlet to re-inject transient beans after stateful page deserialization. This feature is only supported when the stateful page instance is created by Click, not Spring [CLK-667].
      • Replaced Page and Control getMessage methods with varargs equivalents [CLK-604].
      • Removed Click core's dependency on Velocity. This issue was raised by by Andrey Rybin [CLK-606].
      • Replaced multiple ClickUtils close methods with a single method accepting a Closeable. This issue was raised by Andrey Rybin [CLK-620].
      • Improved ClickServlet to use the response's OutputStream if the Writer cannot be retrieved [CLK-644].
      • Fixed issue where RadioGroup label referenced a non-existing ID. RadioGroup is now wrapped inside a span tag with the given ID. This issue was raised and fixed by Finn Bock [CLK-577].
      • Fixed DateField to set seconds back to zero. This issue was raised by Andrey Rybin [CLK-664].
      • The menu.dtd has been published to http://click.apache.org/dtds/menu-2.2.dtd. If you want your configuration to conform to the menu.dtd, include the following declaration in your menu.xml:
        <!DOCTYPE menu PUBLIC
        "-//Apache Software Foundation//DTD Click Menu 2.2//EN"
        "http://click.apache.org/dtds/menu-2.2.dtd">
        
      • The new click-2.2.dtd has been published to http://click.apache.org/dtds/click-2.2.dtd. If you want your configuration to conform to the click.dtd, include the following declaration in your click.xml:
        <!DOCTYPE click-app PUBLIC
        "-//Apache Software Foundation//DTD Click Configuration 2.2//EN"
        "http://click.apache.org/dtds/click-2.2.dtd">
        
      New examples:
      • Dynamic Form demonstrates how to dynamically add new Fields at runtime.
      • Dynamic FieldSet demonstrates how to dynamically add a FieldSet at runtime.
      • Dynamic Select demonstrates how to dynamically add fields based on a Select field value.
      • Disabled Demo demonstrates the behavior of disabled fields.
      Enjoy.

      - The Click team

      Friday, February 19, 2010

      ClickIDE 2.1.0.0 released: support Apache Click 2.1.0 and Eclipse 3.5

      The latest version of ClickIDE is available. This release supports Click 2.1.0 and Eclipse 3.5.

      ClickIDE is based on Eclipse and the Eclipse Web Tools Project (WTP), and provides extended features for developing web applications using Click.

      Important links:

      Main features:

      • Fast switching between Page classes and templates (Ctrl+Alt+S)
      • Project creation wizard
      • Click page creation wizard
      • Visual editor for the Click configuration file
      • Velocity template editor
      • Spring Framework and Apache Cayenne Integration
      • Integrated Click documentation
      New features and enhancements in 2.1.0.0:
      • Upgraded to Cayenne to 3.0 M6.
      • Added "Use PerformanceFilter" option in the project creation wizard.
      • Added switching comment action in the Velocity editor ([CTRL] + [/]).
      • Added (*) to required attributes in the click.xml editor.

      Enjoy Click!