Monday, January 24, 2011

Apache Click v2.3.0 Release Candidate 1 now available

Apache Click 2.3.0 Release Candidate 1  is available for download. v2.3.0 contains important new features including Ajax support, Page Actions and light-weight stateful controls. In addition there are new documentation, examples and a slew other enhancements.

New features and improvement:
  • Ajax support.
  • Page Action support.
  • Stateful Controls.
  • Improve fields to only be processed if they have an incoming request parameter. This improvement streamlines dynamic forms since fields added at runtime during s POST request won't bind their values and won't be validated for that request. In subsequent requests the Field will have an incoming parameter and so will have it's value bound and validated. Another advantage is that dynamically added Fields won't have their default value overridden in the POST request they were added in. This issue has been raised by Nirmal Solanki [CLK-722].
  • Added automapping support for GAE with a caveat that page templates must be placed under the folders page or pages. This issue was raised by Ke Sun [CLK-639].
  • Added MessagesMapService interface to support pluggable messages map implementations [CLK-655].
  • Improved MessagesMap to be extendable and customizable [CLK-728].
  • Added support for loading DateField translations for month and day names from the JDK. [CLK-650].
  • Added support for Menus that do not have roles defined. If no roles are defined, IsUserInRoles passes a null argument to hasAccess to determine whether access is permitted to menus without roles [CLK-724].
  •  Added support for absolute page classnames when configuring pages in click.xml. Absolute classnames aids with IDE hot-linking and is less confusing to use. [CLK-704]. 
  • Fixed escaping of control values and attributes to be XML friendly in order to support Ajax requests. Previously all HTML characters was escaped, now only the following characters are escaped: <, >, ", ', & [CLK-674]. 
New documentation:

New examples:
Removed:
  • Removed the ability to automatically bypass validation for Forms through JavaScript. This ability was added in 2.2.0 but raised concerns over security and was dropped for 2.3.0. If you used this feature in existing applications, please see the Upgrade path for a safe alternative to bypass validation. We apologize for the inconvenience.

Deprecated:
  • Deprecated stateful page support: Page.setStateful().
  • Stateful pages had the following issues:
    • Stateful pages was introduced to make it easier to store page state across multiple HTTP requests. However developing a stateful page is very different from developing a stateless one and this lead to Click applications that are inconsistent and harder to maintain.
    • In addition stateful page support has never been implemented consistently across the framework and some components did not work correctly.
    • Stateful pages are very coarse grained, making it difficult to control which objects are stored in the session.
    • Stateful pages have also introduced unnecessary complexity in the framework itself, which can now be phased out.
    Unfortunately there is no direct upgrade path from a stateful page. However the majority of use cases are catered for by the new stateful support in the controls: Table, Form, TabbedPanel, Field and AbstractLink.

The Apache Click team

Sunday, November 28, 2010

Apache Click v2.3.0 Milestone 1 now available

Click 2.3.0 Milestone 1  is available for download. This milestone contains important new features including Ajax support, Page Actions and light-weight stateful controls. In addition there are new documentation, examples and other minor enhancements.

New features and improvement:
  • Ajax support.
  • Page Action support.
  • Stateful Controls.
  • Improve fields to only be processed if they have an incoming request parameter. This improvement streamlines dynamic forms since fields added at runtime during s POST request won't bind their values and won't be validated for that request. In subsequent requests the Field will have an incoming parameter and so will have it's value bound and validated. Another advantage is that dynamically added Fields won't have their default value overridden in the POST request they were added in. This issue has been raised by Nirmal Solanki [CLK-722].
  • Added automapping support for GAE with a caveat that page templates must be placed under the folders page or pages. This issue was raised by Ke Sun [CLK-639].
  • Added MessagesMapService interface to support pluggable messages map implementations [CLK-655].
  • Improved MessagesMap to be extendable and customizable [CLK-728].
  • Added support for loading DateField translations for month and day names from the JDK. [CLK-650].
  • Added support for Menus that do not have roles defined. If no roles are defined, IsUserInRoles passes a null argument to hasAccess to determine whether access is permitted to menus without roles [CLK-724].
  •  Added support for absolute page classnames when configuring pages in click.xml. Absolute classnames aids with IDE hot-linking and is less confusing to use. [CLK-704]. 
  • Fixed escaping of control values and attributes to be XML friendly in order to support Ajax requests. Previously all HTML characters was escaped, now only the following characters are escaped: <, >, ", ', & [CLK-674]. 
New documentation:

New examples:

Removed:
  • Removed the ability to automatically bypass validation for Forms through JavaScript. This ability was added in 2.2.0 but raised concerns over security and was dropped for 2.3.0. If you used this feature in existing applications, please see the Upgrade path for a safe alternative to bypass validation. We apologize for the inconvenience.

