/// <summary> /// Allows to send a message to receiver, by "hiding" the current node, this way all responce messages /// are targeted to the original sender (incl. responce of this message if it is request). /// This allows to implement a message proxy. /// </summary> /// <param name="receiverId"></param> /// <param name="message"></param> protected void ProxySend(ArbiterClientId receiverId, TransportMessage message) { TransportInfoUnit?info = message.TransportInfo.PopTransportInfo(); if (info == null) { SystemMonitor.Error("Failed to establish message pending transport info."); return; } DoSendCustom(message.IsRequest, info.Value.Id, null, 0, receiverId, info.Value.SenderID, message, DefaultTimeOut); }
/// <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); }
/// <summary> /// Do not use this in normal circumstances, this is automatically assigned. /// Allows to assign element with an existing ID, in order to be recognized in existing paths after de-persistence. /// </summary> /// <param name="id"></param> public bool SetArbiterSubscriptionClientId(ArbiterClientId id) { if (_arbiter != null) { SystemMonitor.Error("CAn not assign arbiter subscription id, after item already added to arbiter."); return(false); } lock (this) { _subscriptionClientId = id; } return(true); }
/// <summary> /// Message received from the "Pipe". /// </summary> void _transport_MessageReceivedEvent(string operationContextSessionID, MessageContainer messageContainer) { TransportMessage message = (TransportMessage)messageContainer.CreateMessageInstance(); TracerHelper.Trace("[" + message.GetType().Name + "], length [" + messageContainer.MessageStreamLength + "]"); if (message.IsRequest) { // Request requestMessage. { // Mark the request requestMessage with additional fragment in the transportation stack. ArbiterClientId senderID = new ArbiterClientId("PipeChannelID", null, null); senderID.SessionTag = operationContextSessionID; message.TransportInfo.AddTransportInfoUnit(new TransportInfoUnit(Guid.NewGuid(), senderID, this.SubscriptionClientID)); } if (MandatoryRequestMessageReceiverID.HasValue) {// There is a default receiver assigned for all messages from this integrator. DoSendCustom(true, Guid.NewGuid(), null, 0, MandatoryRequestMessageReceiverID.Value, this.SubscriptionClientID, message, TimeSpan.Zero); } else {// No explicit mandatory receiver. if (message.TransportInfo.ForwardTransportInfoCount > 0) { // First pop the Session stack, than send the cleared requestMessage. ArbiterClientId?receiverID = message.TransportInfo.PopForwardTransportInfo(); DoSendCustom(true, Guid.NewGuid(), null, 0, receiverID, this.SubscriptionClientID, message, TimeSpan.Zero); } else { DoSendCustom(true, Guid.NewGuid(), null, 0, null, this.SubscriptionClientID, message, TimeSpan.Zero); } } } else {// Responce requestMessage - send back to whoever sent it to us before. // And clear off the initial request information, we are responding now to. Guid sessionID = message.TransportInfo.CurrentTransportInfo.Value.Id; ArbiterClientId?receiverID = message.TransportInfo.CurrentTransportInfo.Value.SenderID; message.TransportInfo.PopTransportInfo(); this.DoSendCustom(false, sessionID, null, 0, receiverID, this.SubscriptionClientID, message, TimeSpan.Zero); } }
/// <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> ///// 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; //} /// <summary> /// Will send a point to point requestMessage and start a conversation that can have many replies. /// </summary> public ConversationPointToPoint CreateConversation(ArbiterClientId senderID, ArbiterClientId receiverID, Message message, TimeSpan timeout) { SystemMonitor.CheckError(((TransportMessage)message).TransportInfo.CurrentTransportInfo != null); if (message is TransportMessage) { SystemMonitor.CheckError(((TransportMessage)message).TransportInfo.CurrentTransportInfo != null); TracerHelper.Trace("sender[" + senderID.Id.Name + "], receiver [" + receiverID.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 from a not present sender [" + message.GetType().Name + ", " + senderID.Id.Print() + "]."); return(null); } if (GetClientByID(receiverID, false) == null) { SystemMonitor.OperationWarning("Sender [" + senderID.Id.Print() + "] creating conversation message [" + message.GetType().Name + " ] by not present receiver [" + receiverID.Id.Print() + "]"); return(null); } ConversationPointToPoint conversation = new ConversationPointToPoint(_executionManager, message, senderID, receiverID, timeout); if (_isDisposed) {// Possible to get disposed while operating here. return(null); } lock (_timeOutMonitor) { _timeOutMonitor.AddEntity(conversation); } return(conversation); }
/// <summary> /// Entity execution has finished. /// </summary> public override void EntityExecutionFinished(ExecutionEntity entity) { ExecutionEntityWithReply entityWithReply = (ExecutionEntityWithReply)entity; if (entityWithReply.ReplyMessage != null) {// The other side replied. ArbiterClientId messageReceiver = ReceiverID; if (_receiverID.Equals(entity.ReceiverID)) {// Swap direction, receiver must now send. messageReceiver = SenderID; } ExecutionEntityWithReply replyEntity = new ExecutionEntityWithReply(this, messageReceiver, entityWithReply.TimeOut, MessageContainer.DuplicateMessage(entityWithReply.ReplyMessage, false)); ExecutionManager.AddExecutionEntity(replyEntity); } else {// We received a nothing, conversation done, die. this.Die(); } }
/// <summary> /// /// </summary> public Message DirectCall(ArbiterClientId receiverID, TransportMessage message) { return(base.DirectCall(receiverID, message)); }
/// <summary> /// /// </summary> protected void SendAddressed(ArbiterClientId receiverID, TransportMessage message) { DoSendCustom(true, Guid.NewGuid(), null, 0, receiverID, this.SubscriptionClientID, message, DefaultTimeOut); }
/// <summary> /// Allows to retrieve an instance of a client by its ID. Use with caution since it breaks the independence model /// and is applied only in special cases. /// </summary> public IArbiterClient GetClientByID(ArbiterClientId id) { return(GetClientByID(id, false)); }
public ExecutionEntityWithReply(Conversation conversation, ArbiterClientId receiverID, TimeSpan timeOut, Message message) : base(conversation, receiverID, timeOut, message) { }
/// <summary> /// Deserialization constructor. /// </summary> /// <param name="singleThreadOnly"></param> public ArbiterClientBase(SerializationInfo info, StreamingContext context) { _subscriptionClientId = (ArbiterClientId)info.GetValue("clientId", typeof(ArbiterClientId)); _messageFilter = (MessageFilter)info.GetValue("messageFilter", typeof(MessageFilter)); }
/// <summary> /// /// </summary> public Conversation(ExecutionManager executionManager, ArbiterClientId ownerID, TimeSpan timeOut) : base(timeOut) { _ownerID = ownerID; _executionManager = executionManager; }
/// <summary> /// /// </summary> public TransportMessageFilter(ArbiterClientId ownerID) : base(true) { _ownerID = ownerID; }
/// /// </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> /// 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); }
public TExpectedMessageClass SendAndReceiveAddressed <TExpectedMessageClass>( ArbiterClientId receiverID, TransportMessage message, TimeSpan timeOut) where TExpectedMessageClass : TransportMessage { return(base.SendAndReceiveAddressed <TExpectedMessageClass>(receiverID, message, timeOut)); }
///// <summary> ///// ///// </summary> //public Message DirectCall(ArbiterClientId receiverID, TransportMessage message) //{ // return base.DirectCall(receiverID, message); //} public new void SendAddressed(ArbiterClientId receiverID, TransportMessage message) { base.SendAddressed(receiverID, message); }
/// <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; }