/*********************************************************************/
/* */
/* AgentService Framework */
/* www.agentservice.it */
/* */
/* Copyright (C) 2007 l.i.d.o. - DIST, University of Genoa, Italy */
/* GNU Lesser General Public License */
/* */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation, */
/* version 2.1 of the License. */
/* */
/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
/* Lesser General Public License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the */
/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */
/* Boston, MA 02111-1307, USA. */
/* */
/*********************************************************************/
using System;
using System.Reflection;
using System.Collections;
using AgentService.Platform;
using AgentService.Platform.Modules;
using AgentService.Platform.Commands;
using AgentService.Interop;
namespace AgentService.Platform
{
///
/// Interface IPlatformContext. Defines the basic functionalities accessible
/// to each module.
///
public interface IPlatformContext : IEventSinkManager, IEventManager
{
#region Platform Information
///
/// Gets the platform base directory.
///
string PlatformBaseDir
{
get;
}
///
/// Gets the platform core modules configuration path.
///
string PlatformCoreConfPath
{
get;
}
///
/// Gets the platform core modules bin path.
///
string PlatformCoreBinPath
{
get;
}
///
/// Gets the platform additional modules configuration path.
///
string PlatformAddConfPath
{
get;
}
///
/// Gets the platform additional modules bin path.
///
string PlatformAddBinPath
{
get;
}
///
/// Gets the platform description.
///
IPlatformDescription Description
{
get;
}
///
/// Gets true if the platform started
/// for the first time (after install).
///
bool IsFirstStart
{
get;
}
#endregion
#region PlatformCommands
///
/// Posts a command to the platform command queue.
///
/// command object
void PostCommand(PlatformCommand cmd);
#endregion
}
///
/// Class CustomEventInfo. Defines the information
/// about a custom event.
///
public class CustomEventInfo
{
///
/// Gets the custom event token
///
public int Token
{
get
{
return this.GetHashCode();
}
}
///
/// custom event name
///
private string name;
///
/// Gets, sets the custom event name.
///
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
///
/// List of handlers attached to this
/// event.
///
public event PlatformEventHandler Handlers;
///
/// Constructs a CustomEventInfo instance.
///
/// name of the event
public CustomEventInfo(string name)
{
this.name = name;
}
///
/// Raises the custom event.
///
/// sender of the event
/// event arguments
public void Raise(object sender, PlatformEventArgs args)
{
if (this.Handlers != null)
{
this.Handlers(sender, args);
}
}
}
///
/// Class EventSinkInfo. Mantains the information
/// about the sink of a given event.
///
public class EventSinkInfo
{
///
/// event sink descriptor.
///
private EventSinkDescriptor descriptor;
///
/// Gets, sets the descriptor of the sink
///
public EventSinkDescriptor Descriptor
{
get
{
return this.descriptor;
}
set
{
this.descriptor = value;
}
}
///
/// Sink of the event.
///
private event PlatformEventSinkHandler sink;
///
/// Constructs an EventSinkInfo instance.
///
/// descriptor of th sink
/// sink of the event
public EventSinkInfo(EventSinkDescriptor descriptor, PlatformEventSinkHandler sink)
{
this.descriptor = descriptor;
this.sink += sink;
}
///
/// Raises the event and forwards it to the connected sink.
///
/// event sink arguments
public void Absorbe(PlatformSinkEventArgs args)
{
this.sink(this, args);
}
}
///
/// Class PlatformContext. Defines the context that is accessible to each module.
///
public class PlatformContext : IPlatformContext
{
///
/// reference to the platform.
///
private IPlatform platform;
///
/// Maps the custom name of the custom events
/// to the real custom event objects.
///
private Hashtable customEventMap;
///
/// Maps the event sink object to real
/// event sink.
///
private Hashtable eventSinkMap;
#region Standard Platform Events
///
/// Fires every time an agent is created.
///
public event PlatformEventHandler OnAgentCreated;
///
/// Fires every time an agent is resumed.
///
public event PlatformEventHandler OnAgentResumed;
///
/// Fires every time an agent is stopped.
///
public event PlatformEventHandler OnAgentStopped;
///
/// Fires every time an agent is woken up.
///
public event PlatformEventHandler OnAgentWokenUp;
///
/// Fires every time a message is sent.
///
public event PlatformEventHandler OnMessageSent;
///
/// Fires every time a message is sent.
///
public event PlatformEventHandler OnMessageReceived;
///
/// Fires every time a bulk of messages is received.
///
public event PlatformEventHandler OnMessageBatch;
///
/// Fires every time a conversation is requested.
///
public event PlatformEventHandler OnConversationRequested;
///
/// Fires every time a conversation is accepted and then opened.
///
public event PlatformEventHandler OnConversationAccepted;
///
/// Fires every time a comversation is refused.
///
public event PlatformEventHandler OnConversationRefused;
///
/// Fires every time a conversation is closed.
///
public event PlatformEventHandler OnConversationClosed;
///
/// Fires every time an agent is persisted.
///
public event PlatformEventHandler OnAgentPersisted;
///
/// Fires every time an assembly is uploaded into the platform storage.
///
public event PlatformEventHandler OnAssemblyUploaded;
///
/// Fires every time an assembly is removed from the platform storage.
///
public event PlatformEventHandler OnAssemblyRemoved;
#endregion
///
/// Constructs a PlatformContext object with the given platform properties.
///
/// platform base directory
/// core modules bin path
/// core modules conf path
/// additional modules bin path
/// additional modules conf path
public PlatformContext(IPlatform platform
/* PlatformDescription description, string baseDir,
string coreBinPath, string coreConfPath,
string addBinPath, string addConfPath
*/)
{
this.platform = platform;
this.description = platform.Description;
this.platformBaseDir = platform.Configuration.BaseDirPath;
this.platformCoreBinPath = platform.Configuration.CoreModulesBinPath;
this.platformCoreConfPath = platform.Configuration.CoreModulesConfPath;
this.platformAddConfPath = platform.Configuration.AdditionalModulesConfPath;
this.platformAddBinPath = platform.Configuration.AdditionalModulesBinPath;
this.customEventMap = new Hashtable();
this.eventSinkMap = new Hashtable();
}
#region Platform Information
///
/// platform base directory
///
private string platformBaseDir;
///
/// Gets the platform base directory
///
public string PlatformBaseDir
{
get
{
return this.platformBaseDir;
}
}
///
/// platform core modules configuration path
///
private string platformCoreConfPath;
///
/// Gets the platform core modules configuration path
///
public string PlatformCoreConfPath
{
get
{
return this.platformCoreConfPath;
}
}
///
/// platform core modules bin path
///
private string platformCoreBinPath;
///
/// Gets the platform core modules bin path
///
public string PlatformCoreBinPath
{
get
{
return this.platformCoreBinPath;
}
}
///
/// platform additional modules configuration path
///
private string platformAddConfPath;
///
/// Gets the platform additional modules configuration path
///
public string PlatformAddConfPath
{
get
{
return this.platformAddConfPath;
}
}
///
/// platform additional modules bin path
///
private string platformAddBinPath;
///
/// Gets the platform additional modules bin path
///
public string PlatformAddBinPath
{
get
{
return this.platformAddBinPath;
}
}
///
/// platform description
///
private IPlatformDescription description;
///
/// Gets the platform description
///
public IPlatformDescription Description
{
get
{
return this.description;
}
}
///
/// Gets true if the platform started
/// after an installation.
///
public bool IsFirstStart
{
get
{
return this.platform.Configuration.IsFirstStart;
}
}
#endregion
#region Custom Events Management
///
/// Adds an event to the custom event registry
///
/// name of the event
/// a token that is used by the owner to track the event, 0 if the event is already present
public int AddEvent(string evtName)
{
lock(this.customEventMap.SyncRoot)
{
CustomEventInfo evtInfo = this.customEventMap[evtName] as CustomEventInfo;
if ((evtInfo == null) && (evtName != null))
{
evtInfo = new CustomEventInfo(evtName);
this.customEventMap.Add(evtName,evtInfo);
return evtInfo.Token;
}
return 0;
}
}
///
/// Removes the event associated to the given token
///
/// token that identifies the event
public bool RemoveEvent(int token)
{
lock(this.customEventMap.SyncRoot)
{
CustomEventInfo found = null;
foreach(CustomEventInfo evtInfo in this.customEventMap.Values)
{
if (evtInfo.Token == token)
{
found = evtInfo;
break;
}
}
if (found != null)
{
this.customEventMap.Remove(found.Name);
return true;
}
return false;
}
}
///
/// Raises the event associated to the given token
///
/// token that identifies the event
/// event argument
/// true if the event is found
public bool RaiseEvent(int token, PlatformEventArgs args)
{
lock(this.customEventMap.SyncRoot)
{
CustomEventInfo found = null;
foreach(CustomEventInfo evtInfo in this.customEventMap.Values)
{
if (evtInfo.Token == token)
{
found = evtInfo;
found.Raise(this,args);
return true;
}
}
return false;
}
}
///
/// Registers an handler to the given event
///
/// name that identifies the event
/// delegate the will be registered
/// true if the registration process is successful, false if the event is not present
public bool Register(string evtName, PlatformEventHandler handler)
{
lock(this.customEventMap.SyncRoot)
{
CustomEventInfo evtInfo = this.customEventMap[evtName] as CustomEventInfo;
if (evtInfo != null)
{
evtInfo.Handlers += handler;
return true;
}
return false;
}
}
///
/// Deregisters an handler to the given event
///
/// name that identifies the event
/// delegate to deregister
/// true if the deregistration process succeeds, falise if the event is not present
public bool Deregister(string evtName, PlatformEventHandler handler)
{
lock(this.customEventMap.SyncRoot)
{
CustomEventInfo evtInfo = this.customEventMap[evtName] as CustomEventInfo;
if (evtInfo != null)
{
evtInfo.Handlers -= handler;
return true;
}
return false;
}
}
#endregion
#region Standard Event Management
///
/// Fires a specified PlatformEvent, with the given args,
/// used by the platform in order to notify the modules that
/// have been registered for that event
///
/// type of the event
/// corresponding srguments
/// owning token
public void RaiseStandardEvent(PlatformEvent eventType, PlatformEventArgs args, int token)
{
if ((token == this.platform.Messaging.GetHashCode()) &&
((eventType == PlatformEvent.ConversationAccepted) ||
(eventType == PlatformEvent.ConversationClosed) ||
(eventType == PlatformEvent.ConversationRefused) ||
(eventType == PlatformEvent.MessageBatch) ||
(eventType == PlatformEvent.MessageReceived) ||
(eventType == PlatformEvent.MessageSent))
)
{
this.raise(eventType, args);
}
else if ((token == this.platform.Storage.GetHashCode()) &&
((eventType == PlatformEvent.AssemblyRemoved) ||
(eventType == PlatformEvent.AssemblyUploaded))
)
{
this.raise(eventType, args);
}
else if (true)
{
// TODO: for all the events related to
// the activity of the AMS
}
}
///
/// Retrieves a valid token for the given core module.
/// The token is used to allow core modules to raise
/// the standard events that belongs to them.
///
/// the instance of the module
/// which is requesting the token
/// owning token
public int GetToken(IPlatformModule module)
{
if (module == this.platform.Messaging)
{
return this.platform.Messaging.GetHashCode();
}
if (module == this.platform.Storage)
{
return this.platform.Storage.GetHashCode();
}
return 0;
}
///
/// Raises a standard event
///
/// standard event type
/// event arguments
internal void raise(PlatformEvent eventType, PlatformEventArgs args)
{
switch(eventType)
{
case PlatformEvent.AgentCreated :
if (this.OnAgentCreated != null)
this.OnAgentCreated(this,args);
break;
case PlatformEvent.AgentPersisted :
if (this.OnAgentPersisted != null)
this.OnAgentPersisted(this,args);
break;
case PlatformEvent.AgentResumed :
if (this.OnAgentResumed != null)
this.OnAgentResumed(this,args);
break;
case PlatformEvent.AgentStopped :
if (this.OnAgentStopped != null)
this.OnAgentStopped(this,args);
break;
case PlatformEvent.AgentWokenUp :
if (this.OnAgentWokenUp != null)
this.OnAgentWokenUp(this,args);
break;
case PlatformEvent.AssemblyUploaded :
if (this.OnAssemblyUploaded != null)
this.OnAssemblyUploaded(this,args);
break;
case PlatformEvent.AssemblyRemoved :
if (this.OnAssemblyRemoved != null)
this.OnAssemblyRemoved(this,args);
break;
case PlatformEvent.MessageSent :
if (this.OnMessageSent != null)
this.OnMessageSent(this,args);
break;
case PlatformEvent.MessageReceived :
if (this.OnMessageReceived != null)
this.OnMessageReceived(this,args);
break;
case PlatformEvent.MessageBatch :
if (this.OnMessageBatch != null)
this.OnMessageBatch(this,args);
break;
case PlatformEvent.ConversationRequested :
if (this.OnConversationRequested != null)
this.OnConversationRequested(this,args);
break;
case PlatformEvent.ConversationAccepted :
if (this.OnConversationAccepted != null)
this.OnConversationAccepted(this,args);
break;
case PlatformEvent.ConversationRefused :
if (this.OnConversationRefused != null)
this.OnConversationRefused(this,args);
break;
case PlatformEvent.ConversationClosed :
if (this.OnConversationClosed != null)
this.OnConversationClosed(this,args);
break;
}
}
#endregion
#region Platform Commands
///
/// Posts a command to the platform command queue
///
/// command object
public void PostCommand(PlatformCommand cmd)
{
// TODO: Add code here to handle the
// command posting operation
throw new System.NotImplementedException();
}
#endregion
#region Event Sink Management
///
/// Returns the list of all the registered event
/// sinks.
///
/// the list of the current event sinks
public EventSinkDescriptor[] GetRegisteredSinks()
{
lock(this.eventSinkMap.SyncRoot)
{
EventSinkDescriptor[] descriptors = new EventSinkDescriptor[this.eventSinkMap.Count];
int ndx = 0;
foreach(EventSinkInfo info in this.eventSinkMap.Values)
{
descriptors[ndx++] = info.Descriptor;
}
return descriptors;
}
}
///
/// Registers an event sink.
///
/// event sink descriptor
/// handler of the event
/// owning token
///
/// one of the following:
///
/// - SinkAlreadyExists - the proposed event sink has been already registered
/// - SinkInvalidEvent - the event descriptor does not identify a valid event sink
/// - SinkOk - registration successful
///
///
public SinkStatusCodes RegisterEventSink(EventSinkDescriptor evtSink, PlatformEventSinkHandler handler, out int token)
{
token = 0;
if ((evtSink == null) || (handler == null))
{
return SinkStatusCodes.SinkInvalidEvent;
}
lock(this.eventSinkMap.SyncRoot)
{
EventSinkInfo info = this.eventSinkMap[evtSink.Name] as EventSinkInfo;
if (info != null)
{
return SinkStatusCodes.SinkAlreadyExists;
}
info = new EventSinkInfo(evtSink,handler);
token = info.GetHashCode();
this.eventSinkMap.Add(info.Descriptor.Name, info);
}
return SinkStatusCodes.SinkOk;
}
///
/// Deregisters an event sink.
///
/// event sink descriptor
/// owning token
///
/// one of the following:
///
/// - SinkNotFound - the event sink identified by the descriptor does not exists
/// - SinkNotOwned - the given token does not allow the modification of the sink
/// - SinkInvalidEvent - the event descriptor does not identify a valid event sink
/// - SinkOk - deregistration successful
///
///
public SinkStatusCodes DeregisterEventSink(EventSinkDescriptor evtSink, int token)
{
if (evtSink == null)
{
return SinkStatusCodes.SinkInvalidEvent;
}
lock(this.eventSinkMap.SyncRoot)
{
EventSinkInfo info = this.eventSinkMap[evtSink.Name] as EventSinkInfo;
if (info == null)
{
return SinkStatusCodes.SinkNotFound;
}
if (info.GetHashCode() != token)
{
return SinkStatusCodes.SinkNotOwned;
}
this.eventSinkMap.Remove(info.Descriptor.Name);
}
return SinkStatusCodes.SinkOk;
}
///
/// Raises an avent for a speficied event sink.
///
/// event name
/// event
///
/// one of the following:
///
/// - SinkNotFound - the event sink identified by the name does not exists
/// - SinkInvalidEvent - the event object is not valid for the given event sink
/// - SinkOk - the event has been pumped to the sink
///
///
public SinkStatusCodes PumpEvent(string evtName, PlatformSinkEvent evt)
{
lock(this.eventSinkMap.SyncRoot)
{
EventSinkInfo info = this.eventSinkMap[evtName] as EventSinkInfo;
if (info == null)
{
return SinkStatusCodes.SinkNotFound;
}
if (info.Descriptor.EventType.IsInstanceOfType(evt))
{
info.Absorbe(new PlatformSinkEventArgs(evtName,evt));
return SinkStatusCodes.SinkOk;
}
return SinkStatusCodes.SinkInvalidEvent;
}
}
///
/// Check if anyone is resgistered as event sink of a given avent
///
/// Descriptor of the event sink
/// True if anyone is registered as event sink
public bool IsEventSinkRegistered (EventSinkDescriptor evtSinkDescriptor)
{
EventSinkDescriptor[] sinkDescriptors = this.GetRegisteredSinks();
foreach (EventSinkDescriptor descriptor in sinkDescriptors)
{
if (evtSinkDescriptor.Equals(descriptor))
{
return true;
}
}
return false;
}
#endregion
}
}