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