32 import org.eclipse.core.runtime.IStatus; |
32 import org.eclipse.core.runtime.IStatus; |
33 import org.eclipse.core.runtime.Status; |
33 import org.eclipse.core.runtime.Status; |
34 import org.osgi.framework.Filter; |
34 import org.osgi.framework.Filter; |
35 |
35 |
36 /** |
36 /** |
37 * Class to manage DSF sessions. A DSF session is a way to |
37 * Class to manage DSF sessions. A DSF session is a way to associate a set of |
38 * associate a set of DSF services that are running simultaneously and |
38 * DSF services that are running simultaneously and are interacting with each |
39 * are interacting with each other to provide a complete set of functionality. |
39 * other to provide a complete set of functionality. |
40 * <p> |
40 * <p> |
41 * Properties of a session are following: |
41 * Properties of a session are following: <br> |
42 * <br>1. Each session is associated with a single DSF executor, although there |
42 * 1. Each session is associated with a single DSF executor, although there |
43 * could be multiple sessions using the same executor. |
43 * could be multiple sessions using the same executor. <br> |
44 * <br>2. Each session has a unique String identifier, which has to be used by |
44 * 2. Each session has a unique String identifier, which has to be used by the |
45 * the services belonging to this session when registering with OSGI services. |
45 * services belonging to this session when registering with OSGI services. <br> |
46 * <br>3. Each session has its set of service event listeners. |
46 * 3. Each session has its set of service event listeners. <br> |
47 * <br>4. Start and end of each session is announced by events, which are always |
47 * 4. Start and end of each session is announced by events, which are always |
48 * sent on that session's executor dispatch thread. |
48 * sent on that session's executor dispatch thread. |
49 * |
49 * |
50 * @see org.eclipse.cdt.dsf.concurrent.DsfExecutor |
50 * @see org.eclipse.cdt.dsf.concurrent.DsfExecutor |
51 * |
51 * |
52 * @since 1.0 |
52 * @since 1.0 |
53 */ |
53 */ |
54 @ConfinedToDsfExecutor("getExecutor") |
54 @ConfinedToDsfExecutor("getExecutor") |
55 public class DsfSession |
55 public class DsfSession { |
56 { |
56 /** |
57 /** |
57 * Listener for session started events. This listener is always going to be |
58 * Listener for session started events. This listener is always going to be |
58 * called in the dispatch thread of the session's executor. |
59 * called in the dispatch thread of the session's executor. |
59 */ |
60 */ |
60 public static interface SessionStartedListener { |
61 public static interface SessionStartedListener { |
61 /** |
62 /** |
62 * Called when a new session is started. It is always called in the |
63 * Called when a new session is started. It is always called in the |
63 * dispatch thread of the new session. |
64 * dispatch thread of the new session. |
64 */ |
65 */ |
65 public void sessionStarted(DsfSession session); |
66 public void sessionStarted(DsfSession session); |
66 } |
67 } |
67 |
68 |
68 /** |
69 /** |
69 * Listener for session ended events. This listener is always going to be |
70 * Listener for session ended events. This listener is always going to be |
70 * called in the dispatch thread of the session's executor. |
71 * called in the dispatch thread of the session's executor. |
71 */ |
72 */ |
72 public static interface SessionEndedListener { |
73 public static interface SessionEndedListener { |
73 /** |
74 /** |
74 * Called when a session is ended. It is always called in the dispatch |
75 * Called when a session is ended. It is always called in the |
75 * thread of the session. |
76 * dispatch thread of the session. |
76 */ |
77 */ |
77 public void sessionEnded(DsfSession session); |
78 public void sessionEnded(DsfSession session); |
78 } |
79 } |
79 |
80 |
80 private static int fgSessionIdCounter = 0; |
81 private static int fgSessionIdCounter = 0; |
81 private static Set<DsfSession> fgActiveSessions = Collections.synchronizedSet(new HashSet<DsfSession>()); |
82 private static Set<DsfSession> fgActiveSessions = Collections.synchronizedSet(new HashSet<DsfSession>()); |
82 private static List<SessionStartedListener> fSessionStartedListeners = Collections |
83 private static List<SessionStartedListener> fSessionStartedListeners = Collections.synchronizedList(new ArrayList<SessionStartedListener>()); |
83 .synchronizedList(new ArrayList<SessionStartedListener>()); |
84 private static List<SessionEndedListener> fSessionEndedListeners = Collections.synchronizedList(new ArrayList<SessionEndedListener>()); |
84 private static List<SessionEndedListener> fSessionEndedListeners = Collections |
85 |
85 .synchronizedList(new ArrayList<SessionEndedListener>()); |
86 /** Returns true if given session is currently active */ |
86 |
87 public static boolean isSessionActive(String sessionId) { |
87 /** Returns true if given session is currently active */ |
88 return getSession(sessionId) != null; |
88 public static boolean isSessionActive(String sessionId) { |
89 } |
89 return getSession(sessionId) != null; |
90 |
90 } |
91 /** Returns a session instance for given session identifier */ |
91 |
92 @ThreadSafe |
92 /** Returns a session instance for given session identifier */ |
93 public static DsfSession getSession(String sessionId) { |
93 @ThreadSafe |
94 synchronized(fgActiveSessions) { |
94 public static DsfSession getSession(String sessionId) { |
95 for (DsfSession session : fgActiveSessions) { |
95 synchronized (fgActiveSessions) { |
96 if (session.getId().equals(sessionId)) { |
96 for (DsfSession session : fgActiveSessions) { |
97 return session; |
97 if (session.getId().equals(sessionId)) { |
98 } |
98 return session; |
99 } |
99 } |
100 } |
100 } |
101 return null; |
101 } |
102 } |
102 return null; |
103 |
103 } |
104 /** |
104 |
105 * Registers a listener for session started events. |
105 /** |
106 * Can be called on any thread. |
106 * Registers a listener for session started events. Can be called on any |
107 */ |
107 * thread. |
108 @ThreadSafe |
108 */ |
109 public static void addSessionStartedListener(SessionStartedListener listener) { |
109 @ThreadSafe |
110 assert !fSessionStartedListeners.contains(listener); |
110 public static void addSessionStartedListener(SessionStartedListener listener) { |
111 fSessionStartedListeners.add(listener); |
111 assert !fSessionStartedListeners.contains(listener); |
112 } |
112 fSessionStartedListeners.add(listener); |
113 |
113 } |
114 /** |
114 |
115 * Un-registers a listener for session started events. |
115 /** |
116 * Can be called on any thread. |
116 * Un-registers a listener for session started events. Can be called on any |
117 */ |
117 * thread. |
118 @ThreadSafe |
118 */ |
119 public static void removeSessionStartedListener(SessionStartedListener listener) { |
119 @ThreadSafe |
120 assert fSessionStartedListeners.contains(listener); |
120 public static void removeSessionStartedListener(SessionStartedListener listener) { |
121 fSessionStartedListeners.remove(listener); |
121 assert fSessionStartedListeners.contains(listener); |
122 } |
122 fSessionStartedListeners.remove(listener); |
123 |
123 } |
124 /** |
124 |
125 * Registers a listener for session ended events. |
125 /** |
126 * Can be called on any thread. |
126 * Registers a listener for session ended events. Can be called on any |
127 */ |
127 * thread. |
128 @ThreadSafe |
128 */ |
129 public static void addSessionEndedListener(SessionEndedListener listener) { |
129 @ThreadSafe |
130 assert !fSessionEndedListeners.contains(listener); |
130 public static void addSessionEndedListener(SessionEndedListener listener) { |
131 fSessionEndedListeners.add(listener); |
131 assert !fSessionEndedListeners.contains(listener); |
132 } |
132 fSessionEndedListeners.add(listener); |
133 |
133 } |
134 /** |
134 |
135 * Un-registers a listener for session ended events. |
135 /** |
136 * Can be called on any thread. |
136 * Un-registers a listener for session ended events. Can be called on any |
137 */ |
137 * thread. |
138 @ThreadSafe |
138 */ |
139 public static void removeSessionEndedListener(SessionEndedListener listener) { |
139 @ThreadSafe |
140 assert fSessionEndedListeners.contains(listener); |
140 public static void removeSessionEndedListener(SessionEndedListener listener) { |
141 fSessionEndedListeners.remove(listener); |
141 assert fSessionEndedListeners.contains(listener); |
142 } |
142 fSessionEndedListeners.remove(listener); |
143 |
143 } |
144 /** |
144 |
145 * Starts and returns a new session instance. This method can be called on any |
145 /** |
146 * thread, but the session-started listeners will be called using the session's |
146 * Starts and returns a new session instance. This method can be called on |
147 * executor. |
147 * any thread, but the session-started listeners will be called using the |
148 * @param executor The DSF executor to use for this session. |
148 * session's executor. |
149 * @param ownerId ID (plugin ID preferably) of the owner of this session |
149 * |
150 * @return instance object of the new session |
150 * @param executor |
151 */ |
151 * The DSF executor to use for this session. |
152 @ThreadSafe |
152 * @param ownerId |
153 public static DsfSession startSession(DsfExecutor executor, String ownerId) { |
153 * ID (plugin ID preferably) of the owner of this session |
154 synchronized(fgActiveSessions) { |
154 * @return instance object of the new session |
155 final DsfSession newSession = new DsfSession(executor, ownerId, Integer.toString(fgSessionIdCounter++)); |
155 */ |
156 fgActiveSessions.add(newSession); |
156 @ThreadSafe |
157 executor.submit( new DsfRunnable() { public void run() { |
157 public static DsfSession startSession(DsfExecutor executor, String ownerId) { |
158 SessionStartedListener[] listeners = fSessionStartedListeners.toArray( |
158 synchronized (fgActiveSessions) { |
159 new SessionStartedListener[fSessionStartedListeners.size()]); |
159 final DsfSession newSession = new DsfSession(executor, ownerId, Integer.toString(fgSessionIdCounter++)); |
160 for (int i = 0; i < listeners.length; i++) { |
160 fgActiveSessions.add(newSession); |
161 listeners[i].sessionStarted(newSession); |
161 executor.submit(new DsfRunnable() { |
162 } |
162 public void run() { |
163 }}); |
163 SessionStartedListener[] listeners = fSessionStartedListeners |
164 return newSession; |
164 .toArray(new SessionStartedListener[fSessionStartedListeners.size()]); |
165 } |
165 for (int i = 0; i < listeners.length; i++) { |
166 } |
166 listeners[i].sessionStarted(newSession); |
167 |
167 } |
168 /** |
168 } |
169 * Terminates the given session. This method can be also called on any |
169 }); |
170 * thread, but the session-ended listeners will be called using the session's |
170 return newSession; |
171 * executor. |
171 } |
172 * @param session session to terminate |
172 } |
173 */ |
173 |
174 @ThreadSafe |
174 /** |
175 public static void endSession(final DsfSession session) { |
175 * Terminates the given session. This method can be also called on any |
176 synchronized(fgActiveSessions) { |
176 * thread, but the session-ended listeners will be called using the |
177 if (!fgActiveSessions.contains(session)) { |
177 * session's executor. |
178 throw new IllegalArgumentException(); |
178 * |
179 } |
179 * @param session |
180 fgActiveSessions.remove(session); |
180 * session to terminate |
181 session.getExecutor().submit( new DsfRunnable() { public void run() { |
181 */ |
182 SessionEndedListener[] listeners = fSessionEndedListeners.toArray( |
182 @ThreadSafe |
183 new SessionEndedListener[fSessionEndedListeners.size()]); |
183 public static void endSession(final DsfSession session) { |
184 for (int i = 0; i < listeners.length; i++) { |
184 synchronized (fgActiveSessions) { |
185 listeners[i].sessionEnded(session); |
185 if (!fgActiveSessions.contains(session)) { |
186 } |
186 throw new IllegalArgumentException(); |
187 }}); |
187 } |
188 } |
188 fgActiveSessions.remove(session); |
189 } |
189 session.getExecutor().submit(new DsfRunnable() { |
190 |
190 public void run() { |
191 private static class ListenerEntry { |
191 SessionEndedListener[] listeners = fSessionEndedListeners |
192 Object fListener; |
192 .toArray(new SessionEndedListener[fSessionEndedListeners.size()]); |
193 Filter fFilter; |
193 for (int i = 0; i < listeners.length; i++) { |
194 |
194 listeners[i].sessionEnded(session); |
195 ListenerEntry(Object listener, Filter filter) { |
195 } |
196 fListener = listener; |
196 } |
197 fFilter = filter; |
197 }); |
198 } |
198 } |
199 |
199 } |
200 @Override |
200 |
201 public boolean equals(Object other) { |
201 private static class ListenerEntry { |
202 return other instanceof ListenerEntry && fListener.equals(((ListenerEntry)other).fListener); |
202 Object fListener; |
203 } |
203 Filter fFilter; |
204 |
204 |
205 @Override |
205 ListenerEntry(Object listener, Filter filter) { |
206 public int hashCode() { return fListener.hashCode(); } |
206 fListener = listener; |
207 } |
207 fFilter = filter; |
208 |
208 } |
209 /** ID (plugin ID preferably) of the owner of this session */ |
209 |
210 private String fOwnerId; |
210 @Override |
211 |
211 public boolean equals(Object other) { |
212 /** Session ID of this session. */ |
212 return other instanceof ListenerEntry && fListener.equals(((ListenerEntry) other).fListener); |
213 private String fId; |
213 } |
214 |
214 |
215 /** Dispatch-thread executor for this session */ |
215 @Override |
216 private DsfExecutor fExecutor; |
216 public int hashCode() { |
217 |
217 return fListener.hashCode(); |
218 /** Service start-up counter for this session */ |
218 } |
219 private int fServiceInstanceCounter; |
219 } |
220 |
220 |
221 /** Map of registered event listeners. */ |
221 /** ID (plugin ID preferably) of the owner of this session */ |
222 private Map<ListenerEntry,Method[]> fListeners = new HashMap<ListenerEntry,Method[]>(); |
222 private final String fOwnerId; |
223 |
223 |
224 /** |
224 /** Session ID of this session. */ |
225 * Map of registered adapters, for implementing the |
225 private final String fId; |
226 * IModelContext.getAdapter() method. |
226 |
227 * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#getAdapter |
227 /** Dispatch-thread executor for this session */ |
228 */ |
228 private final DsfExecutor fExecutor; |
229 @SuppressWarnings("unchecked") |
229 |
230 private Map<Class,Object> fAdapters = Collections.synchronizedMap(new HashMap<Class,Object>()); |
230 /** Service start-up counter for this session */ |
231 |
231 private int fServiceInstanceCounter; |
232 /** Returns the owner ID of this session */ |
232 |
233 public String getOwnerId() { return fOwnerId; } |
233 /** Map of registered event listeners. */ |
234 |
234 private final Map<ListenerEntry, Method[]> fListeners = new HashMap<ListenerEntry, Method[]>(); |
235 public boolean isActive() { return DsfSession.isSessionActive(fId); } |
235 |
236 |
236 /** |
237 /** Returns the ID of this session */ |
237 * Map of registered adapters, for implementing the |
238 public String getId() { return fId; } |
238 * IModelContext.getAdapter() method. |
239 |
239 * |
240 /** Returns the DSF executor of this session */ |
240 * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#getAdapter |
241 public DsfExecutor getExecutor() { return fExecutor; } |
241 */ |
242 |
242 @SuppressWarnings("unchecked") |
243 /** |
243 private final Map<Class, Object> fAdapters = Collections.synchronizedMap(new HashMap<Class, Object>()); |
244 * Adds a new listener for service events in this session. |
244 |
245 * @param listener the listener that will receive service events |
245 /** Returns the owner ID of this session */ |
246 * @param filter optional filter to restrict the services that the |
246 public String getOwnerId() { |
247 * listener will receive events from |
247 return fOwnerId; |
248 */ |
248 } |
249 public void addServiceEventListener(Object listener, Filter filter) { |
249 |
250 ListenerEntry entry = new ListenerEntry(listener, filter); |
250 public boolean isActive() { |
251 assert !fListeners.containsKey(entry); |
251 return DsfSession.isSessionActive(fId); |
252 fListeners.put(entry, getEventHandlerMethods(listener)); |
252 } |
253 } |
253 |
254 |
254 /** Returns the ID of this session */ |
255 /** |
255 public String getId() { |
256 * Removes the given listener. |
256 return fId; |
257 * @param listener listener to remove |
257 } |
258 */ |
258 |
259 public void removeServiceEventListener(Object listener) { |
259 /** Returns the DSF executor of this session */ |
260 ListenerEntry entry = new ListenerEntry(listener, null); |
260 public DsfExecutor getExecutor() { |
261 assert fListeners.containsKey(entry); |
261 return fExecutor; |
262 fListeners.remove(entry); |
262 } |
263 } |
263 |
264 |
264 /** |
265 /** |
265 * Returns the active sessions |
266 * Retrieves and increments the startup counter for services in this session. |
266 * |
267 * DSF services should retrieve this counter when they are initialized, |
267 * @since 2.1 |
268 * and should return it through IService.getStartupNumber(). This number is then |
268 */ |
269 * used to prioritize service events. |
269 @ThreadSafe |
270 * @return current startup counter value |
270 public static DsfSession[] getActiveSessions() { |
271 */ |
271 return fgActiveSessions.toArray(new DsfSession[fgActiveSessions.size()]); |
272 public int getAndIncrementServiceStartupCounter() { return fServiceInstanceCounter++; } |
272 } |
273 |
273 |
274 /** |
274 /** |
275 * Dispatches the given event to service event listeners. The event is submitted to |
275 * Adds a new listener for service events in this session. |
276 * the executor to be dispatched. |
276 * |
277 * @param event to be sent out |
277 * @param listener |
278 * @param serviceProperties properties of the service requesting the event to be dispatched |
278 * the listener that will receive service events |
279 */ |
279 * @param filter |
280 @ThreadSafe |
280 * optional filter to restrict the services that the listener |
281 @SuppressWarnings("unchecked") |
281 * will receive events from |
282 public void dispatchEvent(final Object event, final Dictionary serviceProperties) { |
282 */ |
283 getExecutor().submit(new DsfRunnable() { |
283 public void addServiceEventListener(Object listener, Filter filter) { |
284 public void run() { doDispatchEvent(event, serviceProperties);} |
284 ListenerEntry entry = new ListenerEntry(listener, filter); |
285 @Override |
285 assert !fListeners.containsKey(entry); |
286 public String toString() { return "Event: " + event + ", from service " + serviceProperties; } //$NON-NLS-1$ //$NON-NLS-2$ |
286 fListeners.put(entry, getEventHandlerMethods(listener)); |
287 }); |
287 } |
288 } |
288 |
289 |
289 /** |
290 /** |
290 * Removes the given listener. |
291 * Registers a IModelContext adapter of given type. |
291 * |
292 * @param adapterType class type to register the adapter for |
292 * @param listener |
293 * @param adapter adapter instance to register |
293 * listener to remove |
294 * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter |
294 */ |
295 */ |
295 public void removeServiceEventListener(Object listener) { |
296 @ThreadSafe |
296 ListenerEntry entry = new ListenerEntry(listener, null); |
297 @SuppressWarnings("unchecked") |
297 assert fListeners.containsKey(entry); |
298 public void registerModelAdapter(Class adapterType, Object adapter) { |
298 fListeners.remove(entry); |
299 fAdapters.put(adapterType, adapter); |
299 } |
300 } |
300 |
301 |
301 /** |
302 /** |
302 * Retrieves and increments the startup counter for services in this |
303 * Un-registers a IModelContext adapter of given type. |
303 * session. DSF services should retrieve this counter when they are |
304 * @param adapterType adapter type to unregister |
304 * initialized, and should return it through IService.getStartupNumber(). |
305 * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter |
305 * This number is then used to prioritize service events. |
306 */ |
306 * |
307 @ThreadSafe |
307 * @return current startup counter value |
308 @SuppressWarnings("unchecked") |
308 */ |
309 public void unregisterModelAdapter(Class adapterType) { |
309 public int getAndIncrementServiceStartupCounter() { |
310 fAdapters.remove(adapterType); |
310 return fServiceInstanceCounter++; |
311 } |
311 } |
312 |
312 |
313 /** |
313 /** |
314 * Retrieves an adapter for given type for IModelContext. |
314 * Dispatches the given event to service event listeners. The event is |
315 * @param adapterType adapter type to look fors |
315 * submitted to the executor to be dispatched. |
316 * @return adapter object for given type, null if none is registered with the session |
316 * |
317 * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter |
317 * @param event |
318 */ |
318 * to be sent out |
319 @ThreadSafe |
319 * @param serviceProperties |
320 @SuppressWarnings("unchecked") |
320 * properties of the service requesting the event to be |
321 public Object getModelAdapter(Class adapterType) { |
321 * dispatched |
322 return fAdapters.get(adapterType); |
322 */ |
323 } |
323 @ThreadSafe |
324 |
324 @SuppressWarnings("unchecked") |
325 @Override |
325 public void dispatchEvent(final Object event, final Dictionary serviceProperties) { |
326 @ThreadSafe |
326 getExecutor().submit(new DsfRunnable() { |
327 public boolean equals(Object other) { |
327 public void run() { |
328 return other instanceof DsfSession && fId.equals(((DsfSession)other).fId); |
328 doDispatchEvent(event, serviceProperties); |
329 } |
329 } |
330 |
330 |
331 @Override |
331 @Override |
332 @ThreadSafe |
332 public String toString() { |
333 public int hashCode() { return fId.hashCode(); } |
333 return "Event: " + event + ", from service " + serviceProperties;} //$NON-NLS-1$ //$NON-NLS-2$ |
334 |
334 }); |
335 @SuppressWarnings("unchecked") |
335 } |
336 private void doDispatchEvent(Object event, Dictionary serviceProperties) { |
336 |
337 // Build a list of listeners; |
337 /** |
338 SortedMap<ListenerEntry,List<Method>> listeners = new TreeMap<ListenerEntry,List<Method>>(new Comparator<ListenerEntry>() { |
338 * Registers a IModelContext adapter of given type. |
339 public int compare(ListenerEntry o1, ListenerEntry o2) { |
339 * |
340 if (o1.fListener == o2.fListener) { |
340 * @param adapterType |
341 return 0; |
341 * class type to register the adapter for |
342 } if (o1.fListener instanceof IDsfService && !(o2.fListener instanceof IDsfService)) { |
342 * @param adapter |
343 return Integer.MIN_VALUE; |
343 * adapter instance to register |
344 } else if (o2.fListener instanceof IDsfService && !(o1.fListener instanceof IDsfService)) { |
344 * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter |
345 return Integer.MAX_VALUE; |
345 */ |
346 } else if ( (o1.fListener instanceof IDsfService) && (o2.fListener instanceof IDsfService) ) { |
346 @ThreadSafe |
347 return ((IDsfService)o1.fListener).getStartupNumber() - ((IDsfService)o2.fListener).getStartupNumber(); |
347 @SuppressWarnings("unchecked") |
348 } |
348 public void registerModelAdapter(Class adapterType, Object adapter) { |
349 return 1; |
349 fAdapters.put(adapterType, adapter); |
350 } |
350 } |
351 |
351 |
352 @Override |
352 /** |
353 public boolean equals(Object obj) { |
353 * Un-registers a IModelContext adapter of given type. |
354 return obj == this; |
354 * |
355 } |
355 * @param adapterType |
356 }); |
356 * adapter type to unregister |
357 |
357 * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter |
358 // Build a list of listeners and methods that are registered for this event class. |
358 */ |
359 Class<?> eventClass = event.getClass(); |
359 @ThreadSafe |
360 for (Map.Entry<ListenerEntry,Method[]> entry : fListeners.entrySet()) { |
360 @SuppressWarnings("unchecked") |
361 if (entry.getKey().fFilter != null && !entry.getKey().fFilter.match(serviceProperties)) { |
361 public void unregisterModelAdapter(Class adapterType) { |
362 // Dispatching service doesn't match the listener's filter, skip it. |
362 fAdapters.remove(adapterType); |
363 continue; |
363 } |
364 } |
364 |
365 Method[] allMethods = entry.getValue(); |
365 /** |
366 List<Method> matchingMethods = new ArrayList<Method>(); |
366 * Retrieves an adapter for given type for IModelContext. |
367 for (Method method : allMethods) { |
367 * |
368 assert method.getParameterTypes().length > 0 : eventClass.getName() + "." + method.getName() //$NON-NLS-1$ |
368 * @param adapterType |
369 + " signature contains zero parameters"; //$NON-NLS-1$ |
369 * adapter type to look fors |
370 if ( method.getParameterTypes()[0].isAssignableFrom(eventClass) ) { |
370 * @return adapter object for given type, null if none is registered with |
371 matchingMethods.add(method); |
371 * the session |
372 } |
372 * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter |
373 } |
373 */ |
374 if (!matchingMethods.isEmpty()) { |
374 @ThreadSafe |
375 listeners.put(entry.getKey(), matchingMethods); |
375 @SuppressWarnings("unchecked") |
376 } |
376 public Object getModelAdapter(Class adapterType) { |
377 } |
377 return fAdapters.get(adapterType); |
378 |
378 } |
379 // Call the listeners |
379 |
380 for (Map.Entry<ListenerEntry,List<Method>> entry : listeners.entrySet()) { |
380 @Override |
381 for (Method method : entry.getValue()) { |
381 @ThreadSafe |
382 try { |
382 public boolean equals(Object other) { |
383 method.invoke(entry.getKey().fListener, new Object[] { event } ); |
383 return other instanceof DsfSession && fId.equals(((DsfSession) other).fId); |
384 } |
384 } |
385 catch (IllegalAccessException e) { |
385 |
386 DsfPlugin.getDefault().getLog().log(new Status( |
386 @Override |
387 IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Security exception when calling a service event handler method", e)); //$NON-NLS-1$ |
387 @ThreadSafe |
388 assert false : "IServiceEventListener.ServiceHandlerMethod method not accessible, is listener declared public?"; //$NON-NLS-1$ |
388 public int hashCode() { |
389 } |
389 return fId.hashCode(); |
390 catch (InvocationTargetException e) { |
390 } |
391 DsfPlugin.getDefault().getLog().log(new Status( |
391 |
392 IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Invocation exception when calling a service event handler method", e)); //$NON-NLS-1$ |
392 @SuppressWarnings("unchecked") |
393 assert false : "Exception thrown by a IServiceEventListener.ServiceHandlerMethod method"; //$NON-NLS-1$ |
393 private void doDispatchEvent(Object event, Dictionary serviceProperties) { |
394 } |
394 // Build a list of listeners; |
395 } |
395 SortedMap<ListenerEntry, List<Method>> listeners = new TreeMap<ListenerEntry, List<Method>>( |
396 } |
396 new Comparator<ListenerEntry>() { |
397 } |
397 public int compare(ListenerEntry o1, ListenerEntry o2) { |
398 |
398 if (o1.fListener == o2.fListener) { |
399 private Method[] getEventHandlerMethods(Object listener) |
399 return 0; |
400 { |
400 } |
401 List<Method> retVal = new ArrayList<Method>(); |
401 if (o1.fListener instanceof IDsfService && !(o2.fListener instanceof IDsfService)) { |
402 try { |
402 return Integer.MIN_VALUE; |
403 Method[] methods = listener.getClass().getMethods(); |
403 } else if (o2.fListener instanceof IDsfService && !(o1.fListener instanceof IDsfService)) { |
404 for (Method method : methods) { |
404 return Integer.MAX_VALUE; |
405 if (method.isAnnotationPresent(DsfServiceEventHandler.class)) { |
405 } else if ((o1.fListener instanceof IDsfService) && (o2.fListener instanceof IDsfService)) { |
406 Class<?>[] paramTypes = method.getParameterTypes(); |
406 return ((IDsfService) o1.fListener).getStartupNumber() |
407 if (paramTypes.length > 2) { |
407 - ((IDsfService) o2.fListener).getStartupNumber(); |
408 throw new IllegalArgumentException("ServiceEventHandler method has incorrect number of parameters"); //$NON-NLS-1$ |
408 } |
409 } |
409 return 1; |
410 retVal.add(method); |
410 } |
411 } |
411 |
412 } |
412 @Override |
413 } catch(SecurityException e) { |
413 public boolean equals(Object obj) { |
414 throw new IllegalArgumentException("No permission to access ServiceEventHandler method"); //$NON-NLS-1$ |
414 return obj == this; |
415 } |
415 } |
416 |
416 }); |
417 if (retVal.isEmpty()) { |
417 |
418 throw new IllegalArgumentException("No methods marked with @ServiceEventHandler in listener, is listener declared public?"); //$NON-NLS-1$ |
418 // Build a list of listeners and methods that are registered for this |
419 } |
419 // event class. |
420 return retVal.toArray(new Method[retVal.size()]); |
420 Class<?> eventClass = event.getClass(); |
421 } |
421 for (Map.Entry<ListenerEntry, Method[]> entry : fListeners.entrySet()) { |
422 |
422 if (entry.getKey().fFilter != null && !entry.getKey().fFilter.match(serviceProperties)) { |
423 /** |
423 // Dispatching service doesn't match the listener's filter, skip |
424 * Class to be instanciated only using startSession() |
424 // it. |
425 */ |
425 continue; |
426 @ThreadSafe |
426 } |
427 private DsfSession(DsfExecutor executor, String ownerId, String id) { |
427 Method[] allMethods = entry.getValue(); |
428 fId = id; |
428 List<Method> matchingMethods = new ArrayList<Method>(); |
429 fOwnerId = ownerId; |
429 for (Method method : allMethods) { |
430 fExecutor = executor; |
430 assert method.getParameterTypes().length > 0 : eventClass.getName() + "." + method.getName() //$NON-NLS-1$ |
431 } |
431 + " signature contains zero parameters"; //$NON-NLS-1$ |
432 |
432 if (method.getParameterTypes()[0].isAssignableFrom(eventClass)) { |
|
433 matchingMethods.add(method); |
|
434 } |
|
435 } |
|
436 if (!matchingMethods.isEmpty()) { |
|
437 listeners.put(entry.getKey(), matchingMethods); |
|
438 } |
|
439 } |
|
440 |
|
441 // Call the listeners |
|
442 for (Map.Entry<ListenerEntry, List<Method>> entry : listeners.entrySet()) { |
|
443 for (Method method : entry.getValue()) { |
|
444 try { |
|
445 method.invoke(entry.getKey().fListener, new Object[] { event }); |
|
446 } catch (IllegalAccessException e) { |
|
447 DsfPlugin.getDefault().getLog().log( |
|
448 new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, |
|
449 "Security exception when calling a service event handler method", e)); //$NON-NLS-1$ |
|
450 assert false : "IServiceEventListener.ServiceHandlerMethod method not accessible, is listener declared public?"; //$NON-NLS-1$ |
|
451 } catch (InvocationTargetException e) { |
|
452 DsfPlugin.getDefault().getLog().log( |
|
453 new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, |
|
454 "Invocation exception when calling a service event handler method", e)); //$NON-NLS-1$ |
|
455 assert false : "Exception thrown by a IServiceEventListener.ServiceHandlerMethod method"; //$NON-NLS-1$ |
|
456 } |
|
457 } |
|
458 } |
|
459 } |
|
460 |
|
461 private Method[] getEventHandlerMethods(Object listener) { |
|
462 List<Method> retVal = new ArrayList<Method>(); |
|
463 try { |
|
464 Method[] methods = listener.getClass().getMethods(); |
|
465 for (Method method : methods) { |
|
466 if (method.isAnnotationPresent(DsfServiceEventHandler.class)) { |
|
467 Class<?>[] paramTypes = method.getParameterTypes(); |
|
468 if (paramTypes.length > 2) { |
|
469 throw new IllegalArgumentException( |
|
470 "ServiceEventHandler method has incorrect number of parameters"); //$NON-NLS-1$ |
|
471 } |
|
472 retVal.add(method); |
|
473 } |
|
474 } |
|
475 } catch (SecurityException e) { |
|
476 throw new IllegalArgumentException("No permission to access ServiceEventHandler method"); //$NON-NLS-1$ |
|
477 } |
|
478 |
|
479 if (retVal.isEmpty()) { |
|
480 throw new IllegalArgumentException( |
|
481 "No methods marked with @ServiceEventHandler in listener, is listener declared public?"); //$NON-NLS-1$ |
|
482 } |
|
483 return retVal.toArray(new Method[retVal.size()]); |
|
484 } |
|
485 |
|
486 /** |
|
487 * Class to be instanciated only using startSession() |
|
488 */ |
|
489 @ThreadSafe |
|
490 private DsfSession(DsfExecutor executor, String ownerId, String id) { |
|
491 fId = id; |
|
492 fOwnerId = ownerId; |
|
493 fExecutor = executor; |
|
494 } |
|
495 |
433 } |
496 } |