Home | Download | PDF | API | FAQ | Search | Feedback | History

> ## Writing Backing Bean Methods

> Methods of a backing bean perform application-specific functions for components on the page. These functions include performing validation on the component's value, handling action events, handling value-change events, and performing processing associated with navigation.

> By using a backing bean to perform these functions, you eliminate the need to implement the `Validator` interface to handle the validation or the `Listener` interface to handle events. Also, by using a backing bean instead of a `Validator` implementation to perform validation, you eliminate the need to create a custom tag for the `Validator` implementation. Creating a Custom Validator describes implementing a custom validator. Implementing an Event Listener describes implementing a listener class.

> In general, it's good practice to include these methods in the same backing bean that defines the properties for the components referencing these methods. The reason is that the methods might need to access the component's data to determine how to handle the event or to perform the validation associated with the component.

> This section describes the requirements for writing the backing bean methods.

> ### Writing a Method to Handle Navigation

> A backing bean method that handles navigation processing--called an action method--must be a public method that takes no parameters and returns an `Object`, which is the logical outcome that the navigation system uses to determine what page to display next. This method is referenced using the component tag's `action` attribute.

> The following action method in `CashierBean` is invoked when a user clicks the Submit button on the `bookcashier.jsp` page. If the user has ordered more than $100 (or 100 euros) worth of books, this method sets the `rendered` properties of the `fanClub` and `specialOffer` components to `true`. This causes them to be displayed on the page the next time the page is rendered.

> After setting the components' `rendered` properties to `true`, this method returns the logical outcome `null`. This causes the JavaServer Faces implementation to rerender the `bookcashier.jsp` page without creating a new view of the page. If this method were to return `purchase` (which is the logical outcome to use to advance to `bookcashier.jsp`, as defined by the application configuration resource file), the `bookcashier.jsp` page would rerender without retaining the customer's input. In this case, we want to rerender the page without clearing the data.

> If the user does not purchase more than $100 (or 100 euros) worth of books or the `thankYou` component has already been rendered, the method returns `receipt`.

> The default `NavigationHandler` provided by the JavaServer Faces implementation matches the logical outcome, as well as the starting page (`bookcashier.jsp`) against the navigation rules in the application configuration resource file to determine which page to access next. In this case, the JavaServer Faces implementation loads the `bookreceipt.jsp` page after this method returns.

>     public String submit() {
>       ...
>       if(cart().getTotal() > 100.00 &&
>         !specialOffer.isRendered())
>       {
>         specialOfferText.setRendered(true);
>         specialOffer.setRendered(true);
>         return null;
>       } else if (specialOffer.isRendered() &&
>         !thankYou.isRendered()){
>         thankYou.setRendered(true);
>         return null;
>       } else {
>         clear();
>         return ("receipt");
>       }
>     }

> Typically, an action method will return a `String` outcome, as shown in the previous example. Alternatively, you can define an Enum class that encapsulates all possible outcome strings and then make an action method return an enum constant, which represents a particular String outcome defined by the Enum class. In this case, the value returned by a call to the Enum class's `toString` method must match that specified by the `from-outcome` element in the appropriate navigation rule configuration defined in the application configuration file.

> The Duke's Bank example uses an `Enum` class to encapsulate all logical outcomes:

>     public enum Navigation  {
>       main, accountHist, accountList, atm, atmAck, transferFunds,
>       transferAck, error
>     }

> When an action method returns an outcome, it uses the dot notation to reference the outcome from the `Enum` class:

>     public Object submit(){
>       ...
>       return Navigation.accountHist;
>     }

> Referencing a Method That Performs Navigation (page 370) explains how a component tag references this method. Binding a Component Instance to a Bean Property (page 366) discusses how the page author can bind these components to bean properties. Writing Properties Bound to Component Instances discusses how to write the bean properties to which the components are bound. Configuring Navigation Rules (page 465) provides more information on configuring navigation rules.

> ### Writing a Method to Handle an Action Event

