/*********************************************************************/
/* */
/* 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.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using AgentService.Agent.Runtime;
using AgentService.Platform.AMS;
using AgentService.Platform.MTS;
using System.Collections.Specialized;
namespace AgentService.Platform.DF
{
///
/// Class DefualtYellowPagesServer. Defualt implementation of the IYelloPagesServer interface
///
public class DefaultYellowPagesServer : AgentService.Agent.Runtime.IYellowPagesServer
{
///
/// Collections of DFAgentDescription objects.
///
private DFAgentDescriptionCollection descriptions;
///
/// The AID of the df
///
private AID df;
///
/// The platform that hosts the DF
///
private IPlatform platform;
///
/// This hashtable contains AutoResetEvent objects, one for each transaction with the DF.
///
private Hashtable incomingMessageHashtable;
///
/// This hashtable contains the DFAgentDescription resulting from transactions from remote dfs
///
private Hashtable remoteAgentDescriptionHashtable;
///
/// The file containing the list of federated platforms
///
private String federationConfigFile;
///
/// Constructs a DefualtYellowPagesServer bound to the given collection
/// of DFAgentDescriptions
///
/// collection of DFAgentDescription object
public DefaultYellowPagesServer(DFAgentDescriptionCollection descriptions, AID df, IPlatform platform)
{
this.descriptions = descriptions;
this.platform = platform;
this.df = df;
this.CreateDFQueue();
this.ReadConfigFile();
this.remoteAgentDescriptionHashtable = new Hashtable();
this.incomingMessageHashtable = new Hashtable();
}
#region IYellowPagesServer Members
///
/// Searches for all agents that offers the given service description by checking at the service name
///
/// service description
/// array of DFAgentDescription objects that belonging to agentts that offer the given service
public DFAgentDescription[] SearchAgent(ServiceDescription sd)
{
// TODO: Add DefaultYellowPages.SearchAgent implementation
return this.doSearchAgent(sd, ServiceComparison.ByName, -1);
}
///
/// Searches for all agents that offers the given service description by using the given comparison flags
///
/// service description
/// flags that specify the field to compare
/// array of DFAgentDescription objects that belonging to agentts that offer the given service
public DFAgentDescription[] SearchAgent(ServiceDescription sd, ServiceComparison flags)
{
return this.doSearchAgent(sd, flags, -1);
}
///
/// Searches for all agents that offers the given service description by using the given comparison flags
///
/// service description
/// flags that specify the field to compare
/// number of max results to retrieve (-1 for unlimited)
/// array of DFAgentDescription objects that belonging to agentts that offer the given service
private DFAgentDescription[] doSearchAgent(ServiceDescription sd, ServiceComparison flags, int maxResult)
{
if (maxResult == 0)
return new DFAgentDescription[0];
lock (this.descriptions)
{
int count = 0;
DFAgentDescriptionCollection temp = new DFAgentDescriptionCollection();
for (int ndx = 0; ndx < this.descriptions.Count; ndx++)
{
DFAgentDescription desc = this.descriptions[ndx];
if (desc.Services.Count > 0)
{
for (int sdx = 0; sdx < desc.Services.Count; sdx++)
{
ServiceDescription servDesc = desc.Services[sdx];
if (servDesc.Match(sd, flags) == true)
{
count++;
temp.Add(desc);
if (count == maxResult)
break;
}
}
}
}
if (temp.Count > 0)
{
DFAgentDescription[] found = new DFAgentDescription[temp.Count];
temp.CopyTo(found, 0);
return found;
}
return new DFAgentDescription[0];
}
}
///
/// Searches for all the agents that offer the given service by using the given search constraint
///
/// service description
/// search constraint
/// array of DFAgentDescription that match the search
public DFAgentDescription[] SearchAgent(ServiceDescription sd, SearchConstraints constraint)
{
switch (constraint.Method)
{
case SearchMethod.SamePlatform:
{
return this.doSearchAgent(sd, ServiceComparison.ByName, constraint.MaxResults);
}
case SearchMethod.OtherPlatform:
{
if (constraint.MaxDepth < 1)
{
return new DFAgentDescription[0];
}
else
{
SearchConstraints constr = new SearchConstraints(constraint.MaxDepth, constraint.MaxResults, SearchMethod.Global);
return this.RemoveDuplicates(this.ContactFederatedPlatforms(sd, constr));
}
}
case SearchMethod.Global:
{
DFAgentDescription[] res1 = this.doSearchAgent(sd, ServiceComparison.ByName, constraint.MaxResults);
if (constraint.MaxDepth < 1)
{
return this.RemoveDuplicates(res1);
}
DFAgentDescription[] res2 = this.ContactFederatedPlatforms(sd, constraint);
DFAgentDescription[] result = new DFAgentDescription[res1.Length + res2.Length];
res1.CopyTo(result, 0);
res2.CopyTo(result, res1.Length);
return this.RemoveDuplicates(result);
}
}
return null;
}
///
/// Searches for all the agents that offer the given service by using the given search constraint
///
/// service description
/// service comparison flags
/// search constraint
/// array of DFAgentDescription that match the search
public DFAgentDescription[] SearchAgent(ServiceDescription sd, ServiceComparison flags, SearchConstraints constraint)
{
switch (constraint.Method)
{
case SearchMethod.SamePlatform:
{
return this.doSearchAgent(sd, flags, constraint.MaxResults);
}
case SearchMethod.OtherPlatform:
{
if (constraint.MaxDepth < 1)
{
return new DFAgentDescription[0];
}
else
{
SearchConstraints constr = new SearchConstraints(constraint.MaxDepth, constraint.MaxResults, SearchMethod.Global);
return this.RemoveDuplicates(this.ContactFederatedPlatforms(sd, constr, flags));
}
}
case SearchMethod.Global:
{
DFAgentDescription[] res1 = this.doSearchAgent(sd, flags, constraint.MaxResults);
if (constraint.MaxDepth < 1)
{
return this.RemoveDuplicates(res1);
}
DFAgentDescription[] res2 = this.ContactFederatedPlatforms(sd, constraint, flags);
DFAgentDescription[] result = new DFAgentDescription[res1.Length + res2.Length];
res1.CopyTo(result, 0);
res2.CopyTo(result, res1.Length);
return this.RemoveDuplicates(result);
}
}
return null;
}
///
/// Removes duplicated records from the resulting array.
///
/// The agent array to reduce
/// Returns the reduced array
private DFAgentDescription[] RemoveDuplicates(DFAgentDescription[] agents)
{
Collection items = new Collection();
List list = new List();
foreach (DFAgentDescription item in agents)
{
if(!this.Contains(items, item))
{
list.Add(item);
items.Add(item);
}
}
return list.ToArray();
}
///
/// Check if a DFAgentDescription is already contained in an array.
///
/// The array of DFAgentDescription
/// The DFAgentDescription to check.
/// Returns true if the given DFAgentDescription is already contained in the array
private bool Contains(Collection agents, DFAgentDescription agent)
{
//I've implemented this method because the list.Contains() method apparently doesn't work with DFAgentDescription...
foreach (DFAgentDescription item in agents)
{
if (item.Aid.Name == agent.Aid.Name && item.Aid.HapName == agent.Aid.HapName)
{
return true;
}
}
return false;
}
///
/// This method contacts the DFs of federated platforms.
///
/// The searched service description
/// The search constraints
/// The flags.
/// An array of DFAgentDescription coming from remote dfs
private DFAgentDescription[] ContactFederatedPlatforms(ServiceDescription sd, SearchConstraints constraint, ServiceComparison flags)
{
DFBodyMessage body = new DFBodyMessage();
body.SearchAgent(sd, flags, constraint);
return this.SendMessageToRemoteDFs(body);
}
///
/// This method contacts the DFs of federated platforms.
///
/// The searched service description
/// The search constraints
/// An array of DFAgentDescription coming from remote dfs
private DFAgentDescription[] ContactFederatedPlatforms(ServiceDescription sd, SearchConstraints constraint)
{
DFBodyMessage body = new DFBodyMessage();
body.SearchAgent(sd, constraint);
return this.SendMessageToRemoteDFs(body);
}
///
/// Sends system messages to remote DFs.
///
/// The body of the system message
/// Returns an array of DFAgentDescription coming from remote dfs
private DFAgentDescription[] SendMessageToRemoteDFs(DFBodyMessage body)
{
DFAgentDescription[] descr = new DFAgentDescription[0];
Federation fed = this.DeSerializeFederationData();
this.incomingMessageHashtable.Add(body.TransactionID, new AutoResetEvent(false));
this.remoteAgentDescriptionHashtable.Add(body.TransactionID, new Collection());
int sentMessages = 0;
//Console.WriteLine("---->DF1");
foreach (RemotePlatform remotePlatform in fed.Platforms)
{
//Console.WriteLine("---->" + remotePlatform.Name);
if (remotePlatform.TypeOfPlatform == PlatformType.Platform)
{
//Console.WriteLine("---->DF2");
AID dfAID = new AID("df", remotePlatform.Name);
AgentMessage msg = new AgentMessage();
msg.Envelope.From = this.df;
msg.Envelope.To.Add(dfAID);
msg.Body.Add("content", body);
if (this.platform.Messaging.SendMessage(msg))
{
sentMessages++;
}
}
}
int delay = 10000 * body.SearchConstraints.MaxDepth; //I've set this parameter (for the the above WaitOne())
//depending on the max depth of the search.
for (int i = 0; i < sentMessages; i++)
{
((AutoResetEvent)this.incomingMessageHashtable[body.TransactionID]).WaitOne(delay, true);
if (((Collection)this.remoteAgentDescriptionHashtable[body.TransactionID]).Count != 0)
{
DFAgentDescription[] result = new DFAgentDescription[descr.Length + ((Collection)this.remoteAgentDescriptionHashtable[body.TransactionID])[0].Length];
descr.CopyTo(result, 0);
((Collection)this.remoteAgentDescriptionHashtable[body.TransactionID])[0].CopyTo(result, descr.Length);
descr = result;
((Collection)this.remoteAgentDescriptionHashtable[body.TransactionID]).RemoveAt(0);
}
}
this.incomingMessageHashtable.Remove(body.TransactionID);
this.remoteAgentDescriptionHashtable.Remove(body.TransactionID);
return descr;
}
///
/// Deserialize the federation file
///
/// Returns a federation object containing the list of federated platform
private Federation DeSerializeFederationData()
{
string configFile = this.platform.Configuration.BaseDirPath+"\\" + this.federationConfigFile;
//if (System.IO.File.Exists(this.federationConfigFile) == true)
if (System.IO.File.Exists(configFile) == true)
{
XmlSerializer serializer = new XmlSerializer(typeof(Federation));
XmlReader reader = null;
try
{
//reader = XmlReader.Create(this.federationConfigFile);
reader = XmlReader.Create(configFile);
return (Federation)serializer.Deserialize(reader);
}
finally
{
//Console.WriteLine("ERRORE");
if (reader != null)
{
reader.Close();
}
/*else
{
Console.WriteLine("ERRORE");
}*/
}
}
return new Federation();
}
///
/// Reads the message module configuration file, in order to retrieve the path of the federation configuration file.
///
/// Returns true if the configuration file has been succesfully read
protected bool ReadConfigFile()
{
string cfile = System.IO.Path.Combine(this.platform.Configuration.BaseDirPath, this.platform.Configuration.CoreModulesConfPath);
cfile = System.IO.Path.Combine(cfile, this.platform.Configuration.MessagingModule.ConfigFile);
bool bReadOk = true;
using (StreamReader sr = new StreamReader(cfile))
{
string line = string.Empty;
while ((line = sr.ReadLine()) != null)
{
if ((line.StartsWith("#") == false) && (line != string.Empty))
{
int ndxSeparator = line.IndexOf(' ');
string property = line.Substring(0, ndxSeparator).Trim();
string value = line.Substring(ndxSeparator).Trim();
switch (property)
{
case "FederationConfig": this.federationConfigFile = value; break;
}
}
}
}
return bReadOk;
}
///
/// Registers an agent with the directory facilitator service
///
/// description of the services promoted by the agent
public void Register(DFAgentDescription description)
{
if (description != null)
{
if (this.descriptions.Contains(description) == false)
{
this.descriptions.Add(description);
}
}
}
///
/// Modifies the agent description previously registered with the directory facilitator service
///
/// description of the services promoted by the agent
public void Edit(DFAgentDescription description)
{
if (description != null)
{
int ndx = this.descriptions.IndexOf(description.Aid);
if (ndx > 1)
{
this.descriptions[ndx] = description;
}
}
}
///
/// Registers an agent with the directory facilitator service
///
/// identifier of the agents whoes description has to be removed
public void Deregister(AID aid)
{
this.descriptions.Remove(aid);
}
///
/// Creates the DF agent queue at the message module.
///
private void CreateDFQueue()
{
this.platform.Messaging.CreateAgentQueue(this.df);
if (this.platform.Messaging is AgentService.Platform.Modules.IImprovedMessagingModule)
{
((AgentService.Platform.Modules.IImprovedMessagingModule)this.platform.Messaging).RegisterToIncomingMessage(this.ReplyToRemoteDF, this.df);
}
}
///
/// This method is called when the message module raises the incoming message event.
///
///
///
public void ReplyToRemoteDF(object sender, EventArgs args)
{
AgentMessage msg = this.platform.Messaging.ReceiveMessage(this.df);
if (msg != null)
{
DFBodyMessage body = msg.Body["content"] as DFBodyMessage;
if (body != null)
{
if (body.MessageType == DFMessageType.Query)
{
DFAgentDescription[] descr = new DFAgentDescription[0];
SearchConstraints constr = new SearchConstraints(body.SearchConstraints.MaxDepth - 1, body.SearchConstraints.MaxResults, body.SearchConstraints.Method);
if (body.SearchType == SearchAgentType.ServiceAndConstraints)
{
descr = this.SearchAgent(body.ServiceDescription, constr);
}
else
{
descr = this.SearchAgent(body.ServiceDescription, body.ServiceComparison, constr);
}
DFBodyMessage replyBody = new DFBodyMessage();
replyBody.setReply(descr, body.TransactionID);
AgentMessage reply = msg.Reply(false);
reply.Body.Add("content", replyBody);
this.platform.Messaging.SendMessage(reply);
}
else
{
((Collection)this.remoteAgentDescriptionHashtable[body.TransactionID]).Add(body.AgentDescriptions);
((AutoResetEvent)this.incomingMessageHashtable[body.TransactionID]).Set();
}
}
else
{
throw new Exception("The DF is unable to manage the received message");
}
}
}
/*private bool Contains(RemotePlatform pl, StringCollection addresses)
{
foreach (string address in addresses)
{
string s = address.Split('@')[0];
if (pl.Name.Equals(s)) return true;
}
return false;
}*/
#endregion
}
}