Deprecated:
  • Deprecated stateful page support: Page.setStateful().
  • Stateful pages had the following issues:
    • Stateful pages was introduced to make it easier to store page state across multiple HTTP requests. However developing a stateful page is very different from developing a stateless one and this lead to Click applications that are inconsistent and harder to maintain.
    • In addition stateful page support has never been implemented consistently across the framework and some components did not work correctly.
    • Stateful pages are very coarse grained, making it difficult to control which objects are stored in the session.
    • Stateful pages have also introduced unnecessary complexity in the framework itself, which can now be phased out.
    Unfortunately there is no direct upgrade path from a stateful page. However the majority of use cases are catered for by the new stateful support in the controls: Table, Form, TabbedPanel, Field and AbstractLink.

The Apache Click team

    Tuesday, September 14, 2010

    Apache Click 2.2.0: Dynamic Form Validation

    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 third and final installment I'll cover conditional form validation. This feature simplifies dynamic Form behavior by allowing developers to control when form validation should be applied. Generally form validation should be applied when the user submits the completed form. However when working with dynamic forms, the form is often submitted (using JavaScript) to the server in an incomplete state in order to add dynamic Fields and components. I'll refer to this as "incomplete submissions" because the form was not completely filled out by the user when the submission occurs.

      Ideally form validation should not be applied to incomplete submissions as the user will be presented any validation errors that occurred. Seeing the errors will be unexpected for the user since they are still busy filling out the form and did not intend to perform a submission.

      Let's look at a simple example. Below we have a page with a required name field and a checkbox that indicates whether the user is married or not. If the married checkbox is checked, a field is displayed for capturing the spouse's name. The spouse's name field is also required.

      public class ValidationDemo extends BorderPage {
      
          Form form = new Form("form");
      
          // The submit button is used to submit the completed form. Note, do not
          // name the Submit button "submit". That will cause a JavaScript error when
      // the button is clicked.
          Submit ok = new Submit("ok");
      
          @Override
          public void onInit() {
              super.onInit();
              form.add(new TextField("fullName", true));
              addControl(form);
              Checkbox married = new Checkbox("married", "Married?");
      
              // We use JavaScrcipt to submit the "incomplete" form when the user
              // clicks the checkbox.
              married.setAttribute("onclick", "form.submit();");
              form.add(married);
      
              form.add(ok);
      
              // Explicitly bind the checkbox
              ClickUtils.bind(married);
              if (married.isChecked()) {
                  form.add(new TextField("spouseName", true));
              }
          }
      }

      Note the highlighted line above. We are using JavaScript to submit the form when the married checkbox is checked.

      Here is a screenshot of the page:

      When the checkbox is checked, the form is submitted and the spouse field is added. Next the form is validated and the required name and spouse error messages is displayed, as seen in the screenshot below:


      We don't want to show the validation messages yet. Particularly problematic is the error message for the Spouse Name field since the user has not seen this field until now.

      One solution is to clear the error messages if the form was submitted but the "ok" Submit button was not clicked, meaning the form was submitted through some other means ie. JavaScript. We can add this logic to the onPost page event:

      ...
      
      @Override
      public void onPost() {
          // Clear form errors if the "ok" submit button was not clicked
          if (!ok.isClicked()) {
              form.clearErrors();
          }
      } 

      This produces the screenshot below:

      This looks better. The Spouse Name has been added and no error messages are shown.

      However this solution is not ideal because the validation step is still performed and we have to manually clear the errors. So is there a better way?

      Indeed there is. By leveraging Explicit binding, one can conditionally switch off form and field validation as follows:

      if(!submit.isClicked()) { 
          form.setValidate(false); 
      }

      Let's revisit our earlier example and update it to use conditional validation:

      public class ValidationDemo extends BorderPage {
      
          Form form = new Form("form");
      
          // The submit button is used to submit the completed form. Note, do not
          // name the Submit button "submit". That will cause a JavaScript error when
      // the button is clicked.
          Submit ok = new Submit("ok");
      
          @Override
          public void onInit() {
              super.onInit();
              form.add(new TextField("fullName", true));
              addControl(form);
              Checkbox married = new Checkbox("married", "Married?");
      
              // We use JavaScript to submit the "incomplete" form when the user
              // clicks the checkbox.
              married.setAttribute("onclick", "form.submit();");
              form.add(married);
      
              form.add(ok);
      
              // Bind the submit button. If it wasn't clicked it means the Form was
              // submitted using JavaScript and we don't want to validate yet
              ClickUtils.bind(submit);
      
              // If the Form was submitted but the submit was not clicked, don't validate
              if(form.isFormSubmission() && !submit.isClicked()) {
                  form.setValidate(false);
              }
      
              if (married.isChecked()) {
                  form.add(new TextField("spouseName", true));
              }
          }
      }

      The screenshot below shows the form after checking the checkbox:



      As you can see, no errors are displayed since the form was not validated.

      Conditional form validation together with explicit binding provides a good combination for adding dynamic behavior to your Click pages and forms.

      This concludes the three part series covering the new features of Click 2.2.0.

      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.