2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / Novell.Directory.Ldap / Novell.Directory.Ldap.Events / LdapEventSource.cs
blob3135bc2f9c5cb4e17248cea64ff6d7eb277dbcc1
1 /******************************************************************************
2 * The MIT License
3 * Copyright (c) 2003 Novell Inc. www.novell.com
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *******************************************************************************/
24 // Novell.Directory.Ldap.Events.LdapEventSource.cs
26 // Author:
27 // Anil Bhatia (banil@novell.com)
29 // (C) 2003 Novell, Inc (http://www.novell.com)
32 using System;
33 using System.Threading;
35 using Novell.Directory.Ldap;
37 namespace Novell.Directory.Ldap.Events
39 /// <summary>
40 /// This is the base class for any EventSource.
41 /// </summary>
42 /// <seealso cref='Novell.Directory.Ldap.Events.PSearchEventSource'/>
43 /// <seealso cref='Novell.Directory.Ldap.Events.Edir.EdirEventSource'/>
44 public abstract class LdapEventSource
46 protected enum LISTENERS_COUNT
48 ZERO,
49 ONE,
50 MORE_THAN_ONE
53 internal protected const int EVENT_TYPE_UNKNOWN = -1;
54 protected const int DEFAULT_SLEEP_TIME = 1000;
56 protected int sleep_interval = DEFAULT_SLEEP_TIME;
58 /// <summary>
59 /// SleepInterval controls the duration after which event polling is repeated.
60 /// </summary>
61 public int SleepInterval
63 get
65 return sleep_interval;
67 set
69 if(value <= 0)
70 throw new ArgumentOutOfRangeException("SleepInterval","cannot take the negative or zero values ");
71 else
72 sleep_interval = value;
76 protected abstract int GetListeners();
78 protected LISTENERS_COUNT GetCurrentListenersState()
80 int nListeners = 0;
82 // Get Listeners registered with Actual EventSource
83 nListeners += GetListeners();
85 // Get Listeners registered for generic events
86 if (null != directory_event)
87 nListeners += directory_event.GetInvocationList().Length;
89 // Get Listeners registered for exception events
90 if (null != directory_exception_event)
91 nListeners += directory_exception_event.GetInvocationList().Length;
93 if (0 == nListeners)
94 return LISTENERS_COUNT.ZERO;
96 if (1 == nListeners)
97 return LISTENERS_COUNT.ONE;
99 return LISTENERS_COUNT.MORE_THAN_ONE;
102 protected void ListenerAdded()
104 // Get current state
105 LISTENERS_COUNT lc = GetCurrentListenersState();
107 switch (lc)
109 case LISTENERS_COUNT.ONE:
110 // start search and polling if not already started
111 StartSearchAndPolling();
112 break;
114 case LISTENERS_COUNT.ZERO:
115 case LISTENERS_COUNT.MORE_THAN_ONE:
116 default:
117 break;
121 protected void ListenerRemoved()
123 // Get current state
124 LISTENERS_COUNT lc = GetCurrentListenersState();
126 switch (lc)
128 case LISTENERS_COUNT.ZERO:
129 // stop search and polling if not already stopped
130 StopSearchAndPolling();
131 break;
133 case LISTENERS_COUNT.ONE:
134 case LISTENERS_COUNT.MORE_THAN_ONE:
135 default:
136 break;
140 protected abstract void StartSearchAndPolling();
141 protected abstract void StopSearchAndPolling();
143 protected DirectoryEventHandler directory_event;
145 /// <summary>
146 /// DirectoryEvent represents a generic Directory event.
147 /// If any event is not recognized by the actual
148 /// event sources, an object of corresponding DirectoryEventArgs
149 /// class is passed as part of the notification.
150 /// </summary>
151 public event DirectoryEventHandler DirectoryEvent
155 directory_event += value;
156 ListenerAdded();
158 remove
160 directory_event -= value;
161 ListenerRemoved();
165 /// <summary>
166 /// DirectoryEventHandler is the delegate definition for DirectoryEvent.
167 /// The client (listener) has to register using this delegate in order to
168 /// get events that may not be recognized by the actual event source.
169 /// </summary>
170 public delegate void DirectoryEventHandler(object source, DirectoryEventArgs objDirectoryEventArgs);
172 protected DirectoryExceptionEventHandler directory_exception_event;
173 /// <summary>
174 /// DirectoryEvent represents a generic Directory exception event.
175 /// </summary>
176 public event DirectoryExceptionEventHandler DirectoryExceptionEvent
180 directory_exception_event += value;
181 ListenerAdded();
183 remove
185 directory_exception_event -= value;
186 ListenerRemoved();
190 /// <summary>
191 /// DirectoryEventHandler is the delegate definition for DirectoryExceptionEvent.
192 /// </summary>
193 public delegate void DirectoryExceptionEventHandler(object source,
194 DirectoryExceptionEventArgs objDirectoryExceptionEventArgs);
196 protected EventsGenerator m_objEventsGenerator = null;
198 protected void StartEventPolling(
199 LdapMessageQueue queue,
200 LdapConnection conn,
201 int msgid)
203 // validate the argument values
204 if ( (queue == null)
205 || (conn == null))
207 throw new ArgumentException("No parameter can be Null.");
210 if (null == m_objEventsGenerator)
212 m_objEventsGenerator = new EventsGenerator(this, queue, conn, msgid);
213 m_objEventsGenerator.SleepTime = sleep_interval;
215 m_objEventsGenerator.StartEventPolling();
217 } // end of method StartEventPolling
219 protected void StopEventPolling()
221 if (null != m_objEventsGenerator)
223 m_objEventsGenerator.StopEventPolling();
224 m_objEventsGenerator = null;
226 } // end of method StopEventPolling
228 protected abstract bool
229 NotifyEventListeners(LdapMessage sourceMessage,
230 EventClassifiers aClassification,
231 int nType);
233 protected void NotifyListeners(LdapMessage sourceMessage,
234 EventClassifiers aClassification,
235 int nType)
237 // first let the actual source Notify the listeners with
238 // appropriate EventArgs
240 bool bListenersNotified = NotifyEventListeners(sourceMessage,
241 aClassification,
242 nType);
244 if (!bListenersNotified)
246 // Actual EventSource could not recognize the event
247 // Just notify the listeners for generic directory events
248 NotifyDirectoryListeners(sourceMessage, aClassification);
252 protected void NotifyDirectoryListeners(LdapMessage sourceMessage,
253 EventClassifiers aClassification)
255 NotifyDirectoryListeners(new DirectoryEventArgs(sourceMessage,
256 aClassification));
259 protected void NotifyDirectoryListeners(DirectoryEventArgs objDirectoryEventArgs)
261 if (null != directory_event)
263 directory_event(this, objDirectoryEventArgs);
267 protected void NotifyExceptionListeners(LdapMessage sourceMessage, LdapException ldapException)
269 if (null != directory_exception_event)
271 directory_exception_event(this, new DirectoryExceptionEventArgs(sourceMessage, ldapException));
276 /// <summary> This is a nested class that is supposed to monitor
277 /// LdapMessageQueue for events generated by the LDAP Server.
278 ///
279 /// </summary>
280 protected class EventsGenerator
282 private LdapEventSource m_objLdapEventSource;
283 private LdapMessageQueue searchqueue;
284 private int messageid;
285 private LdapConnection ldapconnection;
286 private volatile bool isrunning = true;
288 private int sleep_time;
289 /// <summary>
290 /// SleepTime controls the duration after which event polling is repeated.
291 /// </summary>
292 public int SleepTime
296 return sleep_time;
300 sleep_time = value;
305 public EventsGenerator(LdapEventSource objEventSource,
306 LdapMessageQueue queue,
307 LdapConnection conn,
308 int msgid)
310 m_objLdapEventSource = objEventSource;
311 searchqueue = queue;
312 ldapconnection = conn;
313 messageid = msgid;
314 sleep_time = DEFAULT_SLEEP_TIME;
315 } // end of Constructor
317 protected void Run()
319 while (isrunning)
321 LdapMessage response = null;
322 try
324 while ((isrunning)
325 && (!searchqueue.isResponseReceived(messageid)))
327 try
329 Thread.Sleep(sleep_time);
331 catch (ThreadInterruptedException e)
333 Console.WriteLine("EventsGenerator::Run Got ThreadInterruptedException e = {0}", e);
337 if (isrunning)
339 response = searchqueue.getResponse(messageid);
342 if (response != null)
344 processmessage(response);
347 catch (LdapException e)
349 m_objLdapEventSource.NotifyExceptionListeners(response, e);
352 } // end of method run
354 protected void processmessage(LdapMessage response)
356 if (response is LdapResponse)
358 try
360 ((LdapResponse) response).chkResultCode();
362 m_objLdapEventSource.NotifyEventListeners(response,
363 EventClassifiers.CLASSIFICATION_UNKNOWN,
364 EVENT_TYPE_UNKNOWN);
366 catch (LdapException e)
368 m_objLdapEventSource.NotifyExceptionListeners(response, e);
371 else
373 m_objLdapEventSource.NotifyEventListeners(response,
374 EventClassifiers.CLASSIFICATION_UNKNOWN,
375 EVENT_TYPE_UNKNOWN);
377 } // end of method processmessage
379 public void StartEventPolling()
381 isrunning = true;
382 new Thread( new ThreadStart( Run ) ).Start();
385 public void StopEventPolling()
387 isrunning = false;
388 } // end of method stopEventGeneration
389 } // end of class EventsGenerator
391 } // end of class LdapEventSource
393 } // end of namespace