Chapter 12. Ajax and JavaScript remoting – Seam in Action

Chapter 12. Ajax and JavaScript remoting

This chapter covers

  • Combining Ajax and JSF
  • Validating form inputs instantly
  • Invoking components from JavaScript
  • Using Seam as a GWT service

When applications are ported to the web environment, something is often lost in translation: the user experience. Even nontechnical users understand the need to wait for a page to load after each action, evidence of the lack of continuity that plagues many web applications. Ajax provides a way to bring the rich, interactive application (RIA) user experience to the web.

In the previous chapter, you learned how the mission-critical and sometimes daunting task of securing your application is dramatically simplified thanks to Seam. By filling in a few blanks, you’re able to blanket your application with basic security and then fine-tune it with contextual security rules. In this chapter, you’ll witness another example of how Seam helps you transform your application with a handful of keystrokes by leveraging its multifaceted Ajax support. This news is especially promising, since moving to Ajax has proven to be a more costly investment than many product managers first anticipated. One reason is that cross-browser JavaScript is not for the faint of heart, and its problems can put the brakes on your development schedule. Another is that JavaScript code quickly becomes spaghetti, making it difficult to comprehend and even harder to test.

In this chapter, you’ll discover that Ajax-based JSF component libraries and Seam’s JavaScript remoting API offer a refreshed approach to Ajax by putting separation between the application and the low-level XMLHttpRequest object, significantly reducing the risk of letting Ajax through the door. The Ajax-enabled JSF component libraries covered in this chapter, Ajax4jsf and ICEfaces, execute the JSF life cycle asynchronously in response to user interactions, resulting in partial page updates that don’t disrupt the user’s activity. Even better, this exchange is transparent to the developer, who doesn’t have to touch a line of JavaScript. Rather than wait for the user’s next move, ICEfaces has a mechanism for pushing presentation changes to the browser in response to changes in the application state. JavaScript remoting cracks the door open to JavaScript slightly, while still managing to hide the interaction with the server, by allowing server-side components to be executed through JavaScript function calls. Seam’s remoting can also give alternate front ends like GWT access to the Seam component model.

Although simplicity remains the underlying theme in the final part of this book, the key word in this chapter is transparency. The investment you have made in learning about the JSF life cycle, Seam components, and the EL throughout this book pays off and helps you get your application rich quick. We begin by looking at how Ajax is transparently weaved into the JSF component model and the types of interactions this enables.

12.1. Using Ajax with JSF

JSF beat Ajax mania to the scene by nearly a year. The order of events was unfortunate because Ajax would have fit perfectly with the design of JSF as an event-driven framework backed by a server-centric model. Although Ajax wasn’t included in the JSF specification (and still isn’t as of JSF 1.2), innovators recognized the potential of Ajax to close the gap in the JSF vision and adapted it to JSF in an intelligent and efficient manner. This section talks about the right and wrong ways of using Ajax with JSF, the two main component libraries that brought Ajax to JSF, and Seam’s role in Ajax-based JSF requests.

12.1.1. Embracing a server-centric application model

JSF uses a server-side model to handle client-side events. The server then responds with an updated view. Unfortunately, the standard mechanism in JSF for propagating an event from the UI to the server is to use a regular form submit followed by a full-page refresh. This makes for a disruptive and costly event notification, in stark contrast with the goal of Ajax and the rich web.

JSF developers with Ajax-envy (myself being one of them) initially attempted to use Ajax in their JSF applications by stepping outside the JSF component model. User interactions would be trapped by custom JavaScript and the HTML in the rendered page manipulated without JSF’s knowledge. To invoke the JSF life cycle from an Ajax request, form data had to be fabricated to trick JSF into thinking the user had initiated the event. When the response arrived, the rendered HTML would once again be manipulated without JSF’s knowledge.

The trouble you get into when attempting to use ad hoc Ajax in JSF is that the rendered page gets out of sync with the server-side UI component model. The next authentic JSF postback is utterly confused, often resulting in unexpected behavior. Frustrated developers pointed the finger at JSF for being too rigid. The real problem, though, is the developer not appreciating JSF’s server-centric application model and the benefits it provides.

The intent of JSF is to let you develop enterprise applications primarily in Java, with a reasonable amount of declarative markup for connecting Java components to user interface components (a linkage known as binding). Ajax, on the other hand, tempts you to become involved in the low-level concerns of hand-coded Dynamic HTML (DHTML) and JavaScript.

Programming models aside, JSF was designed to manage the UI. When it gets left out of the loop, an impedance mismatch develops. The proper way to use Ajax with JSF is to put JSF in charge of the Ajax communication, thus embracing JSF’s servercentric model. This approach extends the value proposition of JSF to cover the development of rich Java-based applications without needing to introduce the complexity of JavaScript to the process. Both Ajax4jsf and ICEfaces position Ajax so that it honors the JSF model.

12.1.2. Ajax4jsf and ICEfaces open a communication channel to JSF

The main draw of Ajax is that it allows communication between the browser and the server to proceed in the background without disrupting the user. In a JSF application, it’s just as important to keep an open channel of communication between the rendered page and the server-side UI component tree. That’s because, as soon as an Ajax request is issued, the rendered page is at risk of becoming stale. It must be synchronized with the server-side UI component tree as soon as possible to prevent its integrity from being compromised.

Although the outlook for the JSF and Ajax marriage may seem grim from this description, Ajax4jsf and ICEfaces each provide a lightweight Ajax bridge that keeps the lines of communication open. Even better, it’s mostly transparent to the developer. Although the first ICEfaces release (August 2005) came six months earlier than Ajax4jsf (March 2006), I want to start by discussing Ajax4jsf because it enables you introduce Ajax into JSF incrementally.

Ajax-enabling JSF with support from Ajax4jsf

The challenge of introducing Ajax into JSF is that the standard UI components, and plenty of third-party UI components, have no awareness of Ajax. Rather than mandating that you switch to an Ajax-based UI component set, RichFaces developer Alexander Smirnov developed a way to weave Ajax into JSF transparently, a solution now known as Ajax4jsf. The mechanism he invented is so transparent, in fact, that it can be used to “Ajax-enable” any JSF page without the UI components having any awareness they’re participating in an Ajax request. This one library took JSF from being Ajax-inept to being one of the most compelling approaches to Ajax.

 

Ajax4jsf or RichFaces—which is it?

RichFaces is a visual JSF component set that’s based on the Ajax4jsf concept and APIs. Ajax4jsf was once its own project, but now it’s bundled with RichFaces. The Ajax4jsf tags are geared specifically toward adding Ajax capabilities to non-Ajax components, such as the standard JSF palette. RichFaces components natively support the Ajax4jsf interaction. The rich in RichFaces credits both its support for Ajax and its attractive look and feel.

 

While the Ajax4jsf component library contains a broad set of UI component tags, the tag that gets the heaviest use, almost disproportionately so, is <a:support> (often written as <a4j:support>). It’s used to bind a user-initiated JavaScript event to a serverside action invoked via Ajax and to designate regions of the page that get rerendered from the Ajax response, encompassing the essence of Ajax4jsf.

A patchwork of updates

The Ajax4jsf process is depicted in figure 12.1. When a request is sent out by Ajax4jsf, the JSF life cycle is invoked, just like with a standard JSF request. However, since the request occurs using Ajax, the page doesn’t change, at least not immediately. To ensure that the rendered page doesn’t become stale, Ajax4jsf lets you declaratively control which areas of the UI to synchronize. Prior to the rendered page being sent back to the Ajax engine, Ajax4jsf extracts the corresponding markup and returns only a set of “patches” (i.e., XHTML fragments) to the browser. The Ajax engine cuts out the dead areas of the UI and stitches in the replacements. Since the state of these areas remains consistent with the server-side UI component tree, any JSF-related actions triggered in those areas behave as expected.

Figure 12.1. The Ajax4jsf request processing. Ajax4jsf filters the JSF response and the Ajax engine that receives the partial response stitches those changes into the rendered page.

Let’s put this process into practice on the golf course search screen. Right now, when the user clicks the Search button to filter the results, it causes a full-page refresh. It would be faster and less disruptive to simply replace the results table, the area of the page we want to rerender. First, we need to assign an id to the results panel, giving it a “handle”:

  <rich:panel id="searchResultsPanel">
    <f:facet name="header">Course search results</f:facet>
    <rich:dataTable var="course" value="#{courseList.resultList}" ...
  </rich:panel>

Next, we nest the <a:support> tag within an input field in the search form, tying a JavaScript event triggered by this field to an invocation of the JSF life cycle. To ensure that the search runs as soon as possible but not before the user is done typing, we choose to bind to the input field’s onblur event (i.e., when it loses focus). We also tell Ajax4jsf which area of the page to rerender by declaring a component id in the reRender attribute:

  <h:input value="#{courseList.course.name}">
    <a:support event="onblur" reRender="searchResultsPanel"/>
  </h:input>

