You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@mina.apache.org by Skywalker <le...@gmail.com> on 2014/05/30 13:59:19 UTC

Understanding Apache Mina 2 Request/Response mapping

Hi all,

I need help to understanding how Apache Mina 2 maps responses to requests.
It appears it matches responses to their respective requests by assuming the
responses will come back on the same socket.

e.g.
If requests to server leaves on lets say Local Address: /192.168.0.10:53217
i.e. ProtocolEncoder's session.getLocalAddress(), Apache mina expects
response on the Local Address: /192.168.0.10:53217 i.e. ProtocolDecoder's
session.getLocalAddress()

However, I have a situation where the service responds to any available
socket, e.g. the response could be on Local Address: /192.168.0.10:53282.

I realize Mina is unable to map this response, and I am unable to get this
response. How do I use something else to map request and response other than
socket id.

Regards.




--
View this message in context: http://apache-mina.10907.n7.nabble.com/Understanding-Apache-Mina-2-Request-Response-mapping-tp42337.html
Sent from the Apache MINA User Forum mailing list archive at Nabble.com.

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Skywalker <le...@gmail.com>.
Here is a sample implementation of my code:

Class MinaTCPClient: This class is a singleton - only one instance is used. 

public class MinaTCPClient {

public static void process(final MinaEndpoint minaEndpoint, int size)
	{
		try
		{
	        Thread[] clientThreads = new Thread[size];
	        int index = 0;
	        for (Thread clientThread: clientThreads)
	        {
	        	clientThread = new Thread(String.valueOf(index))
	            {
	                public void run()
	                {
	                	try
	                	{
	                		String isoXml =
"<request><echodata>1234</echodata></request>";
		                	String response =
String.valueOf(minaEndpoint.process(isoXml));
		                	LOG.debug("Response: " + response);		                	
	                	}
	                	catch(Exception ex)
	                	{
	                		ex.printStackTrace();
	                	}	                	
	                }
	            };
	            clientThread.start();
	        }
	        
	        for (Thread clientThread : clientThreads) {
	            clientThread.join();
	        }
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}		 
	}

}


Class MinaEndpoint:

public class MinaEndpoint()
{

private IoSession session;
    private CountDownLatch latch;
    private long timeout = 55000;
    private SocketAddress address;
    private IoConnector connector;
    private boolean sync;
    private IoSessionConfig connectorConfig;
    private ExecutorService workerPool;

public MinaEndpoint(String host, int port)
	{
		address = new InetSocketAddress(host, port);
		final int processorCount = Runtime.getRuntime().availableProcessors() + 1;
		connector = new NioSocketConnector(processorCount);
	    connectorConfig = connector.getSessionConfig();
	    workerPool = new UnorderedThreadPoolExecutor(16);
		connector.getFilterChain().addLast("threadPool", new
ExecutorFilter(workerPool));
		connector.getFilterChain().addLast("logger", new LoggingFilter());
		connector.setConnectTimeoutMillis(timeout);
		connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new
Mina2ISO8583XMLCodecFactory()));
	}

public Object process(Object body) throws Exception
	{
		connector.getSessionConfig().setAll(connectorConfig);
		connector.setHandler(new ResponseHandler());
        ConnectFuture future = connector.connect(address);
        future.awaitUninterruptibly();
        session = future.getSession();
        latch = new CountDownLatch(1);
        ResponseHandler handler = (ResponseHandler) session.getHandler();
        handler.reset();
        session.write(body);
        boolean done = latch.await(timeout, TimeUnit.MILLISECONDS);
        if(!done)
        	throw new TimeoutException("Timeout waiting for response for " +
body);
        handler = (ResponseHandler) session.getHandler();
        Object response = handler.getMessage();        
        return response;
	}


    private final class ResponseHandler extends IoHandlerAdapter {

        private Object message;
        private Throwable cause;
        private boolean messageReceived;

        public void reset() {
            this.message = null;
            this.cause = null;
            this.messageReceived = false;
        }

        @Override
        public void messageReceived(IoSession ioSession, Object message)
throws Exception {
            this.message = message;
            messageReceived = true;
            cause = null;
            countDown();
        }

        protected void countDown() {
            CountDownLatch downLatch = latch;
            if (downLatch != null) {
                downLatch.countDown();
            }
        }

        @Override
        public void sessionClosed(IoSession session) throws Exception {
            if (sync && !messageReceived) {
                countDown();
            }
        }

        @Override
        public void exceptionCaught(IoSession ioSession, Throwable cause) {
            this.message = null;
            this.messageReceived = false;
            this.cause = cause;
            if (ioSession != null) {
                ioSession.close(true);
            }
        }

        public Throwable getCause() {
            return this.cause;
        }

        public Object getMessage() {
            return this.message;
        }

        public boolean isMessageReceived() {
            return messageReceived;
        }
    }

}

