/// <summary> /// Adds a remote application to communication layer. /// </summary> /// <param name="application">Remote application to add</param> public void AddRemoteApplication(NGRIDRemoteApplication application) { lock (_remoteApplications) { if (!_remoteApplications.ContainsKey(application.ApplicationId)) { _remoteApplications.Add(application.ApplicationId, application); } } }
/// <summary> /// Removes a remote application from communication layer. /// </summary> /// <param name="application">Remote application to remove</param> public void RemoveRemoteApplication(NGRIDRemoteApplication application) { lock (_remoteApplications) { if (_remoteApplications.ContainsKey(application.ApplicationId)) { if (application.ConnectedCommunicatorCount > 0) { throw new NGRIDException("Remote application can not be removed. It has " + application.ConnectedCommunicatorCount + " communicators connected."); } _remoteApplications.Remove(application.ApplicationId); } } }
/// <summary> /// Processes NGRIDRegisterMessage objects. /// </summary> /// <param name="communicator">Sender communicator of message</param> /// <param name="message">Message</param> private void ProcessRegisterMessage(ICommunicator communicator, NGRIDRegisterMessage message) { //Set the communicator properties communicator.CommunicationWay = message.CommunicationWay; NGRIDRemoteApplication remoteApplication = null; //Find remote application lock (_remoteApplications) { foreach (var app in _remoteApplications.Values) { if (app.Name == message.Name && message.CommunicatorType == app.CommunicatorType) { remoteApplication = app; break; } } } //If application is found... if (remoteApplication != null) { try { //Add communicator to communicator list of remote application remoteApplication.AddCommunicator(communicator); //Remove communicator from tempoary communicators list. RemoveFromCommunicators(communicator.ComminicatorId); //Send success message to remote application SendOperationResultMessage(communicator, true, communicator.ComminicatorId.ToString(), message.MessageId); } catch (Exception ex) { Logger.Warn(ex.Message, ex); //An error occured, send failed message to remote application SendOperationResultMessage(communicator, false, ex.Message, message.MessageId); communicator.Stop(false); } } else //application == null { //Stop communicator, because a remote application can not connect this server that is not defined in settings file SendOperationResultMessage(communicator, false, "No remote application found with name: " + message.Name, message.MessageId); communicator.Stop(false); } }
/// <summary> /// Removes a remote application from communication layer. /// </summary> /// <param name="application">Remote application to remove</param> public void RemoveRemoteApplication(NGRIDRemoteApplication application) { lock (_remoteApplications) { if (_remoteApplications.ContainsKey(application.ApplicationId)) { if(application.ConnectedCommunicatorCount > 0) { throw new NGRIDException("Remote application can not be removed. It has " + application.ConnectedCommunicatorCount + " communicators connected."); } _remoteApplications.Remove(application.ApplicationId); } } }
/// <summary> /// Constructor. /// </summary> /// <param name="remoteApplication">Reference to the NGRIDRemoteApplication object that is used with this MessageDeliverer</param> public MessageDeliverer(NGRIDRemoteApplication remoteApplication) { _remoteApplication = remoteApplication; _asynchronMessageControlTimer = new Timer(AsynchronMessageControlTimer_Elapsed, null, Timeout.Infinite, Timeout.Infinite); }
/// <summary> /// Adds message to destination's send queue. /// </summary> /// <param name="senderApplication">Sender application/server</param> /// <param name="senderCommunicator">Sender communicator</param> /// <param name="destApplication">Destination application/server</param> /// <param name="message">Message</param> private static void EnqueueMessage(NGRIDRemoteApplication senderApplication, ICommunicator senderCommunicator, NGRIDPersistentRemoteApplicationBase destApplication, NGRIDDataTransferMessage message) { destApplication.EnqueueMessage(message); SendOperationResultMessage(senderApplication, senderCommunicator, message, true, "Success."); }
/// <summary> /// To send a NGRIDOperationResultMessage to remote application's spesific communicator. /// </summary> /// <param name="senderApplication">Sender application/server</param> /// <param name="communicator">Communicator to send message</param> /// <param name="repliedMessage">Replied Message</param> /// <param name="success">Operation result</param> /// <param name="resultText">Details</param> private static void SendOperationResultMessage(NGRIDRemoteApplication senderApplication, ICommunicator communicator, NGRIDDataTransferMessage repliedMessage, bool success, string resultText) { try { if (success) { //Save MessageId of acknowledged message to do not receive same message again senderApplication.LastAcknowledgedMessageId = repliedMessage.MessageId; } senderApplication.SendMessage(new NGRIDOperationResultMessage { RepliedMessageId = repliedMessage.MessageId, Success = success, ResultText = resultText }, communicator); } catch (Exception ex) { Logger.Warn(ex.Message, ex); } }
/// <summary> /// This method is called by ProcessDataTransferMessage when a message must be sent to a server /// that is not an adjacent of this server. Message is forwarded to next server. /// </summary> /// <param name="senderApplication">Sender application/server</param> /// <param name="senderCommunicator">Sender communicator</param> /// <param name="message">Message</param> private void SendToNextServer(NGRIDRemoteApplication senderApplication, ICommunicator senderCommunicator, NGRIDDataTransferMessage message) { //If there is a path from this server to destination server... if (_serverGraph.ThisServerNode.BestPathsToServers.ContainsKey(message.DestinationServerName)) { //Find best path to destination server var bestPath = _serverGraph.ThisServerNode.BestPathsToServers[message.DestinationServerName]; //If path is regular (a path must consist of 2 nodes at least)... if (bestPath.Count > 1) { //Next server var nextServerName = bestPath[1].Name; /* On one of these conditions, message is stored: * - TransmitRule = StoreAndForward * - (TransmitRule = StoreOnSource OR StoreOnEndPoints) AND (This server is the source server) */ if (message.TransmitRule == MessageTransmitRules.StoreAndForward || message.TransmitRule == MessageTransmitRules.NonPersistent) { EnqueueMessage( senderApplication, senderCommunicator, _serverGraph.AdjacentServers[nextServerName], message ); } /* Else, message is not stored in these conditions: * - TransmitRule = DirectlySend OR StoreOnDestination (this server can not be destination because message is being sent to another server right now) * - All Other conditions */ else { SendMessageDirectly( senderApplication, senderCommunicator, _serverGraph.AdjacentServers[nextServerName], message ); } } //Server graph may be wrong (this is just for checking case, normally this situation must not become) else { SendOperationResultMessage(senderApplication, senderCommunicator, message, false, "Server graph is wrong."); } } //No path from this server to destination server else { SendOperationResultMessage(senderApplication, senderCommunicator, message, false, "There is no path from this server to destination."); } }
/// <summary> /// Sends message directly to application (not stores) and waits ACK. /// This method adds message to queue by NGRIDPersistentRemoteApplicationBase.AddMessageToHeadOfQueue method /// and waits a signal/pulse from RemoteApplication_MessageReceived method to get ACK/Reject. /// </summary> /// <param name="senderApplication">Sender application/server</param> /// <param name="senderCommunicator">Sender communicator</param> /// <param name="destApplication">Destination application/server</param> /// <param name="message">Message</param> private void SendMessageDirectly(NGRIDRemoteApplication senderApplication, ICommunicator senderCommunicator, NGRIDPersistentRemoteApplicationBase destApplication, NGRIDDataTransferMessage message) { //Create a WaitingMessage to wait and get ACK/Reject message and add it to waiting messages var waitingMessage = new WaitingMessage(); lock (_waitingMessages) { _waitingMessages[message.MessageId] = waitingMessage; } try { //Add message to head of queue of remote application destApplication.AddMessageToHeadOfQueue(message); //Wait until thread is signalled by another thread to get response (Signalled by RemoteApplication_MessageReceived method) waitingMessage.WaitEvent.WaitOne((int) (_settings.MessageResponseTimeout*1.2)); //Evaluate response if (waitingMessage.ResponseMessage.Success) { SendOperationResultMessage(senderApplication, senderCommunicator, message, true, "Success."); } else { SendOperationResultMessage(senderApplication, senderCommunicator, message, false, "Message is not acknowledged. Reason: " + waitingMessage.ResponseMessage.ResultText); } } finally { //Remove message from waiting messages lock (_waitingMessages) { _waitingMessages.Remove(message.MessageId); } } }
/// <summary> /// This method is called by ProcessDataTransferMessage when a message must be sent to an adjacent server of this server. /// </summary> /// <param name="senderApplication">Sender application/server</param> /// <param name="senderCommunicator">Sender communicator</param> /// <param name="message">Message</param> private void SentToAdjacentServer(NGRIDRemoteApplication senderApplication, ICommunicator senderCommunicator, NGRIDDataTransferMessage message) { /* On one of these conditions, message is stored: * - TransmitRule = StoreAndForward * - (TransmitRule = StoreOnSource OR StoreOnEndPoints) AND (This server is the source server) */ if (message.TransmitRule == MessageTransmitRules.StoreAndForward || message.TransmitRule == MessageTransmitRules.NonPersistent) { EnqueueMessage( senderApplication, senderCommunicator, _serverGraph.AdjacentServers[message.DestinationServerName], message ); } /* Else, message is not stored in these conditions: * - TransmitRule = DirectlySend OR StoreOnDestination (this server can not be destination because message is being sent to another server right now) * - All Other conditions */ else { SendMessageDirectly( senderApplication, senderCommunicator, _serverGraph.AdjacentServers[message.DestinationServerName], message ); } }
/// <summary> /// This method is called by ProcessDataTransferMessage when a message must be sent to a aclient application /// that is running on this server. /// </summary> /// <param name="senderApplication">Sender application/server</param> /// <param name="senderCommunicator">Sender communicator</param> /// <param name="message">Message</param> private void SentToClientApplication(NGRIDRemoteApplication senderApplication, ICommunicator senderCommunicator, NGRIDDataTransferMessage message) { NGRIDClientApplication destinationApplication = null; //If application exists on this server, get it lock (_clientApplicationList.Applications) { if (_clientApplicationList.Applications.ContainsKey(message.DestinationApplicationName)) { destinationApplication = _clientApplicationList.Applications[message.DestinationApplicationName]; } } //If application doesn't exist on this server... if (destinationApplication == null) { SendOperationResultMessage(senderApplication, senderCommunicator, message, false, "Application does not exists on this server (" + _settings.ThisServerName + ")."); return; } //Send message according TransmitRule switch (message.TransmitRule) { case MessageTransmitRules.DirectlySend: SendMessageDirectly( senderApplication, senderCommunicator, destinationApplication, message ); break; default: // case MessageTransmitRules.StoreAndForward: // case MessageTransmitRules.NonPersistent: EnqueueMessage( senderApplication, senderCommunicator, destinationApplication, message ); break; } }
/// <summary> /// Checks a NGRIDDataTransferMessage and fills it's empty fields by default values. /// </summary> /// <param name="dataTransferMessage">Message</param> /// <param name="senderApplication">Sender application</param> /// <param name="communicator">Sender communicator of application</param> private void FillEmptyMessageFields(NGRIDDataTransferMessage dataTransferMessage, NGRIDRemoteApplication senderApplication, ICommunicator communicator) { //Default SourceApplicationName: Name of the sender application. if (string.IsNullOrEmpty(dataTransferMessage.SourceApplicationName)) { dataTransferMessage.SourceApplicationName = senderApplication.Name; } //Default SourceServerName: Name of this server. if (string.IsNullOrEmpty(dataTransferMessage.SourceServerName)) { dataTransferMessage.SourceServerName = _settings.ThisServerName; } //Default DestinationApplicationName: Name of the sender application. if (string.IsNullOrEmpty(dataTransferMessage.DestinationApplicationName)) { dataTransferMessage.DestinationApplicationName = senderApplication.Name; } //Default DestinationServerName: Name of this server. if (string.IsNullOrEmpty(dataTransferMessage.DestinationServerName)) { dataTransferMessage.DestinationServerName = _settings.ThisServerName; } if (dataTransferMessage.SourceServerName == _settings.ThisServerName) { //Sender communicator id is being set. dataTransferMessage.SourceCommunicatorId = communicator.ComminicatorId; } }
/// <summary> /// This method is used to process a NGRIDDataTransferMessage that is gotten from a ngrid server or client application. /// Message is sent to destination or next server in one of these three conditions: /// - Destination server is this server and application exists on this server /// - Destination server is an adjacent server of this server /// - Destination server in server graph and there is a path from this server to destination server /// </summary> /// <param name="senderApplication">Sender application/server</param> /// <param name="senderCommunicator">Sender communicator</param> /// <param name="message">Message</param> private void ProcessDataTransferMessage(NGRIDRemoteApplication senderApplication, ICommunicator senderCommunicator, NGRIDDataTransferMessage message) { //Check for duplicate messages if (senderApplication.LastAcknowledgedMessageId == message.MessageId) { SendOperationResultMessage(senderApplication, senderCommunicator, message, true, "Duplicate message."); return; } try { AddThisServerToPassedServerList(message); FillEmptyMessageFields(message, senderApplication, senderCommunicator); _routingTable.ApplyRouting(message); //If Destination server is this server then deliver message to the destination application if (message.DestinationServerName.Equals(_settings.ThisServerName, StringComparison.OrdinalIgnoreCase)) { SentToClientApplication(senderApplication, senderCommunicator, message); } //Else, if destination server is an adjacent of this server (so they can communicate directly) else if (_serverGraph.AdjacentServers.ContainsKey(message.DestinationServerName)) { SentToAdjacentServer(senderApplication, senderCommunicator, message); } //Else, if destination server is not adjacent but in server graph (so, send message to next server) else if (_serverGraph.ServerNodes.ContainsKey(message.DestinationServerName)) { SendToNextServer(senderApplication, senderCommunicator, message); } else { //return error to sender SendOperationResultMessage(senderApplication, senderCommunicator, message, false, "Destination does not exists."); } } catch (Exception ex) { SendOperationResultMessage(senderApplication, senderCommunicator, message, false, ex.Message); } }