/*********************************************************************/ /* */ /* 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 Microsoft.ObjectSpaces; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using AgentService.Platform; namespace AgentService.Agent.Knowledge { /// /// Enum PersistenceMode. Defines the different modes used to persist Knowledge objects. /// public enum PersistenceMode { /// /// Knowledge is never persisted /// NotPersistent, /// /// Knowledge is persisted when the agent is persisted or manually /// Persistent, /// /// Knowledge is auto persisted on every update /// StrongPersistent } /// /// Delegate KnowledgeChangedDelegate. Handler for the OnPersistKnowledge event launched /// by the Knowledge class. /// internal delegate void KnowledgeChangedDelegate(object sender); /// /// Class Knowledge. A knowledge is a container of CLI types that are shared /// among the behaviours of an agent and that are persisted against a stream. /// The class is abstract provides a common base for all knowledge objects. /// [Serializable()] public abstract class Knowledge:ISerializable { #region Members and Properties /// /// Collection of items that are contained in the knowledge /// private System.Collections.Hashtable items; /// /// Collection of temporary items used to access knowledge within an exclusive context /// private System.Collections.Hashtable tempItems; /// /// Knowledge string Identifier /// string name; /// /// Gets the name of the knowledge /// public string Name { get { return name; } } /// /// Name of the Agent that owns the knowledge /// internal string ownerName; /// /// locked flag /// private bool isLocked; /// /// Gets the locked flag /// public bool IsLocked { get { return this.isLocked; } } /// /// Persistence mode /// private PersistenceMode pMode; /// /// Gets the persistence mode /// public PersistenceMode Mode { get { return this.pMode; } } /// /// Event OnPersisrtKnowledge. Thrown by the knowledge object, when its internal items /// change and the persistence mode is StrongPersistent /// internal event KnowledgeChangedDelegate OnPersistKnowledge; /// /// Reference to the behaviour instance that is locking the /// knowledge instance /// private Behaviour.Behaviour lockingBehaviour; #endregion # region Constructors /// /// Constructs a Knowledge object with no items, /// persistence mode is set to Persistent /// public Knowledge() { this.name = null; this.items = new System.Collections.Hashtable(); this.pMode = PersistenceMode.Persistent; this.lockingBehaviour = null; } /// /// Costructs a Knowledge object with the given knowledge name and persistence mode /// /// name of the knowledge object /// persistence mode public Knowledge(string knowledgeName, PersistenceMode pMode) { this.name = knowledgeName; this.items = new System.Collections.Hashtable(); this.pMode = pMode; this.lockingBehaviour = null; } /// /// Costructs a Knowledge object with a given knowledge persistent object and agent owner name /// /// persistent version of the knowledge public Knowledge(KnowledgePersistent kp, string ownerName) { this.name = kp.Name; this.items = kp.Items; this.pMode = kp.Mode; this.lockingBehaviour = null; this.ownerName = ownerName; } /// /// Deserialization constructor /// /// SerializationInfo to populate with data /// contextual information about the source or destination of the serialization public Knowledge(SerializationInfo info, StreamingContext context) { this.name = info.GetValue("name", typeof(string)) as string; this.items = info.GetValue("items", typeof(System.Collections.Hashtable)) as System.Collections.Hashtable; this.pMode = (PersistenceMode) info.GetValue("pMode", typeof(PersistenceMode)); } /// /// Serialize the knowledge onto a sreaming context /// /// SerializationInfo to populate with data /// contextual information about the source or destination of the serialization public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("name", this.name); info.AddValue("items", this.items); info.AddValue("pMode", this.pMode); } #endregion # region Synch Methods /// /// Tests if a Behaviour locks the Knowledge /// /// candidate Behaviour /// True if the Knowledge is locked by the given Behaviour public bool IsLockedBy(Behaviour.Behaviour lockBehaviour) { lock(this) { if( this.lockingBehaviour != null ) { return this.lockingBehaviour.Name.Equals(lockBehaviour.Name); } return false; } } /// /// Locks the Knowledge for the given Behaviour /// /// locking Behaviour internal void Lock(AgentService.Agent.Behaviour.Behaviour lockingBehaviour) { while(true) { lock(this) { if(!this.isLocked) { this.isLocked = true; this.lockingBehaviour = lockingBehaviour; this.tempItems = this.cloneItems(this.items); return; } } System.Threading.Thread.Sleep(100); } //Is the exception necessary? //throw new KnowledgeLockedException(this.Name); } /// /// Releases a knowledge previously locked. Throws KnowledgeUnlockedException if the knowledge was not locked. /// internal void UnLock() { lock(this) { if(this.isLocked) { this.isLocked = false; this.lockingBehaviour = null; this.tempItems = null; return; } } // TODO: Log knowledge release // throw new KnowledgeUnlockedException(this.Name); } #endregion # region Knowledge Item Management /// /// Adds new item to knowledge /// /// string key used to access the knowldge item /// type of the item /// reference to object that need to be stored whithin the knowledge // TODO: lo facciamo attraverso un knowledgefactorycontext passato al costruttore (solito gioco dell'active) protected void AddItem(string itemIdentifier, System.Type typeName, object reference)//string assemblyName,string objType,object[] args) { if (this.items.Contains(itemIdentifier)) { throw new KnowledgeItemAlreadyExistException(itemIdentifier,this.name); } this.items.Add(itemIdentifier, new KnowledgeItem(itemIdentifier,typeName,reference)); } /// /// Retrieves all the item's identifiers /// /// The list of item's identifiers public string[] GetItemsId() { lock(this) { string[] itemIds = new string[this.items.Count]; this.items.Keys.CopyTo(itemIds,0); return itemIds; } } /// /// Updates changes in the knowledge items /// /// public void Update(Behaviour.Behaviour lockBehaviour) { lock(this) { if(this.IsLockedBy(lockBehaviour)) { this.items = this.cloneItems(this.tempItems); if(this.Mode == PersistenceMode.StrongPersistent) { this.OnPersistKnowledge(this); } } else { // MOD: 7/6/2006 Christian Vecchiola - added throw exception throw new KnowledgeUnlockedException(this.name); } } } /// /// Knowledge indexer. Gets the instance associated to the given item identifier /// public object this[string itemId, Behaviour.Behaviour behaviour] { get { if(this.lockingBehaviour == behaviour) { KnowledgeItem item = this.tempItems[itemId] as KnowledgeItem; return item.instance; } // MOD: 7/6/2006 Christian Vecchiola - added throw exception throw new KnowledgeAccessException(this.name); } set { if (this.lockingBehaviour == behaviour) { KnowledgeItem item = this.tempItems[itemId] as KnowledgeItem; item.instance = value; } else { // MOD: 7/6/2006 Christian Vecchiola - added throw exception throw new KnowledgeAccessException(this.name); } } } /// /// Clones the given hashtable /// /// hashtable "source" object /// cloned hashtable private System.Collections.Hashtable cloneItems(System.Collections.Hashtable original) { System.IO.MemoryStream ms = new System.IO.MemoryStream(); BinaryFormatter bf = new BinaryFormatter(); bf.Binder = new AgentService.Platform.ASBinder(); bf.Serialize(ms,original); ms.Position = 0; System.Collections.Hashtable copy = bf.Deserialize(ms) as System.Collections.Hashtable; return copy; /* MOD: 7/6/200 Christian Vecchiola switched to cloned items return original; */ } # endregion #region Persistence /// /// Gets the persistent version of the knowledge /// /// persistent version of the knowledge public KnowledgePersistent GetPersistent() { KnowledgePersistent persistent = new KnowledgePersistent(this.name, this.items); persistent.Mode = this.pMode; persistent.TypeName = this.GetType().FullName; return persistent; } /// /// Resumes a knowledge object from a persisted version /// /// persisted version of the knowledge public void ResumeFrom(KnowledgePersistent kp) { this.items = kp.Items; this.name = kp.Name; this.pMode = kp.Mode; } #endregion } }