Seam component events

A very powerful feature in Seam that usually doesn’t get enough attention in my opinion is component-driven events. Seam component can raise or throw arbitrary event and any number of other Seam components can observe or listen to these events. This truly creates a loose coupled architecture. Components raise events and anyone who cares listens to the event. The components are not connected to each other in any way.

Let’s start with CourseManager component:

@Name("courseManager")
public class CourseManager {
 
   private String name; // setter and getter
 
   @Out(required=false)
   private String studentName;
 
   @Logger Log log;
 
   @RaiseEvent("courseDropped")
   public void drop() {
     studentName = name;
     log.info("course dropped");
   }
}

In component above when drop() method is invoked, courseDropped event will be raised via @RaiseEvent annotation. Once invocation is done, the component will outject studentName variable.

Although data can passed with the event, a better way is to use bijection in Seam. The name variable would most likely be submitted from a JSF page. Its value is assigned to studentName component variable and studentName is outjected after the method invokation. Anyone who is interested in this event can listen to it and also get the data associated with the event (via injection).

Below is studentAdvisor component that listens to courseDropped event. Every time a student drops a course, the student advisor is notified that a student dropped a course.

@Name("studentAdvisor")
public class StudentAdvisor {
 
   @Out
   private String studentAdvisorMessage;
 
   @In 
   private String studentName;
 
   @Logger Log log;	
 
   @Observer("courseDropped")
   public void courseDropped() {
      this.studentAdvisorMessage = "Student dropped course: "+studentName;
      log.info("advisor notified");
   }
}

This component observes or listens to the courseDropped event raised by courseManager via @Observer annotation. In other words, when courseDropped is raised, courseDropped() method is invoked. How do we get the data from the event? We use @In annotation to inject studentName into this component just before courseDropped is invoked.

This is very powerful and easy to use and creates a very nice loosely coupled architecture for the components. The components don’t know anything about other components. Components only raise or listen to events.

You can have more than one component listen to a particular event. For example, we can add parents component to be notified when a student drops a class:

@Name ("parents")
public class Parents {   	
   @In
   private String studentName;
 
   @Out
   private String parentsMessage;
 
   @Logger Log log;
 
   @Observer ("courseDropped")
   public void childrenParentTalk () {
      this.parentsMessage = studentName +"'s parents notified";                                 
      log.info("children parent talk");
   }
}

In above component, childrendParentTalk() method is invoked when courseDropped event is raised.

Components can also raise multiple events:

@RaiseEvent ({"courseDropped", "sendEmailConfirmation"})
public void drop (){
   log.info("course dropped");
}

Two different components observe the event:

@Name("courseManager")
public class CourseManager {
   ...
   @Observer ("courseDropped")
   public void drop (){
      log.info("course dropped");
   }
   ...
}
@Name("emailConfirmation")
public class EmailConfirmation {
   ...
   @Observer ("sendEmailConfirmation")
   public void sendEmail (){
      log.info("email confirmation sent");
   }
   ...
}

Instead of using @RaiseEvent annotation, it’s possible to raise an event programmatically:

Events.instance().raiseEvent("courseDropped");

Lastly, instead of using @Observer annotation, it’s possible to specify event listeners inside descriptor file:

<event type="courseDropped">
      <action execute="#{studentAdvisor.courseDropped}"/>
       <action execute="#{parents.childrenParentTalk}"/>
</event>
<event type="sendEmailConfirmation">
       <action execute="#{sendEmail.sendEmail}"/>
</event>

Enjoy this powerful feature in Seam.

4 comments

  1. Quazi

    as one method can raise multiple events which will be observed by multiple orserver. is there any way we can observ multiple events by one @observer method?
    and thanks for a nice tutorial.

Leave a Reply