View Javadoc

1   /*
2    Copyright 2008 Ramon Servadei
3   
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7   
8    http://www.apache.org/licenses/LICENSE-2.0
9   
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15   */
16  package fulmine.event.listener;
17  
18  import static fulmine.util.Utils.COLON;
19  import static fulmine.util.Utils.nullCheck;
20  
21  import java.util.Arrays;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import fulmine.AbstractLifeCycle;
27  import fulmine.event.IEvent;
28  import fulmine.event.IEventManager;
29  import fulmine.event.IEventSource;
30  import fulmine.event.system.AbstractSystemEvent;
31  import fulmine.event.system.ISystemEvent;
32  import fulmine.util.collection.CollectionFactory;
33  import fulmine.util.log.AsyncLog;
34  
35  /**
36   * An event listener that is a composition of multiple internal
37   * {@link IEventListener} objects that each handle a specific type of
38   * {@link IEvent}. Events received by this listener are passed on to the
39   * listener that is mapped to the event's class.
40   * <p>
41   * This class registers itself with event sources and then passes the events to
42   * the appropriate mapped event listener. The internal listeners are never
43   * registered directly with the event sources.
44   * <p>
45   * This needs to locate the listener per event by checking <i>assignment
46   * compatibility</i> of the event with all listeners' registered event class.
47   * This could mean that multiple internal listeners receive the event if there
48   * is an intersection between the registered event class of the listeners and
49   * the current event's class.
50   * <p>
51   * During the {@link #start()} and {@link #destroy()} methods, only listeners
52   * that are mapped to an {@link AbstractSystemEvent} event will cause the
53   * multi-event listener to be registered/unregistered against the event's
54   * 'singleton' source ({@link IEventManager#getSystemEventSource(Class)}).
55   * 
56   * @author Ramon Servadei
57   */
58  public class MultiEventListener extends AbstractLifeCycle implements
59      ILifeCycleEventListener
60  {
61      private final static AsyncLog LOG = new AsyncLog(MultiEventListener.class);
62  
63      /** The listener for each event type */
64      final Map<Class<? extends IEvent>, IEventListener> listeners;
65  
66      /** The name for this */
67      private String name;
68  
69      /** Events context */
70      private final IEventManager context;
71  
72      /**
73       * The filter for events handled by this. The filter is a composition of all
74       * the event filters of the composite {@link IEventListener} instances.
75       */
76      private final Class<? extends IEvent>[] filter;
77  
78      /**
79       * Standard constructor
80       * 
81       * @param name
82       *            the name for this
83       * @param context
84       *            the event context to use
85       * @param listeners
86       *            maps the {@link IEvent} type to the {@link IEventListener}
87       *            object that will process events of that type
88       */
89      @SuppressWarnings("unchecked")
90      public MultiEventListener(String name, IEventManager context,
91          Map<Class<? extends IEvent>, IEventListener> listeners)
92      {
93          super();
94          nullCheck(name, "Null name");
95          nullCheck(listeners, "No listeners provided");
96          this.context = context;
97          this.name = name;
98          this.listeners = listeners;
99          List<Class<? extends IEvent>> filterList = CollectionFactory.newList();
100         for (IEventListener listener : listeners.values())
101         {
102             filterList.addAll(Arrays.asList(listener.getEventTypeFilter()));
103         }
104         this.filter = filterList.toArray(new Class[filterList.size()]);
105     }
106 
107     @SuppressWarnings("unchecked")
108     @Override
109     protected void doDestroy()
110     {
111         final Set<Class<? extends IEvent>> eventTypes = getListeners().keySet();
112         for (Class<? extends IEvent> eventType : eventTypes)
113         {
114             if (AbstractSystemEvent.class.isAssignableFrom(eventType))
115             {
116                 getContext().getSystemEventSource(
117                     (Class<? extends ISystemEvent>) eventType).removeListener(
118                     this);
119             }
120         }
121         getListeners().clear();
122     }
123 
124     @Override
125     protected AsyncLog getLog()
126     {
127         return LOG;
128     }
129 
130     @SuppressWarnings("unchecked")
131     @Override
132     protected void doStart()
133     {
134         final Set<Class<? extends IEvent>> eventTypes = getListeners().keySet();
135         for (Class<? extends IEvent> eventType : eventTypes)
136         {
137             if (AbstractSystemEvent.class.isAssignableFrom(eventType))
138             {
139                 getContext().getSystemEventSource(
140                     (Class<? extends ISystemEvent>) eventType).addListener(this);
141             }
142         }
143     }
144 
145     public final void update(IEvent event)
146     {
147         if (getLog().isTraceEnabled())
148         {
149             getLog().trace("update event=" + event);
150         }
151         for (int i = 0; i < getEventTypeFilter().length; i++)
152         {
153             Class<? extends IEvent> eventType = getEventTypeFilter()[i];
154             if (eventType.isInstance(event))
155             {
156                 final IEventListener eventListener =
157                     getListeners().get(eventType);
158                 if (eventListener != null)
159                 {
160                     eventListener.update(event);
161                 }
162             }
163         }
164     }
165 
166     public void addedAsListenerFor(IEventSource source)
167     {
168         // noop
169     }
170 
171     public void removedAsListenerFrom(IEventSource source)
172     {
173         // noop
174     }
175 
176     public Class<? extends IEvent>[] getEventTypeFilter()
177     {
178         return this.filter;
179     }
180 
181     Map<Class<? extends IEvent>, IEventListener> getListeners()
182     {
183         return this.listeners;
184     }
185 
186     String getName()
187     {
188         return this.name;
189     }
190 
191     IEventManager getContext()
192     {
193         return this.context;
194     }
195 
196     @Override
197     public final String toString()
198     {
199         return getClass().getSimpleName() + COLON + name;
200     }
201 }