/// <summary>
        /// Sets the destination of a message according to distribution strategy.
        /// </summary>
        /// <param name="message">Message to set it's destination</param>
        public void SetDestination(MDSDataTransferMessage message)
        {
            //Return, if no destination exists
            if (_totalCount == 0 || RoutingRule.Destinations.Length <= 0)
            {
                return;
            }

            //Find next destination and set
            var currentTotal = 0;
            foreach (var destination in RoutingRule.Destinations)
            {
                currentTotal += destination.RouteFactor;
                if (_currentNumber < currentTotal)
                {
                    SetMessageDestination(message, destination);
                    break;
                }
            }

            //Increase _currentNumber
            if ((++_currentNumber) >= _totalCount)
            {
                _currentNumber = 0;
            }
        }
示例#2
0
 /// <summary>
 /// Checks all routing rules and apply proper rule to the message
 /// </summary>
 /// <param name="message">Message to apply routing</param>
 public void ApplyRouting(MDSDataTransferMessage message)
 {
     if (Rules.Any(rule => rule.ApplyRule(message)))
     {
         return;
     }
 }
示例#3
0
 /// <summary>
 /// Creates a MDSMessageRecord object using a MDSDataTransferMessage.
 /// </summary>
 /// <param name="message">Message object</param>
 public MDSMessageRecord(MDSDataTransferMessage message)
 {
     Message = message;
     MessageId = message.MessageId;
     DestServer = message.DestinationServerName;
     DestApplication = message.DestinationApplicationName;
     RecordDate = DateTime.Now;
 }
示例#4
0
        /// <summary>
        /// Checks if a message matches with this filter.
        /// </summary>
        /// <param name="message">Message to check</param>
        /// <returns>True, if message matches with this rule</returns>
        public bool Matches(MDSDataTransferMessage message)
        {
            if ((string.IsNullOrEmpty(SourceServer) || SourceServer == message.SourceServerName) &&
                (string.IsNullOrEmpty(SourceApplication) || SourceApplication == message.SourceApplicationName) &&
                (string.IsNullOrEmpty(DestinationServer) || DestinationServer == message.DestinationServerName) &&
                (string.IsNullOrEmpty(DestinationApplication) || DestinationApplication == message.DestinationApplicationName) &&
                (string.IsNullOrEmpty(TransmitRule) || TransmitRule == message.TransmitRule.ToString()))
            {
                return true;
            }

            return false;
        }
示例#5
0
        /// <summary>
        /// Tries to appliy this rule to a data transfer message.
        /// </summary>
        /// <param name="message">Message to apply rule</param>
        /// <returns>True, if rule applied</returns>
        public bool ApplyRule(MDSDataTransferMessage message)
        {
            for (var i = 0; i < Filters.Length; i++)
            {
                if (Filters[i].Matches(message))
                {
                    DistributionStrategy.SetDestination(message);
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Sets the destination of a message.
        /// </summary>
        /// <param name="message">Message to set it's destination</param>
        /// <param name="destination">Destination to set to message</param>
        protected static void SetMessageDestination(MDSDataTransferMessage message, RoutingDestination destination)
        {
            //Sets destination server
            if (!string.IsNullOrEmpty(destination.Server))
            {
                message.DestinationServerName = destination.Server.Equals("this", StringComparison.OrdinalIgnoreCase)
                                                    ? MDSSettings.Instance.ThisServerName
                                                    : destination.Server;
            }

            //Sets destination application
            if (!string.IsNullOrEmpty(destination.Application))
            {
                message.DestinationApplicationName = destination.Application;
            }
        }
示例#7
0
        /// <summary>
        /// Sets the destination of a message according to distribution strategy.
        /// </summary>
        /// <param name="message">Message to set it's destination</param>
        public void SetDestination(MDSDataTransferMessage message)
        {
            //Return, if no destination exists
            if (_maxCount == 0 || RoutingRule.Destinations.Length <= 0)
            {
                return;
            }

            //Create a random number
            var randomNumber = _rnd.Next(_maxCount);

            //Find destination according to random number and set the destination.
            var currentTotal = 0;
            foreach (var destination in RoutingRule.Destinations)
            {
                currentTotal += destination.RouteFactor;
                if (randomNumber < currentTotal)
                {
                    SetMessageDestination(message, destination);
                    return;
                }
            }
        }
        /// <summary>
        /// This method is used to process a MDSDataTransferMessage that is gotten from a mds 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(MDSRemoteApplication senderApplication, ICommunicator senderCommunicator, MDSDataTransferMessage 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);
            }
        }
示例#9
0
 /// <summary>
 /// Finds Next server for a message.
 /// </summary>
 /// <returns>Next server</returns>
 protected override string GetNextServerForMessage(MDSDataTransferMessage message)
 {
     //Next server is this MDSAdjacentServer because message is being sent to that now.
     return Name;
 }
示例#10
0
 /// <summary>
 /// This method is used to send a MDSDataTransferMessage to an available communicator of application.
 /// It just blocks caller thread until a communicator comes available and message is sent or until timeout,
 /// but receives result (ACK/Reject) message asynchronous. It sends result (ACK/Reject) message to OnResponseReceived() method.
 /// </summary>
 /// <param name="message">Message to send</param>
 /// <param name="timeOut">Timeout value to wait if all receivers are busy. Set 0 to do not use timeout.</param>
 public void SendDataMessage(MDSDataTransferMessage message, int timeOut)
 {
     _messageDeliverer.SendDataMessage(message, timeOut);
 }
示例#11
0
 /// <summary>
 /// Deserializes this message.
 /// </summary>
 /// <param name="deserializer">Deserializer used to deserialize objects</param>
 public override void Deserialize(IMDSDeserializer deserializer)
 {
     base.Deserialize(deserializer);
     Result  = deserializer.ReadObject(() => new MDSOperationResultMessage());
     Message = deserializer.ReadObject(() => new MDSDataTransferMessage());
 }
示例#12
0
        /// <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(MDSRemoteApplication senderApplication, ICommunicator senderCommunicator, MDSDataTransferMessage 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.");
            }
        }