NB: CODEC classes arent included



--
View this message in context: http://apache-mina.10907.n7.nabble.com/Understanding-Apache-Mina-2-Request-Response-mapping-tp42337p42366.html
Sent from the Apache MINA User Forum mailing list archive at Nabble.com.

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Emmanuel Lécharny <el...@gmail.com>.
Le 30/05/2014 18:14, Skywalker a écrit :
>>>> What are the part of the code you are working on ? What is the part of 
>>>> the server code taht selects the session to which teh response wil be
>>>> sent ? 
> I do not have access to the server code. It is a Commercial Off the Shelf
> Software. I am working with the ProtocolDecoder and ProtocolEncoder.

The pb is that if something just shuffles the session after the decoding
of your message, I don't see how possibly you can restore it.

Now, if, and only if, there is no executor in the chain, and if there is
a guarantee that the thread processing the request is the same than the
thread processing the answer (and here, I mean no other session session
will use this thread in the mean time), then you can store the original
session into the ThreadLocalStorage, and get it back while processing
the encoding. That could work...


Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Skywalker <le...@gmail.com>.
>>> What are the part of the code you are working on ? What is the part of 
>>> the server code taht selects the session to which teh response wil be
>>> sent ? 

I do not have access to the server code. It is a Commercial Off the Shelf
Software. I am working with the ProtocolDecoder and ProtocolEncoder.

Regards.



--
View this message in context: http://apache-mina.10907.n7.nabble.com/Understanding-Apache-Mina-2-Request-Response-mapping-tp42337p42353.html
Sent from the Apache MINA User Forum mailing list archive at Nabble.com.

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Emmanuel Lécharny <el...@gmail.com>.
Le 30/05/2014 17:30, Skywalker a écrit :

>>>> Question : why don't you store the original session into your message, 
>>>> so that you can send it back to the emitter ? 
> I dont have the capability to include the session in the request to the
> server. 



> However part of the response has an echoed data that can be
> correlated with the original request. I was wondering How I can extend Mina
> to do this correlation.

What are the part of the code you are working on ? What is the part of
the server code taht selects the session to which teh response wil be sent ?

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Skywalker <le...@gmail.com>.
>>> If you server receives a message, this message will be associated with a 
>>> session. If you have changed the session before the handler (ie, in a 
>>> filter), then the messageReceived( session, message ) will not allow you 
>>> to send back the response to the correct session.

Thanks. This confirms my guess.


>>> Question : why don't you store the original session into your message, 
>>> so that you can send it back to the emitter ? 
I dont have the capability to include the session in the request to the
server. However part of the response has an echoed data that can be
correlated with the original request. I was wondering How I can extend Mina
to do this correlation.

Regards.



--
View this message in context: http://apache-mina.10907.n7.nabble.com/Understanding-Apache-Mina-2-Request-Response-mapping-tp42337p42350.html
Sent from the Apache MINA User Forum mailing list archive at Nabble.com.

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Emmanuel Lécharny <el...@gmail.com>.
Le 30/05/2014 15:51, Skywalker a écrit :
>>>> I don't get it... If your server picks a random session to send the 
>>>> response, why are you complaining it does not send the response to a 
>>>> specific session ? 
> Actually , it is not a complaint,

Sorry, bad choice of words from my part.

>  I was trying to give a background
> information to the problem. What I really want is a way to ensure the sender
> gets response to its request.
Get it now.

If you server receives a message, this message will be associated with a
session. If you have changed the session before the handler (ie, in a
filter), then the messageReceived( session, message ) will not allow you
to send back the response to the correct session.

Question : why don't you store the original session into your message,
so that you can send it back to the emitter ?

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Skywalker <le...@gmail.com>.
>>> I don't get it... If your server picks a random session to send the 
>>> response, why are you complaining it does not send the response to a 
>>> specific session ? 

