/*********************************************************************/ /* */ /* 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 } }