示例#13
0
        /// <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(MDSRemoteApplication senderApplication, ICommunicator senderCommunicator, MDSDataTransferMessage message)
        {
            MDSClientApplication 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>
        /// This method is called when a MDSDataTransferMessage sent to this application.
        /// Stores message and adds to queue to send to remote application.
        /// </summary>
        /// <param name="message">Message</param>
        public void EnqueueMessage(MDSDataTransferMessage message)
        {
            //Create MDSMessageRecord from MDSDataTransferMessage to save message to database
            var messageRecord = new MDSMessageRecord(message) {NextServer = GetNextServerForMessage(message)};

            //Lock collection to be synchronized.
            lock (_waitingMessages)
            {
                if (message.TransmitRule == MessageTransmitRules.StoreAndForward)
                {
                    //Save message to database
                    StorageManager.StoreMessage(messageRecord);
                    /* If these conditions are true, then message also added to _waitingMessages 
                     * and message is sent to appliction from this queue instead of read again from database (for performance reasons):
                     * - _waitingMessages's message count is smaller than a maximum count (_waitingMessages.Count < MaxMessagesInQueue).
                     * - All messages in database is also in _waitingMessages (_biggestWaitingMessageIdInList >= _biggestWaitingMessageId) 
                     *   That means there is no message that is in database but not in _waitingMessages list.
                     */
                    if (_waitingMessages.Count < MaxMessagesInQueue &&
                        _biggestWaitingMessageIdInList >= _biggestWaitingMessageId)
                    {
                        //Add message to queue.
                        _waitingMessages.AddLast(new WaitingMessage(messageRecord));
                        //This message's Id is new biggest id on queue.
                        _biggestWaitingMessageIdInList = messageRecord.Id;
                    }

                    //This message's id is new biggest id in database, so update _biggestWaitingMessageId value
                    _biggestWaitingMessageId = messageRecord.Id;
                }
                else
                {
                    //Add message to queue.
                    _waitingMessages.AddFirst(new WaitingMessage(messageRecord));
                }

                //Pulse waiting thread that is in wait state because of no message to process.
                if (!_waitingForAnError)
                {
                    Monitor.PulseAll(_waitingMessages);
                }

                Logger.Debug("EnqueueMessage - WaitingMessages.Count = " + _waitingMessages.Count + ", Application = " + Name);
            }
        }
 /// <summary>
 /// Deserializes this message.
 /// </summary>
 /// <param name="deserializer">Deserializer used to deserialize objects</param>
 public override void Deserialize(IMDSDeserializer deserializer)
 {
     base.Deserialize(deserializer);
     Result = deserializer.ReadObject(() => new MDSOperationResultMessage());
     Message = deserializer.ReadObject(() => new MDSDataTransferMessage());
 }
示例#16
0
 /// <summary>
 /// Finds Next server for a message.
 /// </summary>
 /// <returns>Next server</returns>
 protected override string GetNextServerForMessage(MDSDataTransferMessage message)
 {
     //Next server and destination server is same (this server) because message is being delivered to application now.
     return message.DestinationServerName;
 }
        /// <summary>
        /// Makes web service call, receives result and raises MessageReceived event.
        /// </summary>
        /// <param name="message"></param>
        private void SendMessageToWebService(MDSDataTransferMessage message)
        {
            using (var appService = new MDSAppService())
            {
                appService.Url = _url;
                var responseMessageBytes = appService.ReceiveMDSMessage(MDSSerializationHelper.SerializeToByteArray(message));
                if (responseMessageBytes == null)
                {
                    throw new MDSException("Response byte array from web service call is null.");
                }

                var responseMessage = MDSSerializationHelper.DeserializeFromByteArray(() => new MDSDataTransferResponseMessage(), responseMessageBytes);
                if (responseMessage.Result != null)
                {
                    OnMessageReceived(responseMessage.Result);
                }

                if (responseMessage.Message != null)
                {
                    OnMessageReceived(responseMessage.Message);
                }
            }
        }
        /// <summary>
        /// This method is called when a MDSDataTransferMessage sent to this application.
        /// It does not store message, adds it as first item of sending queue.
        /// </summary>
        /// <param name="message">Message</param>
        public void AddMessageToHeadOfQueue(MDSDataTransferMessage message)
        {
            //Lock collection to be synchronized.
            lock (_waitingMessages)
            {
                //Add message to queue.
                _waitingMessages.AddFirst(
                    new WaitingMessage(
                        new MDSMessageRecord(message)
                            {
                                NextServer = GetNextServerForMessage(message),
                                Id = -1
                            }));

                //Pulse waiting thread that is in wait state because of no message to process.
                if (!_waitingForAnError)
                {
                    Monitor.PulseAll(_waitingMessages);
                }              

                Logger.Debug("AddMessageToHeadOfQueue - WaitingMessages.Count = " + _waitingMessages.Count + ", Application = " + Name);
            }
        }
示例#19
0
        /// <summary>
        /// Adds this server to the list of passed servers of message.
        /// </summary>
        /// <param name="message">Message object</param>
        private void AddThisServerToPassedServerList(MDSDataTransferMessage message)
        {
            //Create new transmit report for this server
            var transmitReport = new ServerTransmitReport
            {
                ArrivingTime = DateTime.Now,
                ServerName = _settings.ThisServerName
            };
            if (message.PassedServers == null)
            {
                //Create array
                message.PassedServers = new ServerTransmitReport[1];
            }
            else
            {
                //Create new array (that has item one more than original array)
                var newArray = new ServerTransmitReport[message.PassedServers.Length + 1];
                //Copy old items to new array
                if (message.PassedServers.Length > 1)
                {
                    Array.Copy(message.PassedServers, 0, newArray, 0, message.PassedServers.Length);
                }

                //Replace old array by new array 
                message.PassedServers = newArray;
            }

            //Add transmit report to array
            message.PassedServers[message.PassedServers.Length - 1] = transmitReport;
        }
示例#20
0
 /// <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(MDSRemoteApplication senderApplication, ICommunicator senderCommunicator, MDSPersistentRemoteApplicationBase destApplication, MDSDataTransferMessage message)
 {
     destApplication.EnqueueMessage(message);
     SendOperationResultMessage(senderApplication, senderCommunicator, message, true, "Success.");
 }
示例#21
0
        /// <summary>
        /// Checks a MDSDataTransferMessage 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(MDSDataTransferMessage dataTransferMessage, MDSRemoteApplication 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>
            /// Sets Leaving time for last passed server (this server) of message.
            /// </summary>
            /// <param name="message">Message object</param>
            private static void SetLeavingTime(MDSDataTransferMessage message)
            {
                if (message.PassedServers == null || message.PassedServers.Length <= 0)
                {
                    return;
                }

                message.PassedServers[message.PassedServers.Length - 1].LeavingTime = DateTime.Now;
            }
示例#23
0
 /// <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(MDSRemoteApplication senderApplication, ICommunicator senderCommunicator, MDSDataTransferMessage 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
             );
     }
 }