When the user tabs or clicks away from the input field, an Ajax request is sent, invoking the JSF life cycle just as though the user had clicked the Search button. But in this case, the response is filtered by Ajax4jsf and only the results panel is sent back. The page is then updated incrementally to reveal the new search results.

The search is able to execute without an explicit action because the Query component automatically detects when the search criteria has changed. You may have a situation that requires an explicit action to be called in order for the search to execute. Ajax4jsf lets you specify either an action or an action listener on the <a:support> tag, using the action and actionListener attributes, respectively. This turns the <a:support> tag into a UI command component, which isn’t triggered by a click but rather a JavaScript event:

  <a:support event="onblur" reRender="searchResultsPanel"
    action="#{hypotheticalSearchAction.search}"/>

If we were to continue Ajax-enabling every input field in the search form, the only problem would be having to specify the reRender attribute each time. Fortunately, Ajax4jsf supports a way to make certain branches of the tree support “autografting.” By wrapping the <a:outputPanel ajaxRendered="true"> tag around a region of the page, it tells Ajax4jsf to automatically rerender that region whenever an Ajax request passes through the Ajax engine. Let’s apply this to the search results panel:

  <a:outputPanel ajaxRendered="true" layout="none">
    <rich:panel>
      <f:facet name="header">Course search results</f:facet>
      <rich:dataTable var="course" value="#{courseList.resultList}"...
    </rich:panel>
  </a:outputPanel>

With the autografting output panel in place, the <a:support> tags no longer have to specify the reRender attribute. If you’re doing other Ajax operations on the page, you can localize the Ajax activity that triggers automatic rerendering by wrapping a portion of the page in <a:region>. In this case, you might wrap the search form and results panel.

Although it may seem like a lot of work to merge the changes back into the UI, this work is far outweighed by the benefits. It ensures the integrity of the page is maintained, it makes Ajax transparent to the developer, and, since the response contains only necessary updates and not a full HTML document, JSF can behave like an efficient event-driven framework and the user’s activity isn’t disrupted by a page refresh.

Ajax4jsf lets you adopt Ajax without having to write JavaScript or replace your existing components, but it still requires that you do a fair amount of work to configure the Ajax interactions. Depending on what you’re trying to accomplish, this can be either a good or a bad thing. One of the limitations of Ajax4jsf is that the marked regions of the page are synchronized even if the markup hasn’t changed. Regions that aren’t specified are prone to falling out of date. What you are basically missing is intelligent synchronization of the UI, a central concern in ICEfaces.

Intelligent UI synchronization with ICEfaces

ICEfaces is an Ajax extension for JavaServer Faces that regards Ajax as a framework concern rather than a developer concern. Ajax-based JSF applications using ICEfaces are virtually indistinguishable from non-Ajax JSF applications. The key lies with the ICEfaces rendering process. Rather than rendering to a stream that’s sent directly to the browser, each view is rendered into a Document Object Model (DOM) on the server, another progression of the UI component tree. The changes to the DOM are detected after each invocation of the JSF life cycle and only the corresponding markup is sent to the browser. As with Ajax4jsf, an Ajax bridge resident in the browser is responsible for merging these updates into the page, as illustrated in figure 12.2.

Figure 12.2. An illustration of how changes in the UI component tree are channeled through the ICEfaces Ajax bridge and merged back into the rendered page in the browser. The numbers indicate the sequence of events

There are two key benefits to the ICEfaces approach (which is known as Direct-to-DOM [D2D] rendering). First, it reflects an efficient use of the network, making it especially suitable for mobile applications. Second, the developer doesn’t need to decide which areas of the page need to be rerendered when an event is triggered—that’s something the framework decides at runtime. In fact, the developer doesn’t have to do anything to Ajax-enable the UI components on the page. Ajax is baked in at a much deeper level so that every interaction is channeled through an Ajax request.

 

Tip

If a long-running conversation isn’t active, the conversation id changes during the Ajax request. Since Seam automatically appends the conversation id to Seam UI command components, this confuses ICEfaces into thinking that areas of the page have changed, resulting in a much larger Ajax response than necessary. To remedy this problem, you either need to ensure that the conversation id isn’t rendered somewhere in the HTML markup or operate within the context of a long-running conversation.

 

Let’s look at the course search example again, this time augmenting it using ICEfaces. Since it’s not necessary to declare which areas of the page are synchronized, we’re only concerned with the search form. Here’s one of the input fields and the submit button:

  <h:inputText value="#{courseList.course.name}"/>
  <h:commandButton value="Search"/>

Hmm. That’s interesting—no special Ajax tags. As I mentioned, ICEfaces transparently adds Ajax interactions to the page. It does so by replacing the standard JSF component renderers with renderers cognizant of the D2D mechanism. In order for the page to be updated in place, you simply forgo use of a JSF navigation event, guaranteed in this case since an action isn’t specified in the UI command button. That raises an important point. Although requests are made over Ajax, JSF navigation rules are still honored. The same goes for Ajax4jsf.

There is a key improvement that can be made in the ICEfaces example. Currently, the Ajax request only happens when the Search button is activated, whereas in the Ajax4jsf example, the search occurs when the input field loses focus. This behavior is accomplished in ICEfaces using a feature known as partial submit. While it’s possible to trigger a partial submit using a built-in JavaScript function, in the spirit of transparency we use the ICEfaces input component tag to hide this JavaScript behind declarative markup. This tag also brings the benefit of component styling.

  <ice:inputText value="#{courseList.course.name}" partialSubmit="true"/>

The partialSubmit attribute activates the same behavior as the <a:support event="onblur"> tag in Ajax4jsf. Partial submit is explored in more depth in section 12.2.

Ajax4jsf and ICEfaces are about more than just Ajax. They are about letting you perform incremental page updates synchronized from the state on the server. You no longer have to design pages around the full-page refresh model. Instead, you can consider fine-grained manipulation of the page to achieve rich effects in the application. The patchwork of updates that are merged back into the rendered page behave as though they’d been there all along (meaning when the page was initially rendered). In addition to incremental page updates, RichFaces and ICEfaces offer styling of components, rich widgets, drag and drop, visual effects, and many more features that set your application apart from a classic web application.

The big question at this point is, what’s Seam’s role in all of this Ajax stuff? That’s the real beauty of it. Seam just keeps doing what it does best.

12.1.3. Seam’s role in Ajax-based JSF requests

While the Ajax requests allow the page to continuously interact with Seam, there’s nothing that Seam has to do differently. The JSF life cycle is still invoked and therefore Seam treats each request just as it would any other postback. That doesn’t mean Seam has nothing to add, though. On the contrary, you find that Seam’s stateful design lends itself perfectly to the Ajax-enabled JSF environment. Here are a few ways Seam adds value:

  • Maintain server-side state— Seam can connect the state from one Ajax request to the next, avoiding the negative impact of pounding the server’s resources. Both the page scope and a long-running conversation work well here. Seam can even facilitate an application transaction performed entirely over Ajax.
  • Contribute outjected context variables— Any action invoked during an Ajax request can trigger bijection. The outjected context variables are available to the regions of the view being rerendered.
  • Dry-run the JSF life cycle— Ajax4jsf can ask JSF to run through the life cycle without performing actions or navigations to verify that form data is acceptable. Seam’s integration with Hibernate Validator is of most interest here.
  • Notify changes in application state— Seam’s event/observer model, its asynchronous dispatcher, and its integration with JMS offer ways to notify components of a change in the application’s state. When combined with ICEfaces’ Ajax Push, presentation changes can be sent to browsers with having to wait for interaction from the user.

Aside from the last point, covered in detail in section 12.3, the items in this list remain consistent with points made throughout the book. The only difference now is that everything is happening in closer to real time and the browser isn’t spinning its wheels reloading the page. You do need to be aware that Ajax requests occur more frequently, so there’s a greater chance that multiple requests in the same conversation will arrive at the server simultaneously. See the accompanying sidebar on the topic of conversation contention.

No configuration is necessary to use RichFaces/Ajax4jsf with Seam. As long as the RichFaces JAR files are present on the classpath and the SeamFilter is registered in the web.xml descriptor, Seam automatically activates the Ajax4jsf filter. Seam doesn’t automatically configure ICEfaces because it requires more than just a filter. Consult the output of the ICEfaces version of seam-gen or the ICEfaces reference documentation for instructions.

 

Concurrent Ajax requests contending for ownership of the conversation

Seam serializes access to conversations, requiring requests to obtain a lock in order to restore a long-running conversation. A common problem encountered when using Ajax4jsf with Seam is contention for a conversation lock, reported by the error message “The conversation ended, timed out or was processing another request.” This problem can happen when multiple Ajax requests requesting the same conversation arrive at the server simultaneously. If the amount of time that a request has to wait exceeds the concurrent request timeout, Seam will abort the request.

One solution is to ensure that Ajax4jsf requests are serialized so that they never contend for a conversation. Related requests are placed into a named sequence using the eventsQueue attribute on RichFaces and Ajax4jsf component tags:

      <a:support event="onblur" eventsQueue="nameOfSequence" .../>