> A backing bean method that handles an action event must be a public method that accepts an action event and returns `void`. This method is referenced using the component tag's `actionListener` attribute. Only components that implement `ActionSource` can refer to this method.

> The following backing bean method from `LocaleBean` of the Duke's Bookstore application processes the event of a user clicking one of the hyperlinks on the `chooselocale.jsp` page:

>     public void chooseLocaleFromLink(ActionEvent event) {
>       String current = event.getComponent().getId();
>       FacesContext context = FacesContext.getCurrentInstance();
>       context.getViewRoot().setLocale((Locale)
>         locales.get(current));
>     }

> This method gets the component that generated the event from the event object. Then it gets the component's ID. The ID indicates a region of the world. The method matches the ID against a `HashMap` object that contains the locales available for the application. Finally, it sets the locale using the selected value from the `HashMap` object.

> Referencing a Method That Handles an Action Event (page 371) explains how a component tag references this method.

> ### Writing a Method to Perform Validation

> Rather than implement the `Validator` interface to perform validation for a component, you can include a method in a backing bean to take care of validating input for the component.

> A backing bean method that performs validation must accept a `FacesContext`, the component whose data must be validated, and the data to be validated, just as the `validate` method of the `Validator` interface does. A component refers to the backing bean method via its `validator` attribute. Only values of `UIInput` components or values of components that extend `UIInput` can be validated.

> Here is the backing bean method of `CheckoutFormBean` from the Coffee Break example:

>     public void validateEmail(FacesContext context,
>       UIComponent toValidate, Object value) {

>       String message = "";
>       String email = (String) value;
>       if (email.contains('@')) {
>         ((UIInput)toValidate).setValid(false);
>         message = CoffeeBreakBean.loadErrorMessage(context,
>           CoffeeBreakBean.CB_RESOURCE_BUNDLE_NAME,
>           "EMailError");
>         context.addMessage(toValidate.getClientId(context),
>           new FacesMessage(message));
>       }
>     }

> The `validateEmail` method first gets the local value of the component. It then checks whether the `@` character is contained in the value. If it isn't, the method sets the component's `valid` property to `false`. The method then loads the error message and queues it onto the `FacesContext` instance, associating the message with the component ID.

> See Referencing a Method That Performs Validation (page 372) for information on how a component tag references this method.

> ### Writing a Method to Handle a Value-Change Event

> A backing bean that handles a value-change event must be a public method that accepts a value-change event and returns `void`. This method is referenced using the component's `valueChangeListener` attribute.

> The Duke's Bookstore application does not have any backing bean methods that handle value-change events. It does have a `ValueChangeListener` implementation, as explained in the Implementing Value-Change Listeners section.

> For illustration, this section explains how to write a backing bean method that can replace the `ValueChangeListener` implementation.

> As explained in Registering a Value-Change Listener on a Component (page 356), the `name` component of the `bookcashier.jsp` page has a `ValueChangeListener` instance registered on it. This `ValueChangeListener` instance handles the event of entering a value in the field corresponding to the component. When the user enters a value, a value-change event is generated, and the `processValueChange(ValueChangeEvent)` method of the `ValueChangeListener` class is invoked.

> Instead of implementing `ValueChangeListener`, you can write a backing bean method to handle this event. To do this, you move the `processValueChange(ValueChangeEvent)` method from the `ValueChangeListener` class, called `NameChanged`, to your backing bean.

> Here is the backing bean method that processes the event of entering a value in the `name` field on the `bookcashier.jsp` page:

>     public void processValueChange(ValueChangeEvent event)
>       throws AbortProcessingException {
>       if (null != event.getNewValue()) {
>         FacesContext.getCurrentInstance().
>           getExternalContext().getSessionMap().
>             put("name", event.getNewValue());
>       }
>     }

> The page author can make this method handle the `ValueChangeEvent` object emitted by a `UIInput` component by referencing this method from the component tag's `valueChangeListener` attribute. See Referencing a Method That Handles a Value-change Event (page 372) for more information.