January 28th, 2012 by Lincoln Baxter III

Server side action methods on JSF ValueChange events using AJAX listeners

I’m about to show you a pattern that will make your heart sing. I have to thank Brian Leathem for his original idea to use CDI events in the ValueChangeListener, but when combined with a little <f:ajax> magic, there’s almost no limit to what you can do without writing a single line of JavaScript. ValueChangeListeners are also the perfect opportunity to build an Event driven model into your application. The following example code was taken from our latest Project: [[SocialPM]], a budding Agile Project Management tool. The first problem that CDI events will help us with is the fact that in this loop, you may come to find find that you have no way of accessing the loop variable (in this case, ‘s’) in your ValueChangeListener. CDI can help. The other issue that comes up as a minor inconvenience is not related to JSF, but is purely programming related. How would you track all of these changes in order to populate something like a status feed? You would have to add logic to each listener – this would increase complexity and make testing more difficult. So let’s get started…
<ui:repeat value="#{stories.list}" var="s">
   ...
   <h:inputText id="priority" value="#{s.priority}" size="2" style="width: 20px;">
       <f:valueChangeListener binding="#{storyPriorityChanged}"/>
   </h:inputText>
   ...
</ui:repeat>
@RequestScoped
@Named("storyPriorityChanged")
public class StoryPriorityChanged implements ValueChangeListener
{
   @Override
   public void processValueChange(final ValueChangeEvent event) throws AbortProcessingException
   {
      if(...)
      {
         // do something with our event, but, we have no reference to '#{s]'
         // only to the old and new values of '#{s.priority}'. We also need
         // to integrate extra logic here in order to track our change events.
      }
   }
}

A ValueChangeListener will execute before data is populated in the Model

And the ValueChange event is not an ActionEvent, so we cannot attach an <f:setPropertyActionListener> to set the value in a backing bean where we would be able to access it from a nested listener. There really should be an <f:setPropertyOnValueChangedListener>, and while we could write one ourselves, that would be somewhat inconvenient. Fortunately, there’s a better way to do both of these things, and it all hinges on our friend CDI… Oh and <f:ajax> can help too. There are better ways to both make sure our loop instance variable is accessible, and also better ways to aggregate change events into a feed.

A viable, reliable solution

Our code looks something like this, and before you start worrying about the fact that you need to write “more” or “more complicated” Java code, I’ll explain why this method actually loosens the coupling between your UI and your Model/Controller: Notice that we are using the same ValueChangeListener, and we are still not passing the value of ‘s’, our Story, into the listener. We are going to add an AJAX listener="", which will execute after our tag, and it will be responsible for receiving our Story. The listener allows us to invoke any server-side EL method when the Ajax event occurs; Using EL 2.0, we can pass our Story ‘s’ into the method as a parameter.
<ui:repeat value="#{stories.list}" var="s">
   ...
   <h:inputText id="priority" value="#{stories.current.priority}" class="span1">
      <f:valueChangeListener binding="#{storyPriorityChanged}"/>
      <f:ajax execute="@form" render="pr" listener="#{storyCommandListener.save(stories.current)}" />
   </h:inputText>
   ...	
</ui:repeat>

But we still don’t have access to ‘s’ in our ValueChangeListener, so what?

This is where we need to pull out a few tricks from our CDI and Java Patterns playbook, so the first thing we need to do is re-think our strategy. We know that the ValueChangeListener will be executed before our AJAX listener, so we need a way of performing our value change logic without the Story ‘s’. Wait, how are we going to do that? The answer is our good friend the Command pattern. The command pattern “is a design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time. This information includes the method name, the object that owns the method and values for the method parameters.” We will combine the command pattern with CDI Events in order to pass this event to a listener which will later invoke all queued commands when we trigger it with our AJAX listener method. This also handles the problem of capturing our ValueChangeEvents so we can create our status feed. How? We’ll get to that soon. Our updated ValueChangeListener looks like the code below. Notice how we are not actually performing the operation yet, we are simply storing all information that we will need to perform this operation at a later time, when we do have access to our Story ‘s’. Once we have prepared the StoryCommand instance, we will fire it as a CDI event, using the the built in injected Event changeEvent mechanism.
@RequestScoped
@Named("storyPriorityChanged")
public class StoryPriorityChanged implements ValueChangeListener
{
   @Inject
   private Event<StoryCommand> changeEvent;
 
   @Override
   public void processValueChange(final ValueChangeEvent event) throws AbortProcessingException
   {
      StoryCommand command = new StoryCommand() {
 
         private final Integer oldVal = (Integer) event.getOldValue();
         private final Integer newVal = (Integer) event.getNewValue();
 
         @Override
         public void perform(Story story)
         {
            if(...)
            {
               // perform some action with the values from our event
            }
         }
      };
 
      changeEvent.fire(command);
   }
}
The events fired by our ValueChanceListener are captured by a method which @Observes StoryCommand command events, and stores them in a list until we are ready to use them. The same class which observes these events is going to perform all queued commands when triggered by our AJAX listener: listener="#{storyCommandListener.save(stories.current)}". Now that we have access to our Story ‘s’, we can run each command passing in the Story on which it will operate.
@Named
@Stateless
@RequestScoped
public class StoryCommandListener
{
   @PersistenceContext
   private EntityManager ss;
 