For information about eventsQueue, see the RichFaces reference documentation.[1]

1http://www.jboss.org/file-access/default/members/jbossrichfaces/freezone/docs/devguide/en/html/index.html

There is still the problem of Ajax and non-Ajax requests contending for the same conversation. To minimize the chance of a timeout occurring as the result of a lock contention, you can increase the timeout period. The timeout value (in milliseconds) is set by configuring the built-in component named manager in the component descriptor:

     <core:manager concurrent-request-timeout="5000" .../>

You should try to eliminate concurrent requests for a conversation before increasing this timeout since leaving threads waiting on the server can impact performance.

Contention for the conversation isn’t seen when using ICEfaces since the ICEfaces framework automatically synchronizes requests from the same page to ensure that the server-side DOM remains uncorrupted.

 

I walk you through more examples showing how the abstraction offered by Ajax4jsf and ICEfaces can be leveraged to enhance the user experience. We first explore live form validation using partial submit and then look at how ICEfaces can push changes in application state to the client without having to wait for the user to perform an action.

12.2. Partial form submits

One of the most frequently requested features in JSF is client-side form validation. Although there are certainly benefits to the performance and near real-time execution of client-side validation, there are equal benefits to having these validations performed on the server instead. Even if the validation passes in the UI, it’s still necessary to validate on the server since JavaScript validation can’t be trusted (execution of JavaScript is voluntary). In addition, validations often need access to server-side resources to arrive at a decision. Thus, client-side validation doesn’t provide that much value. What developers are really asking for is instant, or “live,” validation. That doesn’t mean it has to happen strictly on the client.

12.2.1. Live validation

Both Ajax4jsf and ICEfaces accommodate live form validation using a feature known as partial submit. You have seen this feature used once already with ICEfaces as a way to trigger an Ajax-based form submit from a JavaScript event. What you may not realize is that this flag also enables intelligent form processing, resulting in only partial validation of the form. Ajax4jsf separates the two concerns by letting you control whether one or all of the inputs are validated when an Ajax form submit is triggered from a user-initiated event.

Before getting into the details of how live validation is set up, I want to briefly discuss how server-centric validation, based primarily on Hibernate Validator constraints, centralizes validation concerns, reduces duplication of effort, and ensures that validations are consistent across the application. This discussion sets the stage for the examples that follow.

End-to-end constraints using Hibernate Validator

Using partial form submits, it’s possible to enforce Hibernate Validator constraints instantly, as well as other JSF validators registered on a field, without having to duplicate the effort of writing client-side validators. It’s pretty easy to branch out from there and apply business validations as well. In the end, all the validation work is done in one place, at one time.

As a reminder, Hibernate Validator annotations define constraints on properties of a model object. You first saw these annotations in Chapter 2 when they were translated by seam-gen from constraints on database fields and added to the properties of the entity classes. A wealth of constraints are provided for you out of the box. For instance, the @Email annotation on the emailAddress property of the Member entity ensures that the syntax of the email address is valid:

  @Column(name = "email_address", nullable = false)
  @Email @NotNull
  public String getEmailAddress() {
      return emailAddress;
  }

You can also write your own constraint by defining a custom annotation, implementing the Hibernate Validator interface, and declaring the implementation in the @ValidatorClass meta-annotation on your custom annotation. For a list of built-in constraints and information about how to author your own, see the Hibernate Validator reference documentation.[2]

2http://www.hibernate.org/hib_docs/validator/reference/en/html/validator-defineconstraints.html

In Chapter 3, you learned that it’s possible to stretch Hibernate Validator constraints all the way to the view by using a Seam model validator tag (<s:validate> within an input component or <s:validateAll> around a set of input components). To take it a step further, constraints can be enforced in response to a user-initiated event using the partial submit feature in either Ajax4jsf or ICEfaces. Let’s first look at the ICEfaces approach.

Intelligent form processing using ICEfaces

The partial submit in ICEfaces is more accurately described as intelligent form processing and partial validation rather than an incomplete form post, as the name implies. Before explaining how it works, let’s first consider the problem to be solved.

If you submit a form while the user is still working on it, it’s likely that there are required fields that the user hasn’t gotten to yet. When the Process Validations phase of the JSF life cycle runs, it would normally flag these required fields as invalid and the page would be sprinkled with validation errors. As a result, the application appears impatient with the user’s progress. ICEfaces circumvents this issue by temporarily marking required fields as optional during a partial submit. This allows the validation process to focus on the fields the user has already filled out, for which the user will welcome validation feedback.

As you saw earlier, partial submit is enabled using the ICEfaces input component. From there, getting the Hibernate Validator constraints to be enforced when the field loses focus is just a matter of registering the Seam model validator on the input:

  <ice:inputText id="emailAddress" value="#{newGolfer.emailAddress}"
    required="true" partialSubmit="true">
    <s:validate/>
  </ice:inputText>

If you’re using a seam-gen application, you can decorate the input component with the provided composition template to preclude the use of the model validator tag:

  <s:decorate id="emailField" template="layout/edit.xhtml">
    <ui:define name="label">Email address</ui:define>
    <ice:inputText id="emailAddress" value="#{newGolfer.emailAddress}"
      required="true" partialSubmit="true"/>
  </s:decorate>

That’s pretty much all there is to it. Let’s try this with Ajax4jsf.

Singling out a field using Ajax4jsf

The way that Ajax4jsf defines partial submit is more true to the name. You instruct Ajax4jsf to process a single field by enabling the ajaxSingle attribute on <a:support>, overriding the default behavior of submitting the entire form. Once again, this prevents overeager validation of form fields. However, instead of temporarily marking fields as optional, like ICEfaces, Ajax4jsf pretends as though the form has only one field, the one that triggered the event. The benefit is that the user only sees a validation error for that field, no matter what state the other fields are in. The downside is that this feature cannot be used if you need to do interfield validation.

To add instant validation of the email address using the Hibernate Validator constraint with Ajax4jsf, you nest both <a:support> and <s:validate> in the input component:

  <h:inputText id="emailAddress" value="#{newGolfer.emailAddress}"
    required="true">
    <a:support id="emailAddressCheck" event="onblur" reRender="emailAddress"
      ajaxSingle="true" bypassUpdates="true"/>
    <s:validate/>
  </h:inputText>

You can use the component template included in the seam-gen project as before to isolate the markup and incorporate the validation error message. Figure 12.3 shows an email address validation error in the registration form.

Figure 12.3. Live validation in the UI performed using partial submit

Notice in this example I snuck in another new attribute, bypassUpdates. This attribute tells Ajax4jsf to short-circuit the JSF life cycle as soon as the Process Validations JSF life-cycle phase is complete. The motivation for doing this is to get the validation done quicker and to prevent the partial form submit from making changes to the model. If a managed entity is loaded in the editor, and you aren’t using manual flushing, updating the model would result in the database being updated at the end of the request. You can leave off bypassUpdates if you do want the model to be updated, perhaps to allow the user to switch between conversations without losing the values entered.

In addition to applying conversion and model validations on the trip to the server, you can weave in some business-savvy validations in an action or event listener method.

12.2.2. Business-savvy validations

The Hibernate Validator annotations focus primarily on constraints. To perform validations that are driven by business rules or contextual state, you need to turn to an action component, which is better equipped to handle these “business-savvy” validations.

Once again, you’ll be using partial form submit, but this time you need to register a method that executes custom validation logic (or delegates the work to another component). You have a wide variety of options for associating a method with an input. My preference is to listen for the component’s value change event. Let’s consider an example where a business-savvy validation is needed in the Open 18 registration form.

Choosing a unique username can often be a challenge, especially on a popular site. Therefore, we want to validate not only that the username is syntactically correct but also that it isn’t already taken. The first step is to define a value change listener method on the RegisterAction component that performs the check and warns the user if it’s taken. When you’re writing a method that listens for a value change event, it’s important to understand that the submitted value is in a transient state on the component and hasn’t yet been transferred to the property bound to the input. You access the submitted value by calling the getNewValue() method on the ValueChangeEvent object passed as an argument to the method. From there, you can check for a duplicate username:

  public void verifyUsernameAvailable(ValueChangeEvent e) {
      String username = (String) e.getNewValue();
      if (!isUsernameAvailable(username)) {
          facesMessages.addToControl(e.getComponent().getId(),
              "Sorry, username already taken");
      }
  }

  public boolean isUsernameAvailable(String username) {
      return entityManager.createQuery(
          "select m from Member m where m.username = ?1")
          .setParameter(1, username).getResultList().size() == 0;
      }
  }

The next step is to register this method as a value change listener on the username field:

  <h:inputText value="#{newGolfer.username}"
    valueChangeListener="#{registerAction.verifyUsernameAvailable}"...>

Let’s now shift the focus from slapping the user’s wrist to playing the role of a helping hand.

12.2.3. Working alongside the user to fill out a form

