Annotation Interface Handler


This is the basic, general purpose handler annotation provided as part of the core package.

The annotated method is invoked for events that have a type (or name) matching the given events (or namedEvents) element of the annotation and that are fired on one of the channels (or namedChannels) specified in the annotation.

If neither event classes nor named events are specified in the annotation, the class of the annotated method’s first parameter (which must be of type Event or a derived type) is used as (single) event class (see the examples in events() and namedEvents()).

Channel matching is performed by matching the event’s channels (see Event.channels()) with the channels specified in the handler. The matching algorithm invokes isEligibleFor for each of the event’s channels with the class (or name, see channels() and namedChannels()) of each of the channels specified in the handler.

If neither channel classes not named channels are specified in the handler, or Channel.Default.class is specified as one of the channel classes, the matching algorithm invokes isEligibleFor for each of the event’s channels with the default criterion of the component’s channel (see Manager.channel() and Eligible.defaultCriterion()) as argument.

Finally, independent of any specified channels, the matching algorithm invokes isEligibleFor for each of the event’s channels with the component’s default criterion as argument unless excludeSelf() is set. This results in a match if the component itself is used as one of the event’s channels (see the description of Eligible).

If a match is found for a given event’s properties and a handler’s specified attributes, the handler method is invoked. The method can have an additional optional parameter of type Channel (or a derived type). This parameter does not influence the eligibility of the method regarding a given event, it determines how the method is invoked. If the method does not have a second parameter, it is invoked once if an event matches. If the parameter exists, the method is invoked once for each of the event’s channels, provided that the optional parameter’s type is assignable from the event’s channel.

Because annotation elements accept only literals as values, they cannot be used to register handlers with properties that are only known at runtime. It is therefore possible to specify a Handler annotation with element dynamic=true. Such a handler must be added explicitly by invoking Handler.Evaluator.add(ComponentType, String, Object) or Handler.Evaluator.add(ComponentType, String, Object, Object, int), thus specifying some of the handler’s properties dynamically (i.e. at runtime).

A special case is the usage of a channel that is only known at runtime. If there are several handlers for events on such a channel, a lot of methods will become dynamic. To avoid this, Components support a HandlerDefinition.ChannelReplacements parameter in their constructor. Using this, it is possible to specify a specially defined Channel class in the annotation that is replaced by a channel that is only known at runtime.

If a method with a handler annotation is overwritten in a derived class, the annotation is overwritten as well. The annotated method of the base class is no longer invoked as handler and the method of the derived class is only invoked as handler if it defines its own handler annotation.

See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    This class provides the Handler.Evaluator for the Handler annotation provided by the core package.
    static final class 
    The default value for the channels parameter of the annotation.
    static final class 
    The default value for the events parameter of the annotation.
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    Class<? extends Channel>[]
    Specifies classes of channels that the handler listens on.
    boolean
    Returns true if the annotated method defines a dynamic handler.
    Class<? extends Event>[]
    Specifies classes of events that the handler is to receive.
    boolean
    Excludes the handler from channel matching against its component’s default criterion.
    Specifies names of NamedChannels that the handler listens on.
    Specifies names of NamedEvents that the handler is to receive.
    int
    Specifies a priority.
  • Element Details

    • events

      Class<? extends Event>[] events
      Specifies classes of events that the handler is to receive.
       class SampleComponent extends Component {
       
          @Handler
           public void onStart(Start event) {
               // Invoked for Start events on the component's channel,
               // event object made available
           }
       
          @Handler(events=Start.class)
           public void onStart() {
               // Invoked for Start events on the component's channel,
               // not interested in the event object
           }
       
          @Handler(events={Start.class, Stop.class})
           public void onStart(Event<?> event) {
               // Invoked for Start and Stop events on the component's
               // channel, event made available (may need casting to 
               // access specific properties) 
           }
       }
      
      Returns:
      the event classes
      Default:
      {org.jgrapes.core.annotation.Handler.NoEvent.class}
    • namedEvents

      Specifies names of NamedEvents that the handler is to receive.
       class SampleComponent extends Component {
       
          @Handler(namedEvents="Test")
           public void onTest(Event<?> event) {
               // Invoked for (named) "Test" events (new NamedEvent("Test")) 
               // on the component's channel, event object made available
           }
       }
      
      Returns:
      the event names
      Default:
      {""}
    • channels

      Class<? extends Channel>[] channels
      Specifies classes of channels that the handler listens on.

      If none are specified, the component’s channel is used.

      class SampleComponent extends Component {
      
         @Handler(channels=Feedback.class)
          public void onStart(Start event) {
              // Invoked for Start events on the "Feedback" channel
              // (class Feedback implements Channel {...}),
              // event object made available
          }
      }
      

      Specifying channels=Channel.class make the handler listen for all events, independent of the channel that they are fired on.

      Specifying channels=Self.class make the handler listen for events that are fired on the conponent.

      Returns:
      the channel classes
      Default:
      {org.jgrapes.core.annotation.Handler.NoChannel.class}
    • namedChannels

      Specifies names of NamedChannels that the handler listens on.
       class SampleComponent extends Component {
       
          @Handler(namedChannels="Feedback")
           public void onStart(Start event) {
               // Invoked for Start events on the (named) channel "Feedback"
               // (new NamedChannel("Feedback")), event object made available
           }
       }
      
      Returns:
      the channel names
      Default:
      {""}
    • priority

      Specifies a priority.

      The value is used to sort handlers. Handlers with higher priority are invoked first.

      Returns:
      the priority
      Default:
      0
    • dynamic

      boolean dynamic
      Returns true if the annotated method defines a dynamic handler.

      A dynamic handler must be added to the set of handlers of a component explicitly at run time using Handler.Evaluator.add(ComponentType, String, Object) or Handler.Evaluator.add(ComponentType, String, Object, Object, int).

      class SampleComponent extends Component {
      
          SampleComponent() {
              Handler.Evaluator.add(this, "onStartDynamic", someChannel);
          }
      
         @Handler(dynamic=true)
          public void onStartDynamic(Start event) {
              // Only invoked if added as handler at runtime
          }
      }
      
      Returns:
      the result
      Default:
      false
    • excludeSelf

      boolean excludeSelf
      Excludes the handler from channel matching against its component’s default criterion.

      The typical use case for this annotation is a converter component that receives events from some source channel and then fires the same kind of events with modified data using itself as the (source) channel. In this case, the events generated by the component must not be processed by the component although they are fired using the component as channel. So while it is useful to be able to target a specific component (using it as channel) in general, it isn’t in this special case and can therefore be turned off with this annotation.

      Of course, it would also be possible to work around the ambiguity by firing the conversion results on an extra channel. But it is quite intuitive to use the component itself as (source) channel.

      Returns:
      true, if set
      Default:
      false