示例#24
0
 /// <summary>
 /// Creates a new IncomingDataMessage object from a MDSDataTransferMessage object.
 /// </summary>
 /// <param name="message">MDSDataTransferMessage object to create IncomingDataMessage</param>
 public IncomingDataMessage(MDSDataTransferMessage message)
 {
     DestinationApplicationName = message.DestinationApplicationName;
     DestinationCommunicatorId = message.DestinationCommunicatorId;
     DestinationServerName = message.DestinationServerName;
     MessageData = message.MessageData;
     MessageId = message.MessageId;
     PassedServers = message.PassedServers;
     RepliedMessageId = message.RepliedMessageId;
     SourceApplicationName = message.SourceApplicationName;
     SourceCommunicatorId = message.SourceCommunicatorId;
     SourceServerName = message.SourceServerName;
     TransmitRule = message.TransmitRule;
 }
示例#25
0
        /// <summary>
        /// Sends message directly to application (not stores) and waits ACK.
        /// This method adds message to queue by MDSPersistentRemoteApplicationBase.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(MDSRemoteApplication senderApplication, ICommunicator senderCommunicator, MDSPersistentRemoteApplicationBase destApplication, MDSDataTransferMessage 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>
 /// Finds Next server for a message.
 /// This method is designed, because it is different to get next server's name for client applications and mds servers.
 /// </summary>
 /// <returns>Next server</returns>
 protected abstract string GetNextServerForMessage(MDSDataTransferMessage message);