Since Ajax4jsf and ICEfaces have the ability to rerender areas of the page, it’s possible to assign values to form inputs or alter the composition of the form (i.e., add, remove, or modify elements). These changes become visible when the presentation changes are delivered to the browser. Let’s consider a simple example.

Each U.S. zip code maps to a city and state. We can save the user time by automatically populating the city and state fields when the user enters a zip code. To accomplish this task, a value change listener is registered on the zip code field. Any time the value of that field changes and the value is considered valid, a value change event is fired and the listener called. Within the listener, the zip code is used to look up the city and state, and those values are assigned to the values of the city and state input components.

Before implementing the logic, we need to determine how to get a handle on the city and state input components from within an event listener method. A UI component is located by passing its key to the findComponent() method on any other UI component. Seam provides a map named uiComponent that’s used for the same purpose, except it searches from the root of the UI tree. That brings us to the key that’s used as the lookup value.

JSF stores each component in the tree under a client id, which is a qualified path to the component. This path is built by combining the component’s ID with the ID of each ancestor component that is a NamingContainer, delimited by colons. For instance, the client id of the city component is facility:cityField:city, where facility is the ID of the form, cityField is the ID of the field decorator, and city is the ID of the input. To start the search from the root of the UI component tree, you add a leading colon to the path.

You can also get a reference to a UI component by binding it to a property of a Seam component using the binding attribute on the component tag. This works just like binding an input value to a property, only in this case, you’re binding the UI component itself.

Let’s get back to work. For the purpose of this demonstration, the value change method uses a canned response, but you can just as easily consult a database, web service, or service layer to get real values. This code also shows two ways to locate a UI component:

  @In Map<String, UIComponent> uiComponent;
  public void updateCityAndState(ValueChangeEvent e) {
      String zipCode = (String) e.getNewValue();
      UIComponent city = e.getComponent()
          .findComponent(":facility:cityField:city");
      UIComponent state = uiComponent.get("facility:stateField:state");
      if ("20724".equals(zipCode)) {
          ((EditableValueHolder) city).setSubmittedValue("Laurel");
          ((EditableValueHolder) state).setSubmittedValue("MD");
      }
  }

The final step is to register this method to listen for the value change event on the zip field. The Ajax4jsf version, shown here, marks the fields to be rerendered, which isn’t necessary when using ICEfaces:

    <h:inputText id="zip" size="5" value="#{facilityHome.instance.zip}"
     valueChangeListener="#{facilityHome.updateCityAndState}">
     <a:support event="onblur" bypassUpdates="true" ajaxSingle="true"
       reRender="zipField,cityField,stateField"/>
    </h:inputText>

Most of this section has focused on features that are supported in both Ajax4jsf and ICEfaces, highlighting the slightly different approach taken by the two frameworks. In the next section, we look at Ajax Push, a feature pioneered by ICEfaces that allows server-initiated asynchronous presentation updates.

12.3. Ajax Push with ICEfaces

The other distinguishing feature of ICEfaces is its Ajax Push (aka “Comet”) capability. The A in Ajax stands for asynchronous, and ICEfaces is truly asynchronous. Not only is the page updated in the background in response to user events, but the page can also be updated from the server at any time, independently of user events. One use for this is to send users notifications (for instance, to notify a user when it’s his or her tee time), but what is really interesting is to use Ajax Push for collaboration between multiple users.

Adding Push features to your ICEfaces application is straightforward: first, update the model with the current state; then, notify those users interested in the current state. Updating the model is a basic function of a JSF application; how do we update the users? Let’s jump into an example to find out.

In Chapter 10, you developed a module that allows golfers to enter their score for a round of golf. One of the driving factors for a golfer to publish a round is to get ranked on the leaderboard (i.e., best scores per tee set). For simplicity of demonstration, let’s assume that the leaderboard is managed “in-memory” in an application-scoped component, shown in listing 12.1. Each time a round is entered by a golfer, an event named roundEntered is raised, which broadcasts the Round instance. The leaderboard manager observes this event and attempts to rank the round. This is where Ajax Push comes in. If the round gets ranked, ICEfaces is instructed to immediately rerender the pages associated with the corresponding leaderboard group as a result of a call to the SessionRenderer.render() method. The page changes are calculated by ICEfaces and are pushed to the user’s browsers.

Listing 12.1. A component that manages and renders the leaderboards

So how does a user become a member of the group for a leaderboard? First, the user is presented with a select menu of tee sets. After making a selection, the user clicks a UI command button, which binds the tee set selection to the teeSet property of an action component and invokes the followLeaderboard() method on that same component:

  public void followLeaderboard() {
      SessionRenderer.addCurrentSession("leaderboard-" + teeSet.getId());
  }

Once the user is a member of a leaderboard group, whichever page the user is currently viewing will be updated incrementally as soon as that group is rendered. For instance, if a user is viewing a leaderboard for a tee set when a new round becomes ranked, the score appears immediately in the list.

Using just two methods on SessionRenderer, we’ve transformed our application into a new communication tool that lets users keep up with their favorite golfers in real time. The development methodology is also natural: build a conventional JSF application with Seam; turn it into an Ajax application by including the ICEfaces JAR files; then make it into a multiuser application by invoking server-side rendering in response to a specific application event.

The possibilities of what you can do with an Ajax-based JSF component palette are virtually endless. Unfortunately, this chapter is not, so the story must end here. To get the most out of these libraries, I recommend consulting a dedicated resource on the topic. Max Katz, one of the developers of RichFaces, provides in-depth coverage of RichFaces in his book Using RichFaces (Apress, 2008). For more information on ICEfaces, check out icefaces.org[3] or Ajax in Practice (Manning, 2007), featuring Ted Goddard from the ICEfaces project. You may be tempted to mix Ajax4jsf and ICEfaces, or any Ajax-enabled component set for that matter, but it’s not recommended. The Ajax engines collide with each other while attempting to manipulate the rendered page. Expect this situation to improve once JSF 2.0 is finalized, which will define a standard Ajax mechanism for JSF components. There’s no such restriction for incorporating additional non-Ajax component sets.

3 The developer guides for ICEfaces are located at http://www.icefaces.org/main/resources/documentation.iface.

As cool as declarative Ajax using JSF sounds, you may be looking for a way to do Ajax in Seam without JSF, perhaps using a high-level JavaScript library such as Dojo or jQuery. The Seam developers recognized that there is value in being able to talk to a Seam component directly from JavaScript and therefore introduced the JavaScript remoting module.

12.4. JavaScript remoting to Seam

JavaScript remoting is an alternative to Ajax-based JSF requests for establishing a channel of communication between the browser and the server. It supports using JavaScript to invoke a method on a server-side object as if it were local to the browser. Seam’s JavaScript remoting library is inspired by the Direct Web Remoting (DWR) project,[4] but designed specifically for accessing Seam components. The interaction with the server-side object is performed using Ajax requests, but the requests are encapsulated within dynamically generated JavaScript proxy objects, so you never have to interface with the XMLHttpRequest object directly.

4http://getahead.org/dwr

In JavaScript remoting, the client (browser) and the server (Seam container) are fused together as one, establishing a continuity between local and remote operations. The interchange between the client and server during a remoting request resembles a conventional remote procedure call (RPC) over Java RMI or SOAP, except that JavaScript remoting is far more lightweight and mostly transparent to the developer.

Here’s a sampling of tasks that are well suited as JavaScript remoting tasks:

  • Facilitating a user interaction that’s tangential to the rendered page
  • Persisting entities that don’t have a visual representation
  • Starting and completing tasks in a business process
  • Sending an email in response to a user-triggered event
  • Transmitting a user interface error or statistic to the server to be logged
  • Monitoring or polling for a value maintained on the server

This section provides an overview of the JavaScript remoting technique, explains how to expose your Seam components as endpoints, and presents examples that use this style of browser-to-server communication.

12.4.1. Transparent Ajax

Throughout this book, I’ve demonstrated the ability of Seam’s component model to manage state and provide access to a wide range of technologies. By incorporating Seam’s remoting library into your application, you enable JavaScript to tap into that server-side model and reap its benefits. In the same way that the @Name annotation on a component makes that component accessible to JSF and the EL, the @WebRemote annotation on a component method makes that method accessible to JavaScript, effectively binding JavaScript code to server-side components with little effort.

Communicating through stubs

In order for this transparency to be possible, Seam dynamically generates JavaScript classes[5] that represent the server-side components. These classes are known as stubs. As far as JavaScript is concerned, the stub object is the remote object.

5 A JavaScript class is a misnomer since JavaScript is technically a prototype-based language. However, it’s possible to pretend that the prototype construct is an actual class if you treat it as one.

The stub is responsible for carrying out method execution on the server-side component instance. When a method is invoked on the stub, a new Ajax request is prepared and sent across the wire to the server. The request communicates the method to execute and carries with it parameters that need to be passed to the remote method. If the method has a return value, that value is encoded into the response of the Ajax request. As the response comes back across the wire, it’s received by the remoting framework, which converts the return value, if present, into a JavaScript object. This process is illustrated in figure 12.4.

