/// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="receiver"></param> /// <param name="timeOut"></param> /// <param name="requestMessage"></param> public ExecutionEntity(IExecutor executor, ArbiterClientId receiverID, TimeSpan timeOut, Message message) : base(timeOut) { _executor = executor; _receiverID = receiverID; _message = message; }
/// <summary> /// Helper static method, allowing to duplicate a message instance. /// It will duplicate the message, ONLY if the message is marked as "TransportByReference == false" /// or mandatoryDuplication is true. /// </summary> public static Message DuplicateMessage(Message message, bool mandatoryDuplication) { //if (mandatoryDuplication == false && message.TransportByReference) //{ // return message; //} //if (message is ICloneable) //{ // return (Message)((ICloneable)message).Clone(); //} MessageContainer container; try { container = new MessageContainer(); container.SerializeMessage(message); } catch (Exception exception) { TracerHelper.TraceError("Exception in message duplication [" + exception.Message + "]."); throw; } return container.CreateMessageInstance(); }
/// <summary> /// Constructor. /// </summary> public ConversationPointToPoint(ExecutionManager executionManager, Message message, ArbiterClientId senderID, ArbiterClientId receiverID, TimeSpan timeOut) : base(executionManager, senderID, timeOut) { _receiverID = receiverID; ExecutionEntityWithReply entity = new ExecutionEntityWithReply(this, receiverID, timeOut, MessageContainer.DuplicateMessage(message, false)); ExecutionManager.AddExecutionEntity(entity); }
/// /// </summary> public ConversationMultiPoint(ExecutionManager executionManager, Message message, ArbiterClientId senderID, IEnumerable<ArbiterClientId> receivers, TimeSpan timeOut) : base(executionManager, senderID, timeOut) { _receivers.AddRange(receivers); foreach (ArbiterClientId receiverID in receivers) { ExecutionEntity entity = new ExecutionEntity(this, receiverID, TimeSpan.Zero, MessageContainer.DuplicateMessage(message, false)); _executingEntities.Add(entity); ExecutionManager.AddExecutionEntity(entity); } }
/// <summary> /// /// </summary> /// <param name="message"></param> /// <returns></returns> public override Message ReceiveDirectCall(Message message) { try { //Type type = entity.Message.GetType(); //object t = Activator.CreateInstance(type); XmlSerializer s = new XmlSerializer(message.GetType()); s.Serialize(_fileStream, message); } catch (Exception e) { SystemMonitor.Error("Serialization failure [" + e.Message + "]"); } return null; }
/// <summary> /// Do the filtering based on the transportSessionGuid but allow all that are starting a session now. /// </summary> /// <param name="requestMessage"></param> public override bool MessageAllowed(Message messageInput) { SystemMonitor.CheckError(messageInput is TransportMessage); TransportMessage message = (TransportMessage)messageInput; if (this.Enabled == false) { return true; } bool isTypeAllowed = base.MessageAllowed(message); bool isAddressed = (message.TransportInfo.CurrentTransportInfo.Value.ReceiverID != null); bool isAddressedToMe = IsAddressedToMe(message); if (AllowOnlyAddressedMessages) {// Addressed mode. if (isAddressed == false || isAddressedToMe == false) { return false; } } else {// Non addressed mode. if (isAddressed && isAddressedToMe == false) {// Addressed to someone else. return false; } } // Addressing solved - it allowed the requestMessage to pass on. if (message.IsRequest) {// Request. return isTypeAllowed; } else {// Responce - accept. return true; } }
/// <summary> /// /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public virtual bool MessageAllowed(Message message) { if (!_enabled) { return true; } Type requiredType = message.GetType(); foreach (Type messageType in _allowedNonAddressedMessageTypes) { if (messageType == requiredType) {// Type matched. return true; } if (_allowChildrenTypes && requiredType.IsSubclassOf(messageType)) {// Subclasses allowed and this is one. return true; } } return false; }
/// <summary> /// Constructor. /// </summary> public MessageContainer(Message message) { SerializeMessage(message); }
/// <summary> /// Serializes the message to the internal stream and keeps it there for future usage. /// </summary> public void SerializeMessage(Message message) { lock (_messageStream) { _messageStream.SetLength(0); if (message != null) { try { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(_messageStream, message); } catch (Exception exception) { TracerHelper.TraceError("Exception in message serialization [" + exception.Message + "]."); throw; } } } }
/// <summary> /// Find out what clients need to receive this requestMessage. /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public IEnumerable<ArbiterClientId> GatherMessageClients(Message message, ArbiterClientId senderID) { List<ArbiterClientId> clients = new List<ArbiterClientId>(); if (_isDisposed) {// Possible to get disposed while operating here. return null; } lock (_clientsAndFilters) { foreach (IArbiterClient client in _clientsAndFilters.Keys) { if (_clientsAndFilters[client].MessageAllowed(message)) { clients.Add(client.SubscriptionClientID); } } } return clients; }
/// <summary> /// Will start a shoutcast mode conversation, the sender sending to all. /// </summary> /// <param name="sender"></param> /// <param name="requestMessage"></param> /// <param name="timeout"></param> /// <returns></returns> public ConversationMultiPoint CreateConversation(ArbiterClientId senderID, Message message, TimeSpan timeout) { if (message is TransportMessage) { SystemMonitor.CheckError(((TransportMessage)message).TransportInfo.CurrentTransportInfo != null); TracerHelper.Trace("sender[" + senderID.Id.Name + "], message [" + message.GetType().Name + "] [" + ((TransportMessage)message).TransportInfo.TransportInfoCount + "]"); } else { TracerHelper.Trace("sender[" + senderID.Id.Name + "], message [" + message.GetType().Name + "]"); } if (GetClientByID(senderID, false) == null) { SystemMonitor.Error("Creating conversation by not present sender/owner."); return null; } ConversationMultiPoint conversation = new ConversationMultiPoint(_executionManager, message, senderID, GatherMessageClients(message, senderID), timeout); if (_isDisposed) {// Possible to get disposed while operating here. return null; } lock (_timeOutMonitor) { _timeOutMonitor.AddEntity(conversation); } return conversation; }
/// <summary> /// /// </summary> /// <param name="requestMessage"></param> /// <param name="timeOut"></param> public void SetReply(Message message, TimeSpan timeOut) { _replyMessage = message; _replyTimeOut = timeOut; }
public ExecutionEntityWithReply(Conversation conversation, ArbiterClientId receiverID, TimeSpan timeOut, Message message) : base(conversation, receiverID, timeOut, message) { }
public abstract Message ReceiveDirectCall(Message message);
/// <summary> /// The direct call allows to circumvent the many steps (incl serialization) of typical message sending /// and make a direct call to another Arbiter member; thus making a much faster delivery. This path /// has a maximum optimization for speed, so tracing etc. are disabled. /// /// Also this mechanism only works for TransportClients currently. /// /// The mechanism does not utilize any new threads, and the execution is performed on the calling thread. /// /// Direct calls can only be made to participants on the same arbiter, and no addressing is applied /// for the messages. /// </summary> public Message DirectCall(ArbiterClientId senderID, ArbiterClientId receiverID, Message message) { IArbiterClient receiver = GetClientByID(receiverID, true); if (receiver == null || receiver is TransportClient == false) { SystemMonitor.OperationWarning("Sender [" + senderID.Id.Print() + "] creating conversation message [" + message.GetType().Name + " ] by not present receiver [" + receiverID.Id.Print() + "] or receiver not a TransportClient"); return null; } Message response = receiver.ReceiveDirectCall(message); return response; }