示例#27
0
        /// <summary>
        /// To send a MDSOperationResultMessage 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(MDSRemoteApplication senderApplication, ICommunicator communicator, MDSDataTransferMessage 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 MDSOperationResultMessage
                {
                    RepliedMessageId = repliedMessage.MessageId,
                    Success = success,
                    ResultText = resultText
                }, communicator);
            }
            catch (Exception ex)
            {
                Logger.Warn(ex.Message, ex);
            }
        }
            /// <summary>
            /// This method is used to send a MDSDataTransferMessage to an available communicator of application.
            /// It just blocks caller thread until a communicator comes available and message is sent or until timeout,
            /// but receives result (ACK/Reject) message asynchronous. It sends result (ACK/Reject) message to OnResponseReceived() method.
            /// </summary>
            /// <param name="message">Message to send</param>
            /// <param name="timeOut">Timeout value to wait if all receivers are busy. Set 0 to do not use timeout.</param>
            /// <returns>True, if message sent to communicator.</returns>
            public void SendDataMessage(MDSDataTransferMessage message, int timeOut)
            {
                //Get a free/available communicator from _receiverCommunicators list
                ConnectedCommunicator receiver = null;
                lock (_remoteApplication._communicators)
                {
                    var startTime = DateTime.Now;
                    var passedTime = 0;
                    while (receiver == null)
                    {
                        //If no receiver is connected to server, throw exception
                        if (_remoteApplication._communicators.Count <= 0)
                        {
                            throw new MDSNoCommunicatorException("There is no communicator for remote application '" + _remoteApplication.Name + "' to send message.");
                        }

                        //If timeout is set and timeout occurs, throw an exception
                        if ((timeOut > 0) && ((passedTime = (int)DateTime.Now.Subtract(startTime).TotalMilliseconds) >= timeOut))
                        {
                            throw new MDSTimeoutException("All communicators for remote application '" + _remoteApplication.Name + "' are busy. Waited for " + timeOut + " ms.");
                        }

                        //Get a free communicator that can receive message
                        //TODO: This check is working but not proper for here, move in the future.
                        receiver = message.DestinationServerName == _remoteApplication.Settings.ThisServerName
                                       ? GetFreeReceiverCommunicator(message.DestinationCommunicatorId)
                                       : GetFreeReceiverCommunicator(0);

                        //If no communicator is free, than wait for a free communicator..
                        if (receiver == null)
                        {
                            if (timeOut > 0)
                            {
                                //If there is not free communicator, wait until a communicator is available
                                Monitor.Wait(_remoteApplication._communicators, timeOut - passedTime);
                            }
                            else
                            {
                                //If there is not free communicator, wait until a communicator is available
                                Monitor.Wait(_remoteApplication._communicators);
                            }
                        }
                        else
                        {
                            receiver.ProcessingMessage = message;
                            receiver.ProcessingMessageExpireDate = DateTime.Now.AddMilliseconds(_remoteApplication.Settings.MessageResponseTimeout);
                        }
                    }
                }

                //Send message to communicator
                SetLeavingTime(message);
                SendMessage(message, receiver.Communicator);
            }