cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java
changeset 101 133ef3ae697b
parent 37 c2bce6dd59e7
equal deleted inserted replaced
100:6e8bead0f126 101:133ef3ae697b
    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 }