Figure 12.4. The translation of a method call on a stub to a method call on a server-side component

What it comes down to is that JavaScript remoting enables the browser to speak the native tongue of the server. Although it may seem like the execution is happening in the local lingo—JavaScript—in reality the server is executing the code and the stub objects are marshaling the data back and forth.

Cutting costs by sidestepping JSF

JavaScript remoting is about cutting out the middleman and giving JavaScript access to Seam components without the overhead of restoring the JSF component tree and venturing through the JSF life cycle. The product is a much smaller request. It also gives the browser direct access to the return value of the method invoked, which is not straightforward in JSF.

Seam remoting requests target the SeamResourceServlet rather than the JSF servlet, effectively sidestepping the JSF life cycle. Of course, you never interface with this servlet directly since the negation with the servlet is handled by the stub. When the method is invoked, it has full access to components and context variables. What’s not present, though, is the JSF component tree. That means you can’t access page-scoped or UI components during a remoting request.

Let’s see how to get Seam to generate the stubs, how they’re used to perform remote method invocations, and how the return value can be captured in your JavaScript code.

12.4.2. Giving the browser access to Seam components

The reason acronyms like RPC and SOAP give developers the chills is because they require a lot of commitment. Surely, Seam remoting would suffer the same fate if it were difficult to set up. The good news is that it’s not. In fact, it’s shockingly easy. Only two steps are involved in making your server-side component accessible to your JavaScript code:

  • Declare one or more methods on the component as accessible via remoting.
  • Import the JavaScript remoting framework and stub objects into the browser.

The first step is a necessary formality. Seam could allow remote access to methods across all components, but there is an element of security to be concerned about. Therefore, remoting is disabled for a method unless made exempt from this constraint. If this discussion worries you, realize that remoting just adds a new path to the method, not a more insecure one. You can use the restrictions you learned about in Chapter 11 to lock down methods from unauthorized users, regardless of how they’re called.

The second step is what builds the JavaScript stubs and other auxiliary types. Fortunately, Seam makes this a one-liner. Let’s consider how each step is accomplished.

Declaring a remoting method

You declare methods that you want to be involved in remoting requests using the @WebRemote annotation, summarized in table 12.1. The @WebRemote annotation is placed differently depending on whether you’re exposing a method on an EJB component or a JavaBean. To provide access to a method on an EJB component, you add the @WebRemote annotation to the method declaration on the local interface annotated with @Local. The remote EJB interface isn’t supported. To provide access to a JavaBean, you simply add the annotation to a method on the JavaBean class.

Table 12.1. The @WebRemote annotation

Name:

WebRemote

Purpose:

Declares that the method is allowed to be invoked through the JavaScript remoting library. The JavaScript stub object that Seam generates for this component will include this method.

Target:

METHOD

Attribute

Type

Function

exclude String[] A list of dot-notation paths that dictate which properties of the return object should be filtered out. Only relevant if a value is returned. Default: none.

There’s nothing special about a remoting method. It can accept any number of parameters of any type and can have a return value. For the most part, the type conversions are handled as you’d expect. The main difference is how the call to the method is handled. If the method returns a value, it’s received by the browser asynchronously. The @WebRemote annotation can declare certain properties on the return object, using dot notation, that should be filtered out (nullified) before the object is returned to the browser.

Once the return object is transferred into the JavaScript context, it’s accessed using the same methods that you’d use in Java. That includes maps, collections, and built-in Java types like java.util.Date. Transparency is the key here.

 

Note

If you add a @WebRemote method to a hot deployable class, you need to restart the application for the change to be picked up. The stub generator caches the available methods and is not aware of the hot deployable activity.

 

Let’s consider an example. Members of the Open 18 community can keep their golf trivia skills sharp by quizzing themselves. The Trivia component, shown in listing 12.2, manages a set of golf trivia questions, which are retrieved when the component is instantiated. It has two remoting calls: one to draw a question from the list and one to verify the response.

Each trivia question is represented by an instance of the TriviaQuestion class, which is a simple JPA entity class with three properties: id, question, and answer. Here’s where things get interesting. When the trivia question is sent to the browser, you only want to send the question and the id, not the answer. Otherwise, those techsavvy members could use Firebug[6] to inspect the Ajax request and steal the answer. This filtering is accomplished by declaring answer in the exclude attribute in the @WebRemote annotation. You can also use the exclude attribute to nullify large text or binary fields on the return object that make the response unnecessarily large. You can reach nested properties using dot notation just as you would with the EL. It’s also possible to exclude a property from a type regardless of where it is in the hierarchy using the syntax [type].property. In this expression, type can be a component name or the qualified class name of a noncomponent.

6 A web development add-on for Firefox, Firebug is available at http://www.getfirebug.com.

Listing 12.2. A JavaScript remoting-capable JavaBean component

Once the server-side component is prepared, it needs to be forged into JavaScript.

Importing component stubs

Upon importing the JavaScript remoting framework, Seam doesn’t automatically generate stubs for every Seam component that has a @WebRemote annotation. Instead, you instruct Seam to prepare a fixed set of component stubs that you need access to on a given page.

You can use the <s:remote> component tag to import the remoting framework and the component stubs. This tag produces HTML <script> tags, which request the remoting framework and stubs from the SeamResourceServlet. This tag’s include attribute accepts a comma-separated list of component names to import. To import the components named trivia and componentA, you add the following declaration to your JSF view:

  <s:remote include="trivia,componentA"/>

This declaration produces the following HTML markup, which you’d need to declare manually if you aren’t using JSF:

  <script type="text/javascript"
    src="seam/resource/remoting/resource/remote.js"></script>
  <script type="text/javascript"
    src="seam/resource/remoting/interface.js?trivia&componentA"></script>

The first <script> tag imports the remoting framework, a static JavaScript file. The remoting framework amounts to a handful of JavaScript objects, such as Seam.Component and Seam.Remoting, that are used to access and create instances of stubs. The second <script> tag imports the executable stubs that Seam generates as well as type stubs for any Java type used as a parameter or return value by a @WebRemote method. Seam creates these additional stubs to marshal and unmarshal parameters and return values from the XML payload. There are three stub varieties.

The three stub varieties

Not all stubs are created equal. There are stubs responsible for communicating with the server, and there are stubs that act as the payload exchanged with the server. A stub can’t serve both roles. There is further distinction between nonexecutable stubs, or local stubs, depending on whether the Java class is a Seam component. The three stub varieties are

  • Executable stub
  • Local component stub
  • Local type stub

When the remoting interface generator prepares the stub, it determines which stub to create based on the characteristics of the server-side component. Executable stubs are created for any component that has a @WebRemote method. Recall that for EJB session bean components, the @WebRemote annotation must be applied to methods on the local interface. As far as JavaScript knows, the server-side component represented by the executable stub has no other methods aside from the ones marked as @WebRemote. JavaScript can’t distinguish what type of Seam component it is, either. Local stubs are covered in section 12.4.4. Right now, let’s look at how to get a handle on an executable stub to invoke it.

12.4.3. Making calls to a server-side component

The Seam.Component JavaScript object acts as a mini-client-side version of the Seam container. The relationship between a component and a component instance, discussed in Chapter 4, still applies. However, in the JavaScript remoting environment, the instance is an instance of a stub, not the instance from the server. You state your intent to execute a method on a component instance by invoking the equivalently named method on the stub. Only after the request is shipped off to the server is the actual instance retrieved from the Seam container and invoked.

Getting a handle on an executable stub

You retrieve an instance of a stub using the Seam.Component.getInstance() method, which takes the component name as an argument. For example, you can get an instance of the stub for the component named trivia by executing

  var trivia = Seam.Component.getInstance("trivia");

 

Note

The newInstance() method would also return an instance of an executable stub, but that method is intended for creating new local stub instances. The getInstance() method returns a singleton JavaScript object, which is sufficient for executable stubs.

 

The next step is to invoke a method on the executable stub and capture the return value. The only thing you have to wrap your head around is that the Ajax call is asynchronous.

Executing a remote method asynchronously

You execute methods on an executable stub just as you would on a server-side instance of the component—well, not quite. There are two important differences. You already know that the stub only contains the methods that are marked as @WebRemote. The stub for the Trivia component only has the methods drawQuestion() and answerQuestion(), but not findQuestion(). The other difference is that the method on the stub doesn’t return a value, at least not right away. Let’s find out why.

Every method call made to the server-side component is done asynchronously, which means that it is nonblocking. After all, freezing the browser would defeat the purpose of Ajax. What that means, though, is that the result of the remote method call isn’t available immediately to the executing thread. As such, the method on the stub doesn’t have a value to return, even if the matching server-side method has one. When a method on the remote stub is executed, it is effectively saying, “I’ll get back to you on that. Do you have a number where I can reach you?” The number you provide is a “callback” JavaScript function.

