1

I am attempting to implement Request-Response in Solace.

However RR-Requestor is written in C# whereas the code for the RR-Responder is written in JAVA.

I’ve 2 issues:

  1. After the message is successfully sent by the Solace C# API, it is received by a JAVA application. I happen to receive the message in BytesXMLMessage structure. How do I convert the message to String? message.dump() gives me the entire details.

  2. When I send a reply message, .NET application receives the message with some additional unwanted characters.

Code used in the JAVA side:

    //After session is created
    XMLMessageConsumer consumer = session.getMessageConsumer(new RequestHandler());
    XMLMessageProducer producer = session.getMessageProducer(new PrintingPubCallback());
    consumer.start();
    session.addSubscription(
            JCSMPFactory.onlyInstance().createTopic("Test_Response_Queue"),
            true);
    class RequestHandler implements XMLMessageListener {

    private void sendReply(BytesXMLMessage request, BytesXMLMessage reply)
            throws JCSMPException {

        producer.sendReply(request, reply);

    }

    public void onException(JCSMPException arg0) {
        // TODO Auto-generated method stub

    }

    public void onReceive(BytesXMLMessage message) {
        System.out.println("Received request message, trying to parse it");

        System.out.println(message.dump());

        try {

            TextMessage textMessage = JCSMPFactory.onlyInstance()
                    .createMessage(TextMessage.class);

            final String text = "Reply from JAVA, text message!!";
            textMessage.setText(text);

            sendReply(message, textMessage);

        } catch (JCSMPException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

And in the .NET side

            // Create the request message
        IMessage requestMessage = ContextFactory.Instance.CreateMessage();
        requestMessage.Destination = ContextFactory.Instance.CreateTopic("Test_Response_Queue");
        requestMessage.DeliveryMode = MessageDeliveryMode.Direct; /* explicitly set to MessageDeliveryMode.Direct */
        //IStreamContainer stream = SDTUtils.CreateStream(requestMessage, 256);
        //stream.AddString("Hello from Linux!!");
        requestMessage.BinaryAttachment = Encoding.ASCII.GetBytes("Hello from Linux!!");

        // Send the request message to the service or RRDirectReplier
        IMessage replyMessage = null;
        int timeout = 2000; /* 2 secs*/
        Console.WriteLine("\nSending  request message, waiting for {0} msecs for a reply (make sure that RRDirectReply is running) ...", timeout);

        if (session.SendRequest(requestMessage, out replyMessage, 2000) == ReturnCode.SOLCLIENT_OK)
        {
            // Got a reply, format and print the response message
            Console.WriteLine("\nGot reply message");
            String str = Encoding.ASCII.GetString(replyMessage.BinaryAttachment);
            Console.WriteLine(str);
        }
        else
        {
            Console.WriteLine("Request failed");
        }
        if (requestMessage != null)
        {
            // It is a good practice to dispose of messages once done using them
            requestMessage.Dispose();
        }

Reply contains additional characters in the string received. See the image below.

enter image description here

Any idea?

Thanks.

Dixit Gokhale
  • 601
  • 1
  • 12
  • 32

2 Answers2

3

If the message you receive is a TextMessage, try the following:

if (message instanceof TextMessage) {
    String text = ((TextMessage) message).getText();
} 
//otherwise retrieve the attachment buffer like this
else {
    byte[] body = message.getAttachmentByteBuffer().array();
    //and convert to String
    String text = new String(body);
}

You are probably seeing an extra character at the beginning of your reply message because you are creating a TextMessage as reply. The TextMessage contains an few extra bytes at the beginning of the attachment to mark it as TextMessage and those contain the length of the text. You should use a corresponding class in .NET like TextMessage that does the parsing for you.

3

There are several methods to send/receive strings between the different APIs, and here are 2 possible methods.

1. Convert the string to an array of bytes and attach it as a binary payload to the Solace message.

.NET send:

IMessage message = ContextFactory.Instance.CreateMessage();
message.Destination = topic;
message.BinaryAttachment = Encoding.UTF8.GetBytes("My .NET String");
session.Send(message);

Java receive:

// assuming that message is a reference to a received message
if(message.getAttachmentByteBuffer() != null) {
    byte[] messageBinaryPayload = message.getAttachmentByteBuffer().array();
    try {
        String myReceivedText = new String(messageBinaryPayload, "UTF-8");
        System.out.println("Received String = " + myReceivedText);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
}
else {
    // No binary attachment in message - application needs to decide what to do next.
}

Java send:

String myJavaString = "My Java String";
BytesXMLMessage message = JCSMPFactory.onlyInstance().createMessage(BytesXMLMessage.class);
message.writeAttachment(myJavaString.getBytes(Charset.forName("UTF-8")));
producer.send(message, topic);

.NET receive:

// assuming that message is a reference to a received message
byte[] messageBinaryPayload = message.BinaryAttachment;

if(messageBinaryPayload != null) {
    string myReceivedString = System.Text.Encoding.UTF8.GetString(messageBinaryPayload);
    Console.WriteLine("Received String = " + myReceivedString);
}
else {
    // No binary attachment in message - application needs to decide what to do next.
}

2. Send and receive the string as a TextMessage

.NET send:

IMessage message = ContextFactory.Instance.CreateMessage();
message.Destination = topic;
SDTUtils.SetText(message, "My .NET String");
session.Send(message);

Java receive:

// assuming that message is a reference to a received message
if (message instanceof TextMessage) {
    String myReceivedString = ((TextMessage) message).getText();
    System.out.println("Received String = " + myReceivedString);
} 
else {
    // Message is not a TextMessage - application needs to decide what to do next.
}

Java send:

TextMessage message = JCSMPFactory.onlyInstance().createMessage(TextMessage.class);
message.setText("My Java String");
producer.send(message, topic);

.NET receive:

// assuming that message is a reference to a received message
String myReceivedString = SDTUtils.GetText(message);
if (myReceivedString != null) {
    // Message is an TextMessage
    Console.WriteLine("Received String = " + myReceivedString);
}
else {
    // Message is not a TextMessage - application needs to decide what to do next.
}
Russell Sim
  • 1,693
  • 2
  • 14
  • 22
  • Thanks a lot @Russell Sim – Dixit Gokhale Oct 15 '15 at 07:19
  • Also I believe if(session.SendRequest(requestMessage, out replyMessage, 4000) == ReturnCode.SOLCLIENT_OK){} is the way to send message. It waits till 4 seconds for a message for the reply message to arrive. How can we make it wait indefinitely? If we are not sure how much time the RRResponder is going to take to respond. – Dixit Gokhale Oct 15 '15 at 09:51
  • @Dixit There's no way to make this method wait indefinitely. You can consider using a huge timeout value (Int32.MaxValue) to simulate an indefinite wait. However, it's a better practice to have your application not wait indefinitely, and actually have it take action after a certain amount of time. Perhaps a notification to the user is in order? Perhaps you can consider re-sending the message after a certain amount of wait time. – Russell Sim Oct 16 '15 at 07:08