   private final List<StoryCommand> commands = new ArrayList<StoryCommand>();
 
   protected StoryCommandListener()
   {}
 
   public void capture(@Observes StoryCommand command)
   {
      this.commands.add(command);
   }
 
   @TransactionAttribute
   public void save(Story s)
   {
      for (StoryCommand c : commands) {
         c.perform(s);
      }
      em.save(s);
   }
}
Just for Reference, this is what our StoryCommand class looks like:
public abstract class StoryCommand
{
   public abstract void perform(Story story);
}

Problem solved

We now have access to our Story object in the logic that needs to be executed, but why is this better than simply updating the database in our AJAX listener method itself? We could just do this, after all:
<ui:repeat value="#{stories.list}" var="s">
   ...
   <h:inputText id="priority" value="#{stories.current.priority}" class="span1">
      <f:ajax execute="@form" render="pr" listener="#{storyCommandListener.save(stories.current)}" />
   </h:inputText>
   ...
</ui:repeat>

Status updates

When you want to log change events into a notification feed as we are doing in [[SocialPM]], this is where our new pattern really starts to shine. It is easier to have a second @Observes method (below) that creates a status update when users perform operations, as opposed to integrating the notification service with every method call (i.e. adding code to each ValueChangeListener.) In the end, it is a trade-off, but the real benefit is that this approach, using AJAX listeners and CDI events is a quick, reliable, and decoupled way to extend functionality to your JSF user interfaces.
   public void capture(@Observes StoryCommand command)
   {
      // update status feed with the User, and the type of changes he/she made.
      notifications.updateStatus(user, command.getType());
   }
Cheers! If you want to check out more of this type of code in action, grab the SocialPM Source Code on GitHub, and give us a shout. We’d love to have some more hands in this project!
Lincoln Baxter, III

About the author:

Lincoln Baxter, III is the Chief Editor of Red Hat Developers, and has worked extensively on JBoss open-source projects; most notably as creator & project lead of JBoss Forge, author of Errai UI, and Project Lead of JBoss Windup. This content represents his personal opinions, not those of his employer.

He is a founder of OCPsoft, the author of PrettyFaces and Rewrite, the leading URL-rewriting extensions for Servlet, Java EE, and Java web frameworks; he is also the author of PrettyTime, social-style date and timestamp formatting for Java. When he is not swimming, running, or playing competitive Magic: The Gathering, Lincoln is focused on promoting open-source software and making technology more accessible for everyone.

Posted in JSF2

7 Comments

  1. João says:

    Wow, that’s… convoluted. A great example of what’s wrong with J2EE.

    1. I’m sorry you feel that way. This is a relatively complex solution (for technical reasons that I stated in the conclusion) to an issue that ALSO has a simple solution. If you had read the entire article, you might have seen that. Fortunately, you’re right about one thing. I can stand to make this clearer so that future readers don’t miss that fact 😉 Thanks!

  2. Jason Porter says:

    While I agree it is quite a bit of work for performing one action, it really starts to shine when you need to perform multiple actions, as you stated in the article. Decoupling logic in your application is something that is really a must as soon as you get an application of any decent sized complexity, like you will find in most “enterprise applications”. Sure, you could add all of the necessary code and actions as you go in different iterations, but you’d had best have a good test suite for those methods / app to make sure you don’t break anything. Let’s face it, most applications don’t do as much testing as they should. When you can simply fire an event and have x number of observers and have each action being performed it’s own observers, even a poorly tested application can ensure it doesn’t break the previously coded action. Of course this all takes discipline.

    Good job Lincoln, thanks for showing that way of doing things!

  3. Nik says:

    Decoupling with events is nice but you need some sort of tooling to keep track of observers otherwise you will sooner or later shoot yourself in the foot when you have forgotten about some observer somewhere that kicks in…

    1. Very true! JBoss Tools for Eclipse has a very nice set of tools that allows you to navigate between and discover all CDI observers for a given event 🙂

      http://jboss.org/tools

  4. Paul Dijou says:

    A bit heavy but such a cool solution. Nice article.

    There is a few small points that I want to ask about :
    1) Inside the ui:repeat, why do you use “stories.current” instead of “s” var ? (I said it was small points 🙂 )
    2) In the f:ajax tag, why do you execute @form and not @this ? Since we only want to track the value change of this particular input, is there any necessity to submit all the form ?
    3) In your f:ajax tag, you render “pr”, is that the whole list ? Not enough to render only the input ? (or a decorate around it)
    4) Wouldn’t it be better if the f:ajax event was specified ? Like ‘event=”valueChange”‘ ?

    That’s not very important questions, the main point was the full pattern you explain, but if you have time, I would be glad to know the answers.

    Thanks.

  5. Grant Smith says:

    Note that with Omnifaces, you can use:

    Faces.evaluateExpressionGet("#{s}");

    MUCH EASIER!

Leave a Comment




Please note: In order to submit code or special characters, wrap it in

[code lang="xml"][/code]
(for your language) - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.