The callback function is a standard construct in asynchronous APIs. It’s executed by the remoting framework when a response from an Ajax request arrives back at the browser. If the method on the server-side component has a nonvoid return value, that value is passed into the callback function as its only argument. If the method on the server-side component has a void return type, the callback function takes no arguments. (Actually, the final argument is always the Seam remoting context, which is covered in section 12.5.2.)

Let’s begin with the quizzing. We add a link on the page that encourages members to challenge themselves with a trivia question:

  <a href="javascript: void(0);" onclick="askQuestion();">Quiz me!</a>

The askQuestion() JavaScript function captures a question from the Trivia component:

  function askQuestion() {
      var trivia = Seam.Component.getInstance("trivia");
      trivia.drawQuestion(poseQuestion);
  }

As you can see, the call to drawQuestion() only starts the process. A callback JavaScript function, poseQuestion(), is used to capture the TriviaQuestion instance when it arrives and to prompt the user with the question:

  function poseQuestion(triviaQuestion) {
      if (triviaQuestion == null) {
          alert("Sorry, there are no trivia questions.");
      }
      else if (triviaQuestion.getAnswer() != undefined) {
          alert("This quiz has been compromised!");
      }
      else {
          var response = window.prompt(triviaQuestion.question);
        if (response) {
            var trivia = Seam.Component.getInstance("trivia");
            trivia.answerQuestion(
                triviaQuestion.getId(), response, reportResult);
        }
     }
  }

After receiving the TriviaQuestion instance, we verify that the answer property has been nullified, which was declared in the @WebRemote annotation as an excluded property. Without this exclusion, the integrity of the quiz is drawn into question. If all goes well, the member is prompted with the question using a JavaScript prompt, shown in figure 12.5.

Figure 12.5. The trivia question prompt in which the member enters a response

If the member responds, we initiate another method invocation, this time to verify whether the response is correct. In the call to the answerQuestion() method, the callback function is moved to the third slot. The callback function is always the n+1 parameter, where n is the number of parameters in the remote method. The reportResult() callback JavaScript function handles the verdict (in a crude fashion):

  function reportResult(result) {
      alert(result ? "Correct!" : "Sorry, wrong answer. Keep studying!");
  }

The only major architectural change brought about by using JavaScript remoting over executing calls in Java is that you have to shift to thinking about every interaction in terms of asynchronous communication. This takes some getting used to, both for the developer and the user. Let’s see what the impact is on the user.

What’s the status?

The browser uses a spinner, typically appearing in the upper-right corner of the window, that notifies the user when a page is loading. However, an Ajax-based application “breaks” this feedback mechanism because the browser interacts with the server without a page being formally requested. To reinstate the feedback, Ajax frameworks typically render a spinner in the page while an asynchronous request is in progress. Seam follows this pattern.

Seam’s JavaScript remoting library renders a loading message in the upper-right corner of the page during a remoting call. The message is defined in the property Seam.Remoting.loadingMessage. You can override it like this:

  Seam.Remoting.loadingMessage = "Request in progress";

If you’re using Ajax because you don’t want to bother the user, you can disable the message by overriding the methods that toggle the message with empty functions:

  Seam.Remoting.displayLoadingMessage = function() {};
  Seam.Remoting.hideLoadingMessage = function() {};

Rather than disabling the feedback mechanism, you can use these two functions to customize it.

As a developer, you may want to track the remoting call. Seam remoting includes a debug window that shows the status of the Ajax request. You can call Seam.Remoting.setDebug(true) to enable the window for a given page or activate it for all pages in the component descriptor. First, import the component namespace http://jboss.com/products/seam/remoting, prefixed as remoting. Then, enable debug mode on the built-in remoting component:

  <remoting:remoting debug="true"/>

The debug window appears whenever an Ajax request goes out and you can follow its progress. Despite having this debug window, I strongly urge you to use Firebug instead.

Let’s get back to remoting. As you know, the EL notation plays an important role in every Seam module. No module would be complete without it. JavaScript remoting is no exception.

Evaluating EL from the client

JavaScript remoting can tap into the Seam container via EL, whether it is to access values (value expressions) or execute methods (method expressions). You use the Seam.Remoting.eval() function to execute an EL expression, giving you a way to perform a remote operation without a @WebRemote method. Keep in mind that the resolved value is sent to a callback function asynchronously.

The eval() method (don’t confuse this with JavaScript’s eval() function) is ideal for fetching objects stored in the Seam container. This differs from executable stubs, which ask a component to perform work and return the result.

 

Escaping the EL

If you intend to use the Seam remoting eval() function from within a JSF page, you have to escape the EL notation. The JSF view handler gets a first pass at the template and will resolve any value expressions it finds. You must escape the EL to delay the evaluation.