Actually , it is not a complaint, I was trying to give a background
information to the problem. What I really want is a way to ensure the sender
gets response to its request.

>>> Unless you *want* to send the response to the sender, in some specific 
>>> case... 
Yes.

Regards.



--
View this message in context: http://apache-mina.10907.n7.nabble.com/Understanding-Apache-Mina-2-Request-Response-mapping-tp42337p42345.html
Sent from the Apache MINA User Forum mailing list archive at Nabble.com.

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Emmanuel Lécharny <el...@gmail.com>.
Le 30/05/2014 15:27, Skywalker a écrit :
> Sorry if I think I didnt make this clear, the server sends the response to
> another session. The server is a peculiar one, it sends response to client
> using any session available. This means, it will not necessarily use the
> request session to send its response.

I don't get it... If your server picks a random session to send the
response, why are you complaining it does not send the response to a
specific session ?

Unless you *want* to send the response to the sender, in some specific
case...

If you have a map of all the existing sessions, you can easily retrieve
the session that created the message, then send the response to this
specific response, no ?


Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Skywalker <le...@gmail.com>.
Sorry if I think I didnt make this clear, the server sends the response to
another session. The server is a peculiar one, it sends response to client
using any session available. This means, it will not necessarily use the
request session to send its response.

Actually, I am using the mina 2 in the  Apache Camel Mina2 component
<http://camel.apache.org/mina2.html>  .

Regards.



--
View this message in context: http://apache-mina.10907.n7.nabble.com/Understanding-Apache-Mina-2-Request-Response-mapping-tp42337p42343.html
Sent from the Apache MINA User Forum mailing list archive at Nabble.com.

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Emmanuel Lécharny <el...@gmail.com>.
Le 30/05/2014 14:42, Skywalker a écrit :
>>>> Check that the response is not sent to another session than teh one 
> whoch receivedthe message. 
>
> This is exactly what is happening. The response is sent to another session.

So there is (very likely) something in your code that makes the session
to be modified.
> I modified my ProtocolEncoder & ProtocolDecoder to log its session ids, and
> I found out the response to the request came on a differnet session id.
>
> My question is, is there a way to map the response to its original request?
As I said, in the handler, you do session.write(your message), and this
very session is propagated to your handler when a message is accepted.
If somwhere in yoru code you change the session, then of course, the
targetted session willm be different than the session which received the
message.

Without having your code, it's hard to tell what can happen.


Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Skywalker <le...@gmail.com>.
>>> Check that the response is not sent to another session than teh one 
whoch receivedthe message. 

This is exactly what is happening. The response is sent to another session.
I modified my ProtocolEncoder & ProtocolDecoder to log its session ids, and
I found out the response to the request came on a differnet session id.

My question is, is there a way to map the response to its original request?



--
View this message in context: http://apache-mina.10907.n7.nabble.com/Understanding-Apache-Mina-2-Request-Response-mapping-tp42337p42339.html
Sent from the Apache MINA User Forum mailing list archive at Nabble.com.

Re: Understanding Apache Mina 2 Request/Response mapping

Posted by Emmanuel Lécharny <el...@gmail.com>.
Le 30/05/2014 13:59, Skywalker a écrit :
> Hi all,
>
> I need help to understanding how Apache Mina 2 maps responses to requests.
> It appears it matches responses to their respective requests by assuming the
> responses will come back on the same socket.
right.
>
> e.g.
> If requests to server leaves on lets say Local Address: /192.168.0.10:53217
> i.e. ProtocolEncoder's session.getLocalAddress(), Apache mina expects
> response on the Local Address: /192.168.0.10:53217 i.e. ProtocolDecoder's
> session.getLocalAddress()
>
> However, I have a situation where the service responds to any available
> socket, e.g. the response could be on Local Address: /192.168.0.10:53282.
No. Never.
>
> I realize Mina is unable to map this response, and I am unable to get this
> response. How do I use something else to map request and response other than
> socket id.

MINA use the concept of Session. A Session is created everytime a remote
host connects to a server. The session is associated to the socket.
Whenever a message arrives on a socket, MINA selects the session
associated to this socket, then propagate the message to the handler,
which can/may send back a response, which is again associated to the
session, thus to the socket. There is no way a session can send a
message tp another socket than the one the session is associated to.

Check that the response is not sent to another session than teh one
whoch receivedthe message.