a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
394 lines
10 KiB
C#
394 lines
10 KiB
C#
/******************************************************************************
|
|
* The MIT License
|
|
* Copyright (c) 2003 Novell Inc. www.novell.com
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the Software), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*******************************************************************************/
|
|
//
|
|
// Novell.Directory.Ldap.Events.LdapEventSource.cs
|
|
//
|
|
// Author:
|
|
// Anil Bhatia (banil@novell.com)
|
|
//
|
|
// (C) 2003 Novell, Inc (http://www.novell.com)
|
|
//
|
|
|
|
using System;
|
|
using System.Threading;
|
|
|
|
using Novell.Directory.Ldap;
|
|
|
|
namespace Novell.Directory.Ldap.Events
|
|
{
|
|
/// <summary>
|
|
/// This is the base class for any EventSource.
|
|
/// </summary>
|
|
/// <seealso cref='Novell.Directory.Ldap.Events.PSearchEventSource'/>
|
|
/// <seealso cref='Novell.Directory.Ldap.Events.Edir.EdirEventSource'/>
|
|
public abstract class LdapEventSource
|
|
{
|
|
protected enum LISTENERS_COUNT
|
|
{
|
|
ZERO,
|
|
ONE,
|
|
MORE_THAN_ONE
|
|
}
|
|
|
|
internal protected const int EVENT_TYPE_UNKNOWN = -1;
|
|
protected const int DEFAULT_SLEEP_TIME = 1000;
|
|
|
|
protected int sleep_interval = DEFAULT_SLEEP_TIME;
|
|
|
|
/// <summary>
|
|
/// SleepInterval controls the duration after which event polling is repeated.
|
|
/// </summary>
|
|
public int SleepInterval
|
|
{
|
|
get
|
|
{
|
|
return sleep_interval;
|
|
}
|
|
set
|
|
{
|
|
if(value <= 0)
|
|
throw new ArgumentOutOfRangeException("SleepInterval","cannot take the negative or zero values ");
|
|
else
|
|
sleep_interval = value;
|
|
}
|
|
}
|
|
|
|
protected abstract int GetListeners();
|
|
|
|
protected LISTENERS_COUNT GetCurrentListenersState()
|
|
{
|
|
int nListeners = 0;
|
|
|
|
// Get Listeners registered with Actual EventSource
|
|
nListeners += GetListeners();
|
|
|
|
// Get Listeners registered for generic events
|
|
if (null != directory_event)
|
|
nListeners += directory_event.GetInvocationList().Length;
|
|
|
|
// Get Listeners registered for exception events
|
|
if (null != directory_exception_event)
|
|
nListeners += directory_exception_event.GetInvocationList().Length;
|
|
|
|
if (0 == nListeners)
|
|
return LISTENERS_COUNT.ZERO;
|
|
|
|
if (1 == nListeners)
|
|
return LISTENERS_COUNT.ONE;
|
|
|
|
return LISTENERS_COUNT.MORE_THAN_ONE;
|
|
}
|
|
|
|
protected void ListenerAdded()
|
|
{
|
|
// Get current state
|
|
LISTENERS_COUNT lc = GetCurrentListenersState();
|
|
|
|
switch (lc)
|
|
{
|
|
case LISTENERS_COUNT.ONE:
|
|
// start search and polling if not already started
|
|
StartSearchAndPolling();
|
|
break;
|
|
|
|
case LISTENERS_COUNT.ZERO:
|
|
case LISTENERS_COUNT.MORE_THAN_ONE:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected void ListenerRemoved()
|
|
{
|
|
// Get current state
|
|
LISTENERS_COUNT lc = GetCurrentListenersState();
|
|
|
|
switch (lc)
|
|
{
|
|
case LISTENERS_COUNT.ZERO:
|
|
// stop search and polling if not already stopped
|
|
StopSearchAndPolling();
|
|
break;
|
|
|
|
case LISTENERS_COUNT.ONE:
|
|
case LISTENERS_COUNT.MORE_THAN_ONE:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected abstract void StartSearchAndPolling();
|
|
protected abstract void StopSearchAndPolling();
|
|
|
|
protected DirectoryEventHandler directory_event;
|
|
|
|
/// <summary>
|
|
/// DirectoryEvent represents a generic Directory event.
|
|
/// If any event is not recognized by the actual
|
|
/// event sources, an object of corresponding DirectoryEventArgs
|
|
/// class is passed as part of the notification.
|
|
/// </summary>
|
|
public event DirectoryEventHandler DirectoryEvent
|
|
{
|
|
add
|
|
{
|
|
directory_event += value;
|
|
ListenerAdded();
|
|
}
|
|
remove
|
|
{
|
|
directory_event -= value;
|
|
ListenerRemoved();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// DirectoryEventHandler is the delegate definition for DirectoryEvent.
|
|
/// The client (listener) has to register using this delegate in order to
|
|
/// get events that may not be recognized by the actual event source.
|
|
/// </summary>
|
|
public delegate void DirectoryEventHandler(object source, DirectoryEventArgs objDirectoryEventArgs);
|
|
|
|
protected DirectoryExceptionEventHandler directory_exception_event;
|
|
/// <summary>
|
|
/// DirectoryEvent represents a generic Directory exception event.
|
|
/// </summary>
|
|
public event DirectoryExceptionEventHandler DirectoryExceptionEvent
|
|
{
|
|
add
|
|
{
|
|
directory_exception_event += value;
|
|
ListenerAdded();
|
|
}
|
|
remove
|
|
{
|
|
directory_exception_event -= value;
|
|
ListenerRemoved();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// DirectoryEventHandler is the delegate definition for DirectoryExceptionEvent.
|
|
/// </summary>
|
|
public delegate void DirectoryExceptionEventHandler(object source,
|
|
DirectoryExceptionEventArgs objDirectoryExceptionEventArgs);
|
|
|
|
protected EventsGenerator m_objEventsGenerator = null;
|
|
|
|
protected void StartEventPolling(
|
|
LdapMessageQueue queue,
|
|
LdapConnection conn,
|
|
int msgid)
|
|
{
|
|
// validate the argument values
|
|
if ( (queue == null)
|
|
|| (conn == null))
|
|
{
|
|
throw new ArgumentException("No parameter can be Null.");
|
|
}
|
|
|
|
if (null == m_objEventsGenerator)
|
|
{
|
|
m_objEventsGenerator = new EventsGenerator(this, queue, conn, msgid);
|
|
m_objEventsGenerator.SleepTime = sleep_interval;
|
|
|
|
m_objEventsGenerator.StartEventPolling();
|
|
}
|
|
} // end of method StartEventPolling
|
|
|
|
protected void StopEventPolling()
|
|
{
|
|
if (null != m_objEventsGenerator)
|
|
{
|
|
m_objEventsGenerator.StopEventPolling();
|
|
m_objEventsGenerator = null;
|
|
}
|
|
} // end of method StopEventPolling
|
|
|
|
protected abstract bool
|
|
NotifyEventListeners(LdapMessage sourceMessage,
|
|
EventClassifiers aClassification,
|
|
int nType);
|
|
|
|
protected void NotifyListeners(LdapMessage sourceMessage,
|
|
EventClassifiers aClassification,
|
|
int nType)
|
|
{
|
|
// first let the actual source Notify the listeners with
|
|
// appropriate EventArgs
|
|
|
|
bool bListenersNotified = NotifyEventListeners(sourceMessage,
|
|
aClassification,
|
|
nType);
|
|
|
|
if (!bListenersNotified)
|
|
{
|
|
// Actual EventSource could not recognize the event
|
|
// Just notify the listeners for generic directory events
|
|
NotifyDirectoryListeners(sourceMessage, aClassification);
|
|
}
|
|
}
|
|
|
|
protected void NotifyDirectoryListeners(LdapMessage sourceMessage,
|
|
EventClassifiers aClassification)
|
|
{
|
|
NotifyDirectoryListeners(new DirectoryEventArgs(sourceMessage,
|
|
aClassification));
|
|
}
|
|
|
|
protected void NotifyDirectoryListeners(DirectoryEventArgs objDirectoryEventArgs)
|
|
{
|
|
if (null != directory_event)
|
|
{
|
|
directory_event(this, objDirectoryEventArgs);
|
|
}
|
|
}
|
|
|
|
protected void NotifyExceptionListeners(LdapMessage sourceMessage, LdapException ldapException)
|
|
{
|
|
if (null != directory_exception_event)
|
|
{
|
|
directory_exception_event(this, new DirectoryExceptionEventArgs(sourceMessage, ldapException));
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary> This is a nested class that is supposed to monitor
|
|
/// LdapMessageQueue for events generated by the LDAP Server.
|
|
///
|
|
/// </summary>
|
|
protected class EventsGenerator
|
|
{
|
|
private LdapEventSource m_objLdapEventSource;
|
|
private LdapMessageQueue searchqueue;
|
|
private int messageid;
|
|
private LdapConnection ldapconnection;
|
|
private volatile bool isrunning = true;
|
|
|
|
private int sleep_time;
|
|
/// <summary>
|
|
/// SleepTime controls the duration after which event polling is repeated.
|
|
/// </summary>
|
|
public int SleepTime
|
|
{
|
|
get
|
|
{
|
|
return sleep_time;
|
|
}
|
|
set
|
|
{
|
|
sleep_time = value;
|
|
}
|
|
}
|
|
|
|
|
|
public EventsGenerator(LdapEventSource objEventSource,
|
|
LdapMessageQueue queue,
|
|
LdapConnection conn,
|
|
int msgid)
|
|
{
|
|
m_objLdapEventSource = objEventSource;
|
|
searchqueue = queue;
|
|
ldapconnection = conn;
|
|
messageid = msgid;
|
|
sleep_time = DEFAULT_SLEEP_TIME;
|
|
} // end of Constructor
|
|
|
|
protected void Run()
|
|
{
|
|
while (isrunning)
|
|
{
|
|
LdapMessage response = null;
|
|
try
|
|
{
|
|
while ((isrunning)
|
|
&& (!searchqueue.isResponseReceived(messageid)))
|
|
{
|
|
try
|
|
{
|
|
Thread.Sleep(sleep_time);
|
|
}
|
|
catch (ThreadInterruptedException e)
|
|
{
|
|
Console.WriteLine("EventsGenerator::Run Got ThreadInterruptedException e = {0}", e);
|
|
}
|
|
}
|
|
|
|
if (isrunning)
|
|
{
|
|
response = searchqueue.getResponse(messageid);
|
|
}
|
|
|
|
if (response != null)
|
|
{
|
|
processmessage(response);
|
|
}
|
|
}
|
|
catch (LdapException e)
|
|
{
|
|
m_objLdapEventSource.NotifyExceptionListeners(response, e);
|
|
}
|
|
}
|
|
} // end of method run
|
|
|
|
protected void processmessage(LdapMessage response)
|
|
{
|
|
if (response is LdapResponse)
|
|
{
|
|
try
|
|
{
|
|
((LdapResponse) response).chkResultCode();
|
|
|
|
m_objLdapEventSource.NotifyEventListeners(response,
|
|
EventClassifiers.CLASSIFICATION_UNKNOWN,
|
|
EVENT_TYPE_UNKNOWN);
|
|
}
|
|
catch (LdapException e)
|
|
{
|
|
m_objLdapEventSource.NotifyExceptionListeners(response, e);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_objLdapEventSource.NotifyEventListeners(response,
|
|
EventClassifiers.CLASSIFICATION_UNKNOWN,
|
|
EVENT_TYPE_UNKNOWN);
|
|
}
|
|
} // end of method processmessage
|
|
|
|
public void StartEventPolling()
|
|
{
|
|
isrunning = true;
|
|
new Thread( new ThreadStart( Run ) ).Start();
|
|
}
|
|
|
|
public void StopEventPolling()
|
|
{
|
|
isrunning = false;
|
|
} // end of method stopEventGeneration
|
|
} // end of class EventsGenerator
|
|
|
|
} // end of class LdapEventSource
|
|
|
|
} // end of namespace
|