6 Replies Latest reply on Feb 8, 2012 12:21 PM by fvitorc

    SessionContext and LocalContext within RPC

    fvitorc

      Hi,

       

      I've seen in the reference guide that one can get the SessionContext or the LocalContext using the Message object.

      But in a RPC there is no Message object. How can we get access to those contexts within a RPC?

       

      Regards,

      Vitor.

        • 1. Re: SessionContext and LocalContext within RPC
          csa

          I assume your use case for this is to get access to the HTTP session? I have created a JIRA for this a while back: https://issues.jboss.org/browse/ERRAI-157

           

          If it's for the session object, you could add a servlet filter and store the object in a ThreadLocal, given you use the SimpleDispatcher.

          • 2. Re: SessionContext and LocalContext within RPC
            fvitorc

            Not actually. I wanted acess to the queue id of the client invoking the RPC. I guess that information is in LocalContext right?

            I just put SessionContext in this discussion because those are the contexts provided by errai, so that would be a helpful information.

             

            Anyway, does errai have acess to the Message object just before invoking the RPC?

            I assume it does, and so, it would be possible to store the Message object in a ThreadLocal.

            Then from the RPC we can grab it, and access LocalContext and SessionContext.

             

            Regards,

            Vitor.

            • 3. Re: SessionContext and LocalContext within RPC
              csa

              There's currently no API you could use to get access to the message from within an RPC endpoint. Can you elaborate on the feature you want to implement? Maybe we can come up with an alternative.

              • 4. Re: SessionContext and LocalContext within RPC
                fvitorc

                Ok, so the first thing that comes into my mind in this situation is to use a ThreadLocal. Let me try to show a simple and ugly way to do this.

                As I've seen from the source code, RPCs are initiated from class ConversationalEndpointCallback, correct?

                 

                Let's add ThreadLocal to it:

                 

                private static ThreadLocal<Message> currentMessage = new ThreadLocal<Message>();

                 

                public static Message getCurrentMessage() {

                    return currentMessage.get();

                }

                 

                and right before the createConversation(message) statement, in the beginning of the try block, place this statement:

                try {

                    currentMessage.set(message);

                    createConversation(message)

                     ....

                 

                and create a finally block to the above try block like this:

                ...

                finally {

                    currentMessage.remove();

                }

                 

                Now, in our RPC service, we access the current message object using ConversationEndpointCallback.getCurrentMessage();

                It's ugly but it works. So let's make it look nice. We can use resource injection for that.

                 

                First, let's make getCurrentMessage() protected, so that only classes in the same package can access it.

                protected static Message getCurrentMessage() {

                    return currentMessage.get();

                }

                 

                Now, create an extension component in the same package as ConversationalEndpointCallback that will add bindings to a resource provider:

                 

                @ExtensionComponent

                public class MessageAccessorExtension implements ErraiConfigExtension {

                    @Override

                    public void configure(ErraiConfig config) {

                        config.addBinding(Message.class, new ResourceProvider<Message>() {

                            @Override

                            public Message get() {

                                return ConversationalEndpointCallback.getCurrentMessage();

                            }

                        });

                    }

                }

                 

                That's it. Now we add a provider to our RPC service and access the Message object through this provider:

                 

                @Service

                public class MyServiceImpl implements MyService {

                 

                    @Inject

                    private Provider<Message> message;

                 

                    @Override

                     public void doYourWork() {

                         Message m = message.get();

                    }

                 

                }

                 

                It would also be possible to add more bindings to simplify access of commonly used objects in RPC services, like:

                 

                @Override

                public LocalContext get() {

                    Message m = ConversationalEndpointCallback.getCurrentMessage();

                    return LocalContext.get(m);

                }

                @Override

                public SessionContext get() {

                    Message m = ConversationalEndpointCallback.getCurrentMessage();

                    return SessionContext.get(m);

                }

                 

                 

                What do you think of this solution?

                 

                Regards,

                Vitor.

                • 5. Re: SessionContext and LocalContext within RPC
                  csa

                  Nice! I think your solution would work. However, it seems there's an opportunity for us to provide a higher level abstraction for what you are trying to do. What is your exact use case for this? To identify the client? I am thinking we could make a provider for the context itself which could then be injected.

                  • 6. Re: SessionContext and LocalContext within RPC
                    fvitorc

                    Yes, I need to identify the client. What I need is a list of all users currently logged in, along with their respective queue id. There's no specific need for the Message object. But I know that with it I can get the LocalContext of the currently running RPC.

                     

                    Think of it as chat application (it's a little more complex than a chat application, but it serves as an example). When a user logs in, I register that user as logged in along with his queue id in a application scoped variable. So, if user A wants to send a private message to user B, I get the user B from the application scoped variable along with his queue id. With his queue id, it's now possible to send a message directly to user B.

                     

                    I can use my hack for the moment, but I am looking forward to see this feature in future releases.

                     

                    I've recently opened up another discussion about detecting user presence, because I need to know when a queue has been started or finished. But I still have no response for that.

                     

                    Regards,

                    Vitor.