/// <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> /// /// </summary> protected virtual void HandleResponseMessage(TransportMessage message) { SessionResults respondedSession = null; // First - check if this is a responce to a currently pending session. lock (_communicationSessions) { string requestMessageInfo = string.Empty; if (message is ResponseMessage) { requestMessageInfo = ((ResponseMessage)message).RequestMessageTypeName; } if (_communicationSessions.ContainsKey(message.TransportInfo.CurrentTransportInfo.Value.Id) == false) { TracerHelper.TraceError("Response received to a session that is not pending [from " + message.TransportInfo.OriginalSenderId.Value.Id.Print() + " to " + this.SubscriptionClientID.Id.Print() + "]. Message [" + message.GetType().Name + " responding to " + requestMessageInfo + "] dumped."); return; } respondedSession = _communicationSessions[message.TransportInfo.CurrentTransportInfo.Value.Id]; } // Clear off the sessioning Transport Info that just brough it back as well. message.TransportInfo.PopTransportInfo(); respondedSession.ReceiveResponse(message); }
/// <summary> /// /// </summary> /// <param name="entity"></param> public void AddExecutionEntity(ExecutionEntity entity) { TracerHelper.TraceEntry(); lock (this) { if (_pendingEntities.Count > _maxPendingExecutionItems) { TracerHelper.TraceError("Too many pending entities in system. Some older entities are being dropped."); if ((DateTime.Now - _maxPendingItemsWarningShownTime) > _warningsTimeSpan) { _maxPendingItemsWarningShownTime = DateTime.Now; SystemMonitor.Error("Too many pending entities in system. Some older entities are being dropped."); } // Loose the oldest entity in line. _timeOutMonitor.RemoveEntity(_pendingEntities[0]); _pendingEntities.RemoveAt(0); } _timeOutMonitor.AddEntity(entity); _pendingEntities.Add(entity); } // Continue execution chain. UpdatePendingExecution(); }
/// <summary> /// This is an entry point for the direct call mechanism. So optimization is on speed and not functionality. /// </summary> /// <param name="message"></param> /// <returns></returns> public override Message ReceiveDirectCall(Message message) { FastInvokeHelper.FastInvokeHandlerDelegate handler = GetMessageHandler(message); if (handler != null) { return((Message)handler(this, new object[] { message })); } else {// We failed to find a handler for this type or for any of the parent ones. TracerHelper.TraceError("Client instance did not handle a request message received, client [" + this.GetType().Name + "], message [" + message.GetType().Name + "]."); return(null); } //Message responceMessage = (Message)invokeMethodInfo.Invoke(this, new object[] { message }); //return responceMessage; }
/// <summary> /// /// </summary> /// <param name="messageContainer"></param> public void ReceiveMessageContainer(MessageContainer messageContainer) { TracerHelper.Trace("[" + messageContainer.MessageStreamLength + "], clientCallback[" + OperationContext.Current.SessionId + "]"); if (MessageContainerReceivedEvent != null) { string sessionId = OperationContext.Current.SessionId; GeneralHelper.FireAndForget(delegate() { try { MessageContainerReceivedEvent(sessionId, messageContainer); } catch (Exception ex) { TracerHelper.TraceError(ex.Message); } }); } }
/// <summary> /// Set operationContextSessionID to "*" to mark all clients. /// </summary> /// <param name="operationContextSessionID"></param> /// <param name="messageContainer"></param> public void SendMessageContainer(string operationContextSessionID, MessageContainer messageContainer) { TracerHelper.TraceEntry("[" + messageContainer.MessageStreamLength + "]"); if (messageContainer.MessageStreamLength > MaximumAllowedMessageSize) { TracerHelper.TraceError("Message too bid. Operation failed."); return; //throw new Exception("Arbiter::MessageContainerTransportServer::MessageContainer requestMessage is too big. Message will not be sent."); } Dictionary <IMessageContainerTransport, OperationContext> clientsContexts; lock (_contextManager) { clientsContexts = new Dictionary <IMessageContainerTransport, OperationContext>(_contextManager.ClientsContextsUnsafe); } List <IMessageContainerTransport> badInterfaces = new List <IMessageContainerTransport>(); foreach (IMessageContainerTransport clientCallback in clientsContexts.Keys) { // "*" indicates send to all clients if (operationContextSessionID == "*" || clientsContexts[clientCallback].SessionId == operationContextSessionID) { try { TracerHelper.Trace("clientCallback [" + operationContextSessionID + "]"); clientCallback.ReceiveMessageContainer(messageContainer); TracerHelper.Trace("clientCallback [" + operationContextSessionID + "] invoked"); } catch (Exception ex) { TracerHelper.TraceError("Failed to invoke client interface [" + ex.ToString() + "]"); badInterfaces.Add(clientCallback); } } } ProcessBadInterfaces(badInterfaces); TracerHelper.TraceExit(); }
/// <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> /// Send container over to the other side. /// </summary> /// <param name="messageContainer"></param> /// <returns></returns> public virtual bool SendMessageContainer(MessageContainer messageContainer) { TracerHelper.TraceEntry("sending [" + messageContainer.MessageStreamLength + "], sessionID[" + this.ConnectionSessionID + "]"); SystemMonitor.CheckThrow(messageContainer.MessageStreamLength <= MessageContainerTransportServer.MaximumAllowedMessageSize, "MessageContainer message is too big. Message will not be sent."); if (_connectingEvent.WaitOne(_defaultConnectionTimeOut) == false) { SystemMonitor.OperationError("Failed to send message due to initialization timeout.", TracerItem.PriorityEnum.Medium); return(false); } try { IMessageContainerTransport messageInterface; lock (this) { if (_proxyServerInterface == null) { TracerHelper.TraceError("Failed to send to server, interface not created."); return(false); } messageInterface = _proxyServerInterface; } messageInterface.ReceiveMessageContainer(messageContainer); lock (this) { _lastServerCall = DateTime.Now; } } catch (Exception exception) { TracerHelper.TraceError("Failed to send to server, reason [" + exception.Message + "]."); return(false); } return(true); }
/// <summary> /// Handle a request message. /// </summary> protected virtual void HandleRequestMessage(TransportMessage message) { FastInvokeHelper.FastInvokeHandlerDelegate handler = GetMessageHandler(message); if (handler == null) {// We failed to find a handler for this type or for any of the parent ones. TracerHelper.TraceError("Client instance did not handle a request message received, client [" + this.GetType().Name + "], message [" + message.GetType().Name + "]."); return; } // Before giving the requestMessage to the user class, make a copy of its transport info // so that if the user messes it up, we still can deliver the responce properly. TransportInfo requestMessageTransportInfo = message.TransportInfo.Clone(); TransportMessage responseMessage = (TransportMessage)handler(this, new object[] { message }); if (responseMessage == null) {// No result. return; } if (responseMessage is ResponseMessage) { ((ResponseMessage)responseMessage).RequestMessageTypeName = message.GetType().Name; } Guid sessionGuid = requestMessageTransportInfo.CurrentTransportInfo.Value.Id; ArbiterClientId?senderID = requestMessageTransportInfo.CurrentTransportInfo.Value.SenderID; requestMessageTransportInfo.PopTransportInfo(); // Transfer inherited underlaying transport stack. responseMessage.TransportInfo = requestMessageTransportInfo; // Send the responce requestMessage back. DoSendCustom(false, sessionGuid, null, 0, senderID, this.SubscriptionClientID, responseMessage, TimeSpan.Zero); }
/// <summary> /// /// </summary> public void ReceiveResponce(TransportMessage message) { if (message != null && message.GetType() != _responceTypeRequired && message.GetType().IsSubclassOf(_responceTypeRequired) == false) { SystemMonitor.Error("Session received invalid responce message type [expected (" + _responceTypeRequired.Name + "), received(" + message.GetType().Name + ")]. Message ignored."); } else { if (message == null) {// We received a NULL signalling to stop wait and abort session. _sessionEndEvent.Set(); return; } else { lock (_responcesReceived) { if (_responcesReceived.Count < _responcesRequired) { _responcesReceived.Add(message); if (_responcesReceived.Count == _responcesRequired) { _sessionEndEvent.Set(); } } else {// One more requestMessage responce received. TracerHelper.TraceError("Session received too many responce messages. Message ignored."); } } } } }
/// <summary> /// Create a message instance based on the information in the internal stream. /// </summary> public Message CreateMessageInstance() { lock (_messageStream) { _messageStream.Position = 0; if (_messageStream.Length > 0) { try { BinaryFormatter formatter = new BinaryFormatter(); Message message = (Message)formatter.Deserialize(_messageStream); return(message); } catch (Exception exception) { TracerHelper.TraceError("Exception in message deserialization [" + exception.Message + "]."); throw; } } } TracerHelper.TraceError("No message serialized to deserialize."); return(null); }
/// <summary> /// Central sending function. /// </summary> /// <param name="receiverID">The ID of the receiver module. Can be <b>null</b> and this sends to all in the Arbiter.</param> protected TransportMessage[] DoSendCustom(bool isRequest, Guid sessionGuid, Type expectedResponseMessageClassType, int responsesRequired, ArbiterClientId?receiverId, ArbiterClientId?senderId, TransportMessage message, TimeSpan timeOut) { //TracerHelper.TraceEntry(); SessionResults session = null; if (receiverId.HasValue && receiverId.Value.IsEmpty /*receiverId.Value.CompareTo(ArbiterClientId.Empty) == 0*/) { SystemMonitor.Error("Can not send an item to empty receiver. Use null to specify broadcast."); return(null); } // Preliminary verification. if (Arbiter == null) { SystemMonitor.OperationWarning("Using a client [" + this.GetType().Name + ":" + senderId.Value.ClientName + " to " + (receiverId.HasValue ? receiverId.Value.Id.Name : string.Empty) + " , " + message.GetType().Name + "] with no Arbiter assigned."); return(null); } message.IsRequest = isRequest; TransportInfoUnit infoUnit = new TransportInfoUnit(sessionGuid, senderId, receiverId); message.TransportInfo.AddTransportInfoUnit(infoUnit); bool sessionEventResult = false; if (expectedResponseMessageClassType != null) {// Responce waiting session. session = new SessionResults(responsesRequired, expectedResponseMessageClassType); lock (_communicationSessions) {// Register the session. _communicationSessions.Add(sessionGuid, session); } } SystemMonitor.CheckError(message.TransportInfo.CurrentTransportInfo != null); Conversation conversation; if (receiverId == null) { // We shall not use the next level time out mechanism. conversation = Arbiter.CreateConversation(senderId.Value, message, TimeSpan.Zero); } else {// Addressed conversation. // We shall not use the next level time out mechanism. conversation = Arbiter.CreateConversation(senderId.Value, receiverId.Value, message, TimeSpan.Zero); } if (conversation != null && expectedResponseMessageClassType != null) { // Responce waiting session (only if conversation was properly created). if (timeOut == TimeSpan.Zero) { // Wait forever. sessionEventResult = session.SessionEndEvent.WaitOne(); } else {// Wait given period. sessionEventResult = session.SessionEndEvent.WaitOne(timeOut, false); } lock (_communicationSessions) {// Remote the session. _communicationSessions.Remove(sessionGuid); } } message.TransportInfo.PopTransportInfo(); if (expectedResponseMessageClassType == null) {// No responce waiting, just return. //TracerHelper.TraceExit(); return(null); } // Responce waiting session. if (sessionEventResult == false) {// Timed out - only send and receives can time out, as the other ones do not have sessions!! TracerHelper.TraceError("Session has timed out [" + message.GetType().Name + "]."); return(null); } //TracerHelper.TraceExit(); return(session.Responses.ToArray()); }