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