I also wanted to add a
ObservationManager.getListener(String
listenerName) API.
-Vincent
On May 29, 2009, at 12:13 PM, Vincent Massol wrote:
On May 29, 2009, at 12:02 PM, Marius Dumitru Florea wrote:
Hi Vincent,
Vincent Massol wrote:
Here's my latest proposal:
/**
* Components wanting to receive Observation {@link Event events}
must implement this interface.
*
* @version $Id: EventListener.java 10164 2008-06-09 12:44:53Z
sdumitriu $
*/
public interface EventListener
{
/**
* @return the listener's name. It's a free form text identifying
this listener instance in a unique manner.
* This name is used for some operations in {@link
ObservationManager}.
*/
String getName();
/**
* @return the list of events this listener is configured to
receive. This listener will be automatically
* registered with this list of events against the {@link
ObservationManager}. For each matching event
* the {@link #onEvent(Event, Object, Object)} method
will be called.
*/
List<Event> getEvents();
/**
* The {@link org.xwiki.observation.ObservationManager} calls
this methods when an event matches the events for
* which this listener is registered (see {@link #getEvents()}.
*
* @param event the event triggered. Can be used to differentiate
different events if your Object supports several
* events for example.
* @param source the event source i.e. the object for which the
event was triggered. For example this would be the
* document Object if the event is a document update
event.
* @param data some additional and optional data passed that can
be acted on.
*/
void onEvent(Event event, Object source, Object data);
}
And:
/**
* The main orchestrator for event notification. To receive events
create a component implementing the
* {@link EventListener} interface. Your component will be
automatically registered when this Observation
* Manager component is loaded. To send events to all registered
listeners, call one of the
* {@link #notify} methods.
*
* @version $Id: ObservationManager.java 20537 2009-05-26 20:41:25Z
vmassol $
*/
@ComponentRole
public interface ObservationManager
{
/**
* Manually add a listener. Components implementing the {@link
EventListener} interfaces are only loaded
* when the Observation Manager component is created. Thus if you
need to add a new listener while the
* system is running you'll need to call this method.
*
* @param event the event to register the listener against; acts
as a template that filters out only specific events
* the listener is interested in
* @param eventListener the listener to register
*/
void addListener(EventListener eventListener);
/**
* Remove a listener from the list of registered listeners. The
removed listener will no longer receive events.
*
* @param listenerName the name of the listener to remove (must
match {@link EventListener#getName()}
*/
void removeListener(String listenerName);
/**
* Adds an Event to an already registered listener.
*
* @param listenerName the name of the listener to which the
event must be added
* (must match {@link EventListener#getName()}
* @param event the event to add to the matching listener
*/
void addEvent(String listenerName, Event event);
/**
* Removes an Event to an already registered listener.
*
* @param listenerName the name of the listener to which the
event must be removed
* (must match {@link EventListener#getName()}
* @param event the event to remove to the matching listener
*/
void removeEvent(String listenerName, Event event);
/**
* Remove a listener from a specific event.
*
* @param event the event to remove the listener from.
* @param eventListener the listener to remove.
*/
void removeListener(Event event, EventListener eventListener);
I don't understand why sometimes you use the name of the listener (a
String) to identify it and some times a reference (EventListener).
Why
does the ObservationManager need a listener name? I'm asking
because in
the event systems I know (like the DOM event system) there's no
need for
such a name.
The instance is used to register it and the name is used to modify
an existing instance since it would be cumbersome for the calling
code to have to retrieve an instance just to add an Event to it.
Note that this is more complex than it looks and it also prevents
having cyclic dependencies between Listener components and main
components (like MacroManager and MacroManagerListener for ex)
since the listener will need to call the main component when an
event happens and thus if the main component need to add an Event
it would need to get a listener instance.
-Vincent
>> /**
>> * Call the registered listeners matching the passed Event.
>> * The definition of <em>source</em> and <em>data</em>
is purely
>> up to the communicating classes.
>> *
>> * @param event the event to pass to the registered listeners
>> * @param source the source of the event (or <code>null</code>)
>> * @param data the additional data related to the event (or
>> <code>null</code>)
>> */
>> void notify(Event event, Object source, Object data);
>>
>> /**
>> * Convenience front-end where the additional data parameter is
>> <code>null</code>.
>> *
>> * @param event the event to pass to the registered listeners
>> * @param source the source of the event (or <code>null</code>)
>> * @see #notify(org.xwiki.observation.event.Event, Object,
>> Object)
>> */
>> void notify(Event event, Object source);
>> }
>>
>> This allows adding events after the listener is registered thus
>> allowing Sergiu's use case in the Localization module.
>>
>> WDYT?
>>
>> Thanks
>> -Vincent
>>
>> On May 28, 2009, at 1:59 PM, Sergiu Dumitriu wrote:
>>
>>> Sergiu Dumitriu wrote:
>>>> Vincent Massol wrote:
>>>>> Hi,
>>>>>
>>>>> There's a pb with the current implementation:
>>>>> When we get the Observation manager implementation and list the
>>>>> registered listeners we only get the components that have been
>>>>> initialized *before* we get the Observation manager component.
>>>>> Thus if
>>>>> we want to be sure all listeners will receive events we need to
>>>>> ensure they're loaded first. This is hard to do.
>>>>>
>>>>> I'm proposing instead to modify the observation module:
>>>>>
>>>>> * Modify EventListener to be a @ComponentRole
>>>> +1
>>>>
>>>>> * Add List<Event> EventListener.getEvents() (the events that
the
>>>>> listener handles)
>>>> Hm, I'm not sure about this. A document watcher will dynamically
>>>> add and
>>>> remove events to the list of monitored resources. We could have
>>>> this
>>>> method to be called for the initial registration, as otherwise
>>>> it's
>>>> hard
>>>> to do the initialization.
>>>>
>>>> +0
>>> Also, this requires that the ComponentManager is Initializable,
>>> otherwise it won't actually register anything.
>>>
>>>>> * Inject List<EventListener> in DefaultObservationManager.
>>>>> Thus when
>>>>> the Observation Manager is looked up, all listener components
>>>>> are
>>>>> created and injected.
>>>> +1
>>>>
>>>>> * Keep add/removeListener in ObservationManager so that
>>>>> listeners
>>>>> can
>>>>> be manually added/removed (for ex if a new listener component is
>>>>> added dynamically in the system) but with following signatures:
>>>>> - addListener(EventListener);
>>>>> - removeListener(EventListener);
>>>> -1. See above, a component with a dynamic list of events will
>>>> need to
>>>> register/unregister just one in a long list. So we do need the
>>>> existing
>>>> signatures. Maybe add these signatures, but also keep the
>>>> existing
>>>> ones.