You make an expression unrecognizable to the view handler by either escaping the pound sign (#) with a leading backslash (\):

     "\#{contextVariable}"

or by assembling the expression using string concatenation:

     "#" + "{contextVariable}"

Personally, I prefer the backslash syntax.

 

The only thing you have to be aware of when using eval() is that if the value expression resolves to an object of a custom type, you need to explicitly import that type using the <s:remote> tag. This problem doesn’t come up when using executable stubs since Seam automatically generates the necessary type stubs. Because the EL can resolve any type, it would be difficult for Seam to know what type stubs to prepare. If you’re only using the EL to resolve primitive values or built-in types (strings, dates, collections), you don’t need any extra imports.

Let’s try an example to get a feel for using the EL with remoting. In the Java world, we care a great deal about language support, but as soon as we move to JavaScript we seem to forget about this lofty goal. Having the ability to evaluate EL from JavaScript opens up the possibility of pulling down the message bundle map so that it can be referenced from JavaScript. In this case, we don’t want to execute a method but instead just retrieve the map:

  var messages = null;
  Seam.Remoting.eval("\#{messages}", function(value) {
      messages = value;
  });

Keep in mind that the call is asynchronous, so there’s a brief period of time before the messages arrive, but it’s likely to execute fast enough so that you don’t have to worry about the lapse.

With access to the locale-specific message bundle, we can reward or shame members in their language of choice in the reportResult() callback function:

  alert(result ? messages.get("response.correct") :
    messages.get("response.incorrect"));

As you can see, evaluating EL is a great way to pull down reference data needed in the UI. Next up, you’ll learn how to push data the other way by creating instances of local stubs and sending them off to the server through methods on executable stubs.

12.4.4. Local stubs

A local stub is a JavaScript version of a JavaBean class. It shares all of the same properties as its server-side counterpart. The properties on the local stub are addressed using JavaBean-style accessor methods or direct field access, as shown here:

  triviaQuestion.setAnswer("The Masters");
  triviaQuestion.answer = "The Masters";
  "The Masters" == triviaQuestion.getAnswer();

The fundamental difference between a local stub and an executable stub is that when a method on a local stub is called, it doesn’t trigger a remote execution (an Ajax request).

Sorting out the local stubs

There are two categories of local stubs: component and type. A Seam component with no @WebRemote methods becomes a local component stub when imported through the remoting framework. (The Seam component must be declared using @Name. It’s not enough to declare it in the component descriptor.) All other classes become local type stubs.

A local component stub is instantiated by passing its component name to the Seam.Component.newInstance() JavaScript method from the remoting framework, whereas a local type stub is instantiated by passing its qualified class name to the Seam.Remoting.createType() method:

  var favorite = Seam.Component.newInstance("newFavorite");
  var golfer = Seam.Remoting.createType("org.open18.model.Golfer");

Apart from how they’re instantiated, the two local stub varieties are identical. The benefit a component stub has over a type stub is that the component stub gets addressed by its component name, which is typically shorter than the class name and doesn’t tightly couple the qualified class name to the client (the JavaScript).

A local stub is intended to be used as a data structure that’s passed as a parameter to a method on an executable stub or mapped to the method’s return value. When an instance of a local stub reaches the server, it’s translated into a real Java object. Local stubs aren’t needed to create primitives and strings since there’s an implied mapping between JavaScript and Java for simple types.

So why do these objects need to be passed to the server? Well, the primary reason for using JavaScript remoting is to get the server to perform work that JavaScript can’t do. One example is persisting an object to the database. Local stubs are a perfect complement for this operation. The client can seed a transient entity instance from a local stub, which is then shipped off to the server to be persisted.

Persisting entities from javaScript

Let’s work through an example to see how a transient entity instance can be persisted via remoting. In this example, the entity class named Favorite is introduced to capture an item that the user has selected to be in his or her list of favorites. The essential parts of this entity are shown here:

  @Entity
  @Table(name = "FAVORITE")
  @Name("newFavorite")
  public class Favorite implements Serializable {
      private Long id;
      private Long entityId;
      private String entityName;
      private Golfer golfer;
      // getters and setters hidden
  }

Since the entity class is annotated with @Name, it becomes a local component stub and can be referenced by its component name, newFavorite. The FavoritesAction component, shown in listing 12.3, is responsible for persisting instances of the Favorite entity. It also has a method to check for a duplicate entry.

Listing 12.3. A remoting-capable component for working with Favorite entities

Notice the @Transactional annotation on the class. Since remoting requests operate outside the JSF life cycle, they aren’t wrapped in Seam’s global transaction. Therefore, @WebRemote methods must declare transaction boundaries.

If an exception is thrown during the execution of a @WebRemote method, no result is returned. Thus, it’s important to catch any exceptions and handle them gracefully. To expose the status of the exception, you can either return it or save it, then access it on a subsequent remoting call.

The next step is to create a JavaScript function that invokes the method to add the current entity to the golfer’s favorites, shown in listing 12.4. You place this JavaScript function on any entity detail page (since this design is agnostic to entity type).

Listing 12.4. Remoting logic used to add an entity as a favorite
  function addToFavorites(entityId, entityName, golferId) {
      var favoritesAction =
          Seam.Component.getInstance("favoritesAction");    
      favoritesAction.isFavorite(
          entityId, entityName, function(exists) {     
          if (exists) {
              alert("This " + entityName + " is already a favorite");
          }
          else {
              var favorite = Seam.Component.newInstance("newFavorite");    
              favorite.setEntityId(entityId);
              favorite.setEntityName(entityName);
              var golfer =
                  Seam.Remoting.createType("org.open18.model.Golfer");    
              golfer.setId(golferId);
              favorite.setGolfer(golfer);

              favoritesAction.addFavorite(favorite, notify);     
          }
      });
  }

  function notify(favoriteInstance) {
      if (favoriteInstance == null) {
          alert(messages.get("favorite.addFailed"));
      }
      var message = messages.get("favorite.addSucceeded");
      message = message.replace("{0}", favoriteInstance.getEntityName());
      message = message.replace("{1}", favoriteInstance.getId());
      alert(message);
  }

The addToFavorites() method accepts the information to create and persist an instance of Favorite. The first step is to get a handle on the stub for FavoritesAction . Rather than jumping right into the call, we verify that the favorite doesn’t yet exist by invoking the isFavorite() method. This deals with a race condition to the server. Like all remoting methods, the isFavorite() method runs asynchronously, so it’s necessary to jump into a callback method to continue with the operation .

If the favorite doesn’t already exist, a transient instance of Favorite is constructed by passing its component name to newInstance() . The Golfer entity is not a Seam component. Therefore, it’s necessary to use createType() to create a transient instance . Here’s where things get interesting. To satisfy the foreign key relationship from Favorite to Golfer, an identifier is assigned to the transient instance of Golfer. The persistence manager understands how to link the records in the database. Once the transient instance of Favorite is built, it’s sent off to the server to be persisted.

All that’s left is to add a link to the entity detail page that invokes the JavaScript method:

  <a href="javascript: void(0);" onclick=
    "addToFavorites(#{facilityHome.id}, 'Facility', #{currentGolfer.id});">
    Add to favorites</a>

The EL value expressions in the link definition is interpreted when the page is rendered, resolving to the numeric identifiers of the current golfer and facility, respectively.

This example uses the persistence manager to perform a duty in response to a user-triggered event. As you may recall from Chapter 7, Ajax requests occur with a much greater frequency than traditional page requests and it’s a good idea to leverage conversations to avoid unnecessary load from being placed on vital resources such as the database. Let’s explore how you give JavaScript remoting requests access to stateful components in a long-running conversation.

12.5. Conversational remoting calls

There are two ways for JavaScript remoting requests to partake in conversations. They can join the conversation associated with the current page, or they can go off and establish their own conversation, isolated from and transparent to the rendered page. Let’s consider these two scenarios for using conversations with JavaScript remoting.

12.5.1. Joining the conversation in progress

Remoting requests maintain a special context for holding the “active” conversation id. You can access this context using the JavaScript method Seam.Remoting.getContext(). The context has two methods: getConversationId() and setConversationId(). Once the conversation id is established on this context, it remains set until it’s explicitly changed.

If a long-running conversation is active at the time the page is rendered, the remoting context can join it. The technique is to use an EL value expression to resolve the current conversation id and pass it as an argument to the setConversationId() method:

  Seam.Remoting.setConversationId(#{conversation.id});

The expression is resolved when the page is rendered, leaving behind the numeric conversation id. This call should be placed in the window’s onload handler. Once the conversation id is established, remoting requests are able to “see” all objects in the long-running conversation in progress (objects related to the rendered page). You can pull references to these objects using Seam.Component.getInstance() or Seam.Remoting.eval(). For instance, if a list of data were retrieved and stored in the conversation, the remoting request could talk to the server and ask it to hand over that data set rather than asking the database to retrieve it again. You could also invoke a method on a conversation-scoped component, manipulating the state of the data held in the conversation. Seam offers parallel support for conversations in web service calls.

Remoting requests can also work in their own conversation context. Let’s consider how this differs from participating in the page’s conversation.

12.5.2. Striking up a conversation

A remote method call can start a new long-running conversation and then participate in that conversation on subsequent calls. When it’s time to say goodbye, another remoting method can end the conversation. This style of conversational Ajax is great for single-page applications where the page flow concept doesn’t apply. It’s even possible to get multiple conversations going at the same time. You swap between them by changing the active conversation id on the remoting context prior to issuing a call.

Let’s return to the trivia example and make it a cohesive quiz. We also give the user a choice of category and three chances to get each answer right. The member is first presented with a list of topics. Once a topic is selected, the quiz is started, which in turn begins a long-running conversation. Each time a question is answered correctly or the user fails all three attempts, it’s removed from the pool. When members reach the last question, they get their score and the conversation ends. We stick to pseudocode since the method implementations aren’t important to understanding the concept. The following shows the conversation component with the method stubs:

  @Name("trivia")
  @Scope(ScopeType.CONVERSATION)
  public Trivia implements Serializable {
      @In private EntityManager entityManager;
      private Double score;
      private List<TriviaQuestion> questions;

      @WebRemote
      public List<String> getCategories() { ... }

      @Begin @WebRemote
      public boolean selectQuiz(String category) { ... }

      @WebRemote(exclude = "answer")
      public TriviaQuestion drawNextQuestion() { ... }

      @WebRemote
      public boolean answerQuestion(Long id, String response) { ... }

      public TriviaQuestion findQuestion(Long id) { ... }

      @End @WebRemote
      public Double endQuiz() { ... }
  }

Things kick off with a call to the getCategories() method:

  Seam.Component.getInstance("trivia").getCategories(showCategories);

This call happens outside a long-running conversation. When the response comes back from the server, it contains the conversation id of the temporary conversation. The next remoting call, which is to the selectQuiz() method, sends this conversation id along with the request:

  Seam.Component.getInstance("trivia").selectQuiz(startQuiz);

The selectQuiz() method queries the database for the questions associated with the category and stashes them in the questions property of the component. When the response comes back from the selectQuiz() call, it contains the conversation id of the long-running conversation that was started as a result of executing this method. However, it will not overwrite the conversation id on the remoting context since one has already been established. There are two ways to force the conversation id to be updated:

  • Clear the conversation id before executing the method on the stub.
  • Explicitly overwrite the conversation id with the value returned from the server.

The second option is typically the best approach to take. I mentioned earlier that the callback function accepts a remoting context as the last argument. This context contains the conversation id that was assigned by the server. By accepting this parameter in your callback function, you can transfer the conversation id to the page’s remoting context:

  function startQuiz(ready, context) {
      Seam.Remoting.setConversationId(context.getConversationId());
      askQuestion();
  }

The remoting context is now participating in the long-running conversation. Questions are drawn and answered until no more questions remain. When the questions are exhausted, the endQuiz() method is called to end the conversation and report the member’s score:

  Seam.Component.getInstance("trivia").endQuiz(reportScore);

The setConversationId() method can also be used to switch between parallel conversations. In some ways, JavaScript remoting is more capable of dealing with conversations than regular JSF navigation because you have fine-grained control over the active conversation.

There’s one final form of conversation I want to mention before closing this chapter. This one has to do with batching communication between the browser and the server.

12.5.3. Storing up requests for a shipment

Ajax is chatty. While it may be a lot of little requests, they can take their toll on the server. Studies have shown that the metric that matters most in server load is not the size of the request, but rather the quantity of requests.[7] Therefore, if possible, it’s a good idea to try to stockpile the requests and send them all at once. By doing so you’ll see a significant performance boost by reducing both server load and network traffic. A good way to know if you have such a use case is to use Firebug to monitor the Ajax requests being fired. If they’re occurring in rapid succession, you could benefit from bundling them together.

7 For “Best Practices for Speeding Up Your Web Site,” see http://developer.yahoo.com/performance/rules.html.

To begin queuing requests—executable stub method invocations and EL evaluations—you call Seam.Remoting.startBatch(). You still use callback functions just as you always would, only there is going to be a longer delay before those functions are executed by the response. When you’re ready to have the pending requests sent off, you call Seam.Remoting.executeBatch(). The requests are fired off in the order that they were queued. Rest assured that the callback functions are also executed in this order. If you decide at some point after opening the queue that you want to discard the pending requests, simply call Seam.Remoting.cancelBatch() and exit batch mode. The cancel batch feature is useful for letting the user discard pending changes in the UI.

Having Ajax requests participate in conversations minimizes the load that Ajax requests would otherwise impose on the server. Conversely, remoting requests add a new dimension to how conversations are able to serve the application, enabling you to take advantage of Seam’s conversation model for single-page applications. If you’re committed to single-page applications, you may even want to consider switching to GWT.

12.6. Responding to GWT remoting calls

As you lean more toward the single-page application, you may reach a point where JSF just doesn’t fit any longer. If that’s the case, you are probably better off moving to a UI framework that’s designed around the use of remoting calls. One such library is the Google Web Toolkit (GWT). A move from JSF to GWT doesn’t mean that you have to leave Seam behind. GWT is intended for creating the user interface, which means it must delegate work to transactional components on the back end. Seam remoting can establish that bridge.

This section is focused on the integration of Seam and GWT, not on GWT fundamentals. If you are a novice to GWT and are seeking in-depth information on the subject, I encourage you to pick up a copy of GWT in Action (Manning, 2007). Once you’re comfortable with GWT, or if you’re just interested in finding out how the integration works, forge ahead.

12.6.1. A quick introduction to GWT integration

GWT is an Ajax-based framework that allows you to develop your web application purely in Java, without having to write HTML or JavaScript. It offers a similar value proposition as Ajax-based JSF libraries, but replaces the declarative UI with Java constructs. The toolkit compiles your Java code down to JavaScript, which means that you don’t have to go through the pain of coding JavaScript and you can be confident that the JavaScript is delivered to the browser in the most efficient manner possible.

GWT’s remote procedure call (RPC) mechanism is designed to allow a GWT client application to access server-side business components via Ajax. In the GWT tutorials, you are told to use a Java servlet to handle the request. However, in this section, I show you how to hook one of these RPC calls to a @WebRemote method on a Seam component. We refactor the Trivia component so that it can act as a remote service to GWT, giving GWT access to the trivia questions in the database. Seam’s GWT integration uses Seam remoting, so be sure to have the Seam resource servlet installed when using this integration.

12.6.2. Preparing the remoting service

To make a Seam component accessible to GWT, you first have to convert it to a GWT service. This step involves implementing GWT’s RemotingService interface. You will end up with three Java classes. First, you define a synchronous interface that declares the public methods of the Seam component. Trivia is now an interface:

  public interface Trivia extends RemotingService {
      public TriviaQuestion drawQuestion();
      public void answerQuestion(Long id, String response);
  }

All return values and parameters in a GWT service must be primitive or serializable. That means the TriviaQuestion class must be declared as serializable using the IsSerializable interface from GWT:

  public class TriviaQuestion implements IsSerializable {...}

 

Note

Although GWT 1.4 and above supports the java.io.Serializable interface, at the time of this writing, Seam’s GWT integration doesn’t support it. Also, to make a collection serializable, you need to specify the type it contains using the special JavaDoc annotation @gwt.typeArgs. See the GWT reference documentation for details.

 

GWT makes asynchronous calls to the remote service. But, as you learned earlier, asynchronous methods can’t have return types. Instead, when an asynchronous call is made, the status code and return value are directed to a callback object. The Trivia interface can’t accommodate such a call. That means it’s necessary to define an asynchronous version of the service interface that can be called on by the GWT application. You must use the following list of conventions when developing the asynchronous interface:

  • It must be in the same Java package as the synchronous interface.
  • Its name must be the name of the synchronous interface plus the suffix Async.
  • It must have the same methods as the synchronous interface, except the return types must be void and each method must accept AsyncCallback as the final argument.

Here’s the asynchronous interface for the trivia service that satisfies these requirements:

  public TriviaAsync implements RemotingService {
      public void drawQuestion(AsyncCallback callback);
      public void answerQuestion(Long id, String response,
          AsyncCallback callback);
  }

Although you have a pair of interfaces for the GWT service, you only have to provide an implementation class for the synchronous interface. The asynchronous interface is implemented at runtime by GWT and its method calls delegate to the implementation of the synchronous interface. The AsyncCallback is an interface that defines two methods: onSuccess() and onFailure(). The first accepts the return value of the synchronous method, and the second accepts the Throwable object that reports the nature of the failure.

To complete the contract, the Trivia class from the earlier example is renamed to TriviaImpl and now implements the synchronous interface. In addition, the name of the component must match the qualified name of this interface. The component is scoped to the session because conversations aren’t supported in the GWT integration at the time of this writing:

  @Name("org.open18.action.Trivia")
  @Scope(ScopeType.SESSION)
  public class TriviaImpl implements Trivia, Serializable { ... }

If you need to access a conversation, pass the conversation id as an argument to a @WebRemote method. Within the method, manually restore the conversation using the switchConversation() method on the built-in manager component. After switching to (or restoring) the conversation, you can retrieve a conversation-scoped component using the Seam API (i.e., Component.getInstance()).

With the implementation of the Trivia service interface, you now have a bona fide GWT service. Let’s see how it is called from GWT.

12.6.3. Making a GWT service call through Seam remoting

After looking up the GWT service in a GWT client application, you set the service entry point to a URL that’s handled by the Seam resource servlet and subsequently the Seam remoting library. The lookup for the trivia service is handled in the getTriviaService() method on the GWT application class (shown here):

  private TriviaAsync getTriviaService() {
      String endpointURL = GWT.getModuleBaseURL() + "seam/resource/gwt";
      TriviaAsync service = (TriviaAsync) GWT.create(Trivia.class);
      ((ServiceDefTarget) service).setServiceEntryPoint(endpointURL);
  }

Notice that this lookup casts to the asynchronous interface, which lets you provide a callback to handle the response from the server. To use the Seam integration while debugging a GWT application in hosted mode, start the application server that hosts the Seam application as usual and then hardcode the absolute URL in the Java GWT client code. You can use GWT.isScript(), which returns true in deployment mode and false in hosted mode, thus making the code portable.

Let’s use the endpoint in the GWT application that presents the trivia challenge. Since the focus of this section is not on creating a full GWT application, only a small excerpt is shown here. The method that sends the user’s response to be validated is bound to a button named Guess:

  final Button guess = new Button("Guess");
  guess.addClickListener(new ClickListener() {
      public void onClick(Widget w) {
          getTriviaService().answerQuestion(question.getId(),
              answerInput.getText(), new AsyncCallback() {
              public void onFailure(Throwable t) {
                  Window.alert("The call didn't go through");
              }
              public void onSuccess(Object data) {
                  boolean result = ((Boolean) data).booleanValue();
                  Window.alert(result ? "Correct!", "Wrong, try again.");
              }
          });
      }
  });

This example demonstrates that using a Seam component as a GWT RPC service is relatively straightforward. The best part is that you can back GWT with the power of Seam rather than a clunky servlet. Seam remoting is very powerful because not only does it allow you to call server-side methods from JavaScript, it also serves as the foundation to integrate with other rich-client frameworks. This section presents GWT, but parallel integrations are available for Laszlo, Flex, and Java FX. To assist with this integration, Exadel has developed a seam-gen clone called Flamingo,[8] which uses Maven 2 to generate projects that use either Flex or Java FX as a front end to Seam. Also check out Granite Data Services’ GraniteDS,[9] another framework that bridges Flex to Seam.

8http://exadel.com/web/portal/flamingo

9http://graniteds.org

12.7. Summary

In this chapter, you learned to use two types of Ajax without having to get your hands dirty with the XMLHttpRequest object. You began by using Ajax4jsf and ICEfaces to execute Ajax requests that honor the JSF life cycle and perform partial rerendering of the page by grafting on updated branches of the JSF component tree. ICEfaces intelligently calculates the portions of the UI component tree that need to be rerendered, whereas Ajax4jsf relies on declarative hints. To give credit to Ajax4jsf, it’s capable of creating Ajax interactions between components not designed with Ajax in mind.

Although Ajax-based JSF components are powerful, there are times when you need something leaner. As an alternative, you learned to bypass the JSF life cycle and let JavaScript invoke server-side components as if they were local to the browser. The only challenge is that you have to think in terms of asynchronous return values. You discovered that Seam remoting allows JavaScript to speak the language of EL notation and tap into conversations, two paramount features of Seam that are particularly useful for single-page applications. Finally, you used Seam remoting to connect GWT to a Seam component acting as a GWT RPC service.

The two styles of Ajax presented in this chapter each have their own purpose. Ajax-based JSF component libraries are critical when you want to alter areas of the page under JSF’s control, such as a form or data table, while keeping in sync with the server’s view of the page. JavaScript remoting is for lightweight calls that don’t involve UI components. Both styles get you thinking in terms of incremental pages updates rather than full-page refreshes.

In the next chapter, you’ll escape the well-worn groove of HTML and JavaScript and explore file uploading, dynamic graphic generation, PDF creation, multipart emails, and themes. After taking in the lessons from the next chapter, you’ll find that the applications you create become far more 3D, to play on the name of one of the topics that await.