///<summary>Sends a "jms/stream-message"-encoded RPC request,
 ///and expects an RPC reply in the same format.</summary>
 ///<remarks>
 ///<para>
 /// The arguments passed in must be of types that are
 /// representable as JMS StreamMessage values, and so must the
 /// results returned from the service in its reply message.
 ///</para>
 ///<para>
 /// Calls OnTimedOut() and OnDisconnected() when a timeout or
 /// disconnection, respectively, is detected when waiting for
 /// our reply.
 ///</para>
 ///<para>
 /// Returns null if the request timed out or if we were
 /// disconnected before a reply arrived.
 ///</para>
 ///<para>
 /// The reply message, if any, is acknowledged to the AMQP
 /// server via Subscription.Ack().
 ///</para>
 ///</remarks>
 ///<see cref="IStreamMessageBuilder"/>
 ///<see cref="IStreamMessageReader"/>
 public virtual object[] Call(params object[] args)
 {
     IStreamMessageBuilder builder = new StreamMessageBuilder(Model);
     builder.WriteObjects(args);
     IBasicProperties replyProperties;
     byte[] replyBody = Call((IBasicProperties)builder.GetContentHeader(),
         builder.GetContentBody(),
         out replyProperties);
     if (replyProperties == null)
     {
         return null;
     }
     if (replyProperties.ContentType != StreamMessageBuilder.MimeType)
     {
         throw new ProtocolViolationException
             (string.Format("Expected reply of MIME type {0}; got {1}",
                 StreamMessageBuilder.MimeType,
                 replyProperties.ContentType));
     }
     IStreamMessageReader reader = new StreamMessageReader(replyProperties, replyBody);
     return reader.ReadObjects();
 }
 ///<summary>Called by ProcessRequest(), this is the most
 ///general method that handles RPC-style requests.</summary>
 ///<remarks>
 ///<para>
 /// This method should map requestProperties and body to
 /// replyProperties and the returned byte array.
 ///</para>
 ///<para>
 /// The default implementation checks
 /// requestProperties.ContentType, and if it is
 /// "jms/stream-message" (i.e. the current value of
 /// StreamMessageBuilder.MimeType), parses it using
 /// StreamMessageReader and delegates to
 /// HandleStreamMessageCall before encoding and returning the
 /// reply. If the ContentType is any other value, the request
 /// is passed to HandleSimpleCall instead.
 ///</para>
 ///<para>
 /// The isRedelivered flag is true when the server knows for
 /// sure that it has tried to send this request previously
 /// (although not necessarily to this application). It is not
 /// a reliable indicator of previous receipt, however - the
 /// only claim it makes is that a delivery attempt was made,
 /// not that the attempt succeeded. Be careful if you choose
 /// to use the isRedelivered flag.
 ///</para>
 ///</remarks>
 public virtual byte[] HandleCall(bool isRedelivered,
                                  IBasicProperties requestProperties,
                                  byte[] body,
                                  out IBasicProperties replyProperties)
 {
     if (requestProperties.ContentType == StreamMessageBuilder.MimeType) {
         IStreamMessageReader r = new StreamMessageReader(requestProperties, body);
         IStreamMessageBuilder w = new StreamMessageBuilder(m_subscription.Model);
         HandleStreamMessageCall(w,
                                 isRedelivered,
                                 requestProperties,
                                 r.ReadObjects());
         replyProperties = (IBasicProperties) w.GetContentHeader();
         return w.GetContentBody();
     } else {
         return HandleSimpleCall(isRedelivered,
                                 requestProperties,
                                 body,
                                 out replyProperties);
     }
 }