3

Now I am learning Akka a little bit, but I can't understand the exact meaning of getSender(). In this official document, the method getSender() is used and the explanation is like

// Reply to original sender of message getSender().tell(msg + ":" + getSelf());

This seems to be a response method, so this actor has to respond to a actor who sent a message and that method is what does it actually. And I am confused because I don't understand whether getSender() affords the receiver actor or the sender actor. So, could you give me an explanation about it?

Thanks.

public class WebSocketActor extends UntypedActor {

/**
 * Actor's reference
 */
private final static ActorRef ref = Akka.system().actorOf(new Props(WebSocketActor.class));

/**
 * the list of those who should get messages
 */
Map<String, WebSocket.Out<JsonNode>> members = new HashMap<String, WebSocket.Out<JsonNode>>();

/**
 * a method adding a certain user
 * @param username a user name
 * @param in receive of WebSokcet
 * @param out sending of WebSocket
 * @throws Exception
 */
public static void join(final String username, WebSocket.In<JsonNode> in, WebSocket.Out<JsonNode> out) throws Exception {

    // causing JOIN event 
    Boolean result = (Boolean) Await.result(ask(ref, new Message(username, "", "", WebSocketEvent.JOIN, out), 1000), Duration.create(1, SECONDS));

    if(result) {
        // if a message is sent,MESSAGE event will occur.
        in.onMessage(new Callback<JsonNode>() {
            public void invoke(JsonNode event) {
                ref.tell(new Message(username, event.get("x").asText(), event.get("y").asText(), WebSocketEvent.MESSAGE, null), ref);
            }
        });
        // a close method when WebSocket is closed
        in.onClose(new Callback0() {
            public void invoke() {
                ref.tell(new Message(username, "", "", WebSocketEvent.QUIT, null), ref);
            }
        });
    } else {
        // sending an error
        ObjectNode error = Json.newObject();
        error.put("error", result);
        out.write(error);
    }
}

/**
 * the executable method when an event happens
 * @param message an event object
 * @throws Exception
 */
@Override
public void onReceive(Object message) throws Exception {

    // diciding whether the object is an event or not
    Option<Message> event = EventUtil.getEvent(message);
    if(event.isDefined()){
        Message m = event.get();
        switch (m.getEventType()) {
            // adding to members
            case JOIN:
                members.put(m.getUsername(), m.getChannel());
                getSender().tell(true, ref);
                break;
            // sending all
            case MESSAGE:
                WebSocketMessenger.notifyAll(m.getUsername(), m.getX(), m.getY(), members);
                break;
            // excluding someone from members
            case QUIT:
                members.remove(m.getUsername());
                break;
            default:
                unhandled(message);
                break;
        }
    }

}

}

In above code, in onReceive(Object message) method you can see the getSender() method. However, when the join(final String username, WebSocket.In<JsonNode> in, WebSocket.Out out) method is called, first the actor asks a new message of another actor, and then in onReceive(Object message) method, another actor answers with true by executing like getSender().tell(true, ref);. In this circumstance, getSender() gives the first actor who asked. Isn't it strange because the first actor who asked gives true to the another actor who should give true to the first actor? Your answer would be very useful, but I am still not clear, sorry.

EDIT: You said this doesn't work well, but it works. Are you familiar with PlayFramework? If so, it is totally straightforward to grasp a whole picture. This code is the controller's code which calls the join() method.

 public static WebSocket<JsonNode> ws() {
    final String username = session("username");
    return new WebSocket<JsonNode>() {
        @Override
        public void onReady(final WebSocket.In<JsonNode> in, final WebSocket.Out<JsonNode> out) {
            try {
                WebSocketActor.join(username, in, out);
            } catch (Exception e) {
                Logger.error("Can't connect WebSocket");
                e.printStackTrace();
            }
        }
    };
}
Kazuya Tomita
  • 667
  • 14
  • 34

1 Answers1

3

It simply returns a reference on the actor (ActorRef) that just sent the message you are currently handling.

Thus, it's a way for an actor to answer a message... in the code handling it.

In other words, If actor A send a message M1 to an actor B, when B calls getSender, it will return a reference on actor A.

edit after code provided:

The following won't work properly:

Boolean result = (Boolean) Await.result(ask(ref, new Message(username, "", "", WebSocketEvent.JOIN, out), 1000), Duration.create(1, SECONDS));

You can't ask() and expect a response from an actor, if you're not actor yourself. The join() method is static and completely executed outside the actor system! it could (and should) be in another class.

This is why getSender() doesn't makes sense here : there is no "akka" sender.

Yuri
  • 4,254
  • 1
  • 29
  • 46
Fabien Benoit-Koch
  • 2,784
  • 2
  • 21
  • 33
  • I understand the return value of the method `getSender()`. However, I am still not confused with some points, please see my additional question if possible. – Kazuya Tomita Jan 21 '17 at 11:14
  • Okay you're confused because your class is mixing up two concerns : *websocket event handling* with *actor message handling*. Moreover, the ask() in the join method won't work - because the ask() is not called by an akka actor, but a static method! therefore, the getSender() won't return an actor reference, since the origin of the message is not an actor. Do you see what i mean? – Fabien Benoit-Koch Jan 21 '17 at 13:56
  • There are vast amount of information, let me see... First, what do you mean by _websocket event handling with actor message handling_? Can you be more specific? Second, I can understand what you say maybe,namely it is not good, not following Akka's theory. And in fact what should I interpret this code? Do you have any idea? – Kazuya Tomita Jan 21 '17 at 15:03