Using Makai event model from HTML 5 Calling JavaScript from Java part III

From Resin 4.0 Wiki

(Difference between revisions)
Jump to: navigation, search
Rick (Talk | contribs)
(Created page with "Makai allows you to receive method calls from services. You can do this even with JavaScript/HTML 5 clients. In JAMP/Makai when you are sending a message, your default addre...")

Latest revision as of 02:58, 28 June 2013

Makai allows you to receive method calls from services.

You can do this even with JavaScript/HTML 5 clients.

In JAMP/Makai when you are sending a message, your default address is "me".

The "me" address is similar to the "this" reference in Java.

"me" means my local address.

To register for a callback, you have to know you actual Makai address.

You get this actual address from the link service which is under /amp/link/server.

AMP by the way stands for Actor Model Protocol, and is the underpinning of JAMP, HAMP and CHAMP, which are three different channel protocols that work with Makai.

For a client to ask for his AMP address he needs to formulate the following JAMP method call as follows:

["query",{},"me",2,"/amp/link/server","publishChannel","/reply-address"]

The server will respond with an address like the following:

["reply",{},"me",2,"/resin/jamp/D+IpaDeAAAC/reply-address"]

The string /resin/jamp/D+IpaDeAAAC/reply-address is your clients address.

Now a server side service can start to invoke JAMP methods in your client.

Let's say you have a service defined as follows:

@Service("/taskService")
@Export
@Singleton
@Startup
public class TaskService {

    private List<Callback> callbacks = new ArrayList<>();


    public void addCallback(@Service Callback cb) {
        System.out.println("Add callback " + cb);
        callbacks.add(cb);

        System.out.println("size of callbacks " + callbacks.size());

    }

    public void fireMessage(String message) {
        System.out.println("FIRE MESSAGE " + message);

         for (Callback cb : callbacks) {
             System.out.println("server says:" + message);

             cb.messageFromServer("server says:" + message);
         }

        System.out.println("fire callbacks " + callbacks.size());

    }
...

package com.example;

public interface Callback {

    void messageFromServer(String msg);

}

callbacks is a list of callbacks. Calling addCallback adds an instance of Callback to the callbacks list.

Then when fireMessage is invoked it will iterate over the list of callbacks calling each of them.

Java or JavaScript clients could register for these callbacks.

For a JavaScript client to register as a callback they merely need to invoke the following:

["send",{},"/taskService","addCallback","/resin/jamp/D+IpaDeAAAC/reply-address"]

What follows is a complete example that finds its AMP address, and register for a callback as described above in HTML5/JavaScript.

<html>

<head>

    <title>Todo List Client</title>

    <link rel="stylesheet" type="text/css" href="css/style.css"
          media="screen" />


    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>


    <script type="text/javascript">
        var ENTER_KEY = '13';
        var messageId = 1;
        var calls = new Array();

        var myAddress = "me";

        var todoService = {
            version : "1.0",
            webSocketURL : buildWebSocketURL(),
            webSocket : null,//WebSocket
            userName : null
        };


        function sendJampMessage(serviceName, methodName, args) {

            doInvokeJampMethod("send", serviceName, methodName, null, args);

        }

        function invokeJampMethod(serviceName, methodName, callback, args) {
            doInvokeJampMethod("query", serviceName, methodName, callback, args);
        }

        function doInvokeJampMethod(messageType, serviceName, methodName, callback, args) {

            var list = new Array();
            list.push(messageType);
            list.push({});
            if (messageType === "query") {
                list.push("me");
                list.push(messageId);
            }
            list.push(serviceName);
            list.push(methodName);
            for (var index=0; index < args.length; index++) {
                var obj = args[index];
               list.push(obj);
            }

            if (todoService.webSocket.readyState == WebSocket.OPEN) {

                todoService.webSocket.send(JSON.stringify(list));

                todoService.status(JSON.stringify(list));

                $("#tasks").prepend("<p style='color:black'>"  + JSON.stringify(list) + "</p>");


                if (messageType === "query") {
                    var call = {
                        queryId: messageId,
                        "serviceName": serviceName,
                        "methodName" : methodName,
                        func: callback,
                        "args": args};

                    calls[messageId]=call;
                }


            } else {
                todoService.status("websocket  unable to send ");
            }
            messageId++;
        }


        function buildWebSocketURL() {
            var url = document.URL;
            var parts = url.split('/');
            var scheme = parts[0];
            var hostPort = parts[2];
            var wssScheme = null;


            if (scheme=="http:") {
                wssScheme="ws:";
            } else if (scheme=="https:") {
                wssScheme="wss:";
            }

            wssUrl = wssScheme + "//" + hostPort  + "/simple/jamp";

            //wssUrl = "ws://localhost:8080/tasks/jamp";

            return wssUrl;

        }



        function todo_createTask(taskName) {
            var myargs = new Array();
            myargs.push(taskName);
            invokeJampMethod("/taskService", "addTask", showReturnFromServer, myargs);
        }

        function showReturnFromServer(data, call) {
            $("#tasks").prepend("<p style='color:blue'>"  + data + "</p>");
            var taskName = call.args[0];
            $("#taskList").append("<p style='color:blue'>"  + taskName + "</p>");
            invokeJampMethod("/taskService", "tasks", showAllItems, new Array());

        }

        function showAllItems(data, call) {
            var index = 0;
            var task = "";

            $("#tasks").prepend("<p style='color:blue'>"  + data + "</p>");

            $("#taskList").text="";

            for (index =0; index < call.returnValue.length;  index++) {
                task = call.returnValue[index];
                $("#taskList").append("<p style='color:green'>"  + task + "</p>");
            }

        }

        function saveReturned(data, call) {
            $("#tasks").prepend("<p style='color:blue'>SAVED!</p>");

            $("#tasks").prepend("<p style='color:blue'>"  + data + "</p>");

        }

        function fireReturned(data, call) {
            $("#tasks").prepend("<p style='color:blue'>FIRE RETURNED!</p>");

            $("#tasks").prepend("<p style='color:blue'>"  + data + "</p>");

        }

        function readReturned(data, call) {
            $("#tasks").prepend("<p style='color:blue'>READ!</p>");

            $("#tasks").prepend("<p style='color:blue'>"  + data + "</p>");

            invokeJampMethod("/taskService", "tasks", showAllItems, new Array());


        }

        function registerReturned(data, call) {
            $("#tasks").prepend("<p style='color:blue'>REGISTER RETURNED!</p>");

            $("#tasks").prepend("<p style='color:blue'>"  + data + "</p>");

            $("#tasks").prepend("<p style='color:blue'>"  + call.returnValue + "</p>");


            myAddress = call.returnValue;

            $("#myAddress").text(myAddress);






        }


        function todo_openWebSocket() {
            todoService.webSocket = new WebSocket(todoService.webSocketURL);
            var socket = todoService.webSocket;

            socket.onmessage = function(msg) {
                todoService.onMessage(msg);
            }

            socket.onerror = function(errorEvent) {
                todoService.onError(errorEvent);
            }

            socket.onopen = function() {
                todoService.onOpen();
            }
            socket.onclose = function(closeEvent) {
                todoService.onClose(closeEvent);
            }

        }


        function todo_onOpen() {
            todoService.status("Todo SIMPLE Client (logged in)");
            $('#header').text(
                    "Todo Client (logged in...)");

            $("#inputArea").show(500);
            $("#statusBar").show(500);
            $("#todoNameInput").focus();
        }


        function todo_Status(message) {
            $("#statusBar").show(500);
            $('#statusBarPara1').text(message);

            $("#statusBar").show(500);

        }

        function todo_onMessage(msgEvent) {
            $('#onMessageBar').text(msgEvent.data);


            var list = JSON.parse(msgEvent.data);

            if (list[0] == "reply") {
                replyRecieved(list[3], list[4], msgEvent.data);
            } else {
                $("#tasks").prepend("<p style='color:blue'> CALL FROM SERVER"  + msgEvent.data + "</p>");

            }

        }

        function replyRecieved (qid, returnValue, data) {
            var call = calls[qid];
            call.returnValue = returnValue;
            call.func(data, call);

        }


        function todo_onError(msg) {
//            $('#statusBarPara1').text(" Websocket error :" + JSON.stringfy(msg));
//            $("#statusBar").show(500);
        }


        function todo_onClose(closeEvent) {
            $('#header').text(
                    "Todo Client (not connected)  " );


            $('#statusBarPara1').text(" not logged in. " +
                    ":: Reason: " + closeEvent.reason +
                    " Code: " + closeEvent.code);

            $("#inputArea").hide(500);
            $("#statusBar").show(500);

        }

        todoService.open = todo_openWebSocket;
        todoService.onMessage = todo_onMessage;
        todoService.onOpen = todo_onOpen;
        todoService.onClose = todo_onClose;
        todoService.onError = todo_onError;
        todoService.createTask = todo_createTask;
        todoService.status = todo_Status;

        $(document).ready(function() {

            todoService.open();




            $("#inputArea").show();



            $("#statusBar").click(function() {
                $("#statusBar").hide(300);
            });

            $("#save").click(function() {
                $("#tasks").prepend("<p style='color:red'>save called</p>");

                invokeJampMethod("/taskService", "save", saveReturned, new Array());

            });

            $("#read").click(function() {
                $("#tasks").prepend("<p style='color:red'>read called</p>");

                invokeJampMethod("/taskService", "read", readReturned, new Array());

            });

            $("#showTasks").click(function() {
                $("#tasks").prepend("<p style='color:red'>show tasks</p>");

                invokeJampMethod("/taskService", "tasks", showAllItems, new Array());
            });


            $("#fireEvent").click(function() {
                $("#tasks").prepend("<p style='color:red'>fire events</p>");


                var args = new Array();
                args.push("HI MOM!");
                invokeJampMethod("/taskService", "fireMessage", fireReturned, args);
            });





            $("#linkAddress").click(function() {
                $("#tasks").prepend("<p style='color:red'>Link Address called</p>");

                //session.getBasicRemote().sendText("[\"query\",{},\"me\",1,\"/amp/link/server\",\"publishChannel\",\"/reply-address\"]");


                var args = new Array();
                args.push("/reply-address")
                invokeJampMethod("/amp/link/server", "publishChannel", registerReturned, args);

            });

            $("#registerCallback").click(function() {
                $("#tasks").prepend("<p style='color:red'>Adding Calback</p>");

                var args = new Array();
                args.push(myAddress);
                sendJampMessage("/taskService", "addCallback", args );


            });


            $("#todoNameInput").keypress(function(event) {

                var keycode = (event.keyCode ? event.keyCode : event.which);
                if (keycode == ENTER_KEY) {
                    var textMessage = $("#todoNameInput").val();

                     $("#todoNameInput").val("");
                     $("#hint").hide(500);
                     todoService.createTask(textMessage);
                }
                event.stopPropagation();
            });


            invokeJampMethod("/taskService", "tasks", showAllItems, new Array());


            $("#myAddress").val(myAddress);

        });
    </script>

</head>

<body>

<h1 id="header">Todo</h1>


<div id="statusBar">
    <p id="statusBarPara1">Welcome to Todo App, Click to hide</p>
    ME == <p id="myAddress">me</p>
</div>

<div id="buttons">
    <button id="showTasks">Show Tasks</button>
    <button id="save">Save</button>
    <button id="read">Read</button>
    <button id="linkAddress">Link Address</button>
    <button id="registerCallback">Register Callback</button>
    <button id="fireEvent">Fire Event</button>

</div>

<div id="onMessageBar">
    <p id="onMessageBar1"></p>
</div>


<div id="inputArea">
    <p id="hint">Enter a new task in here:</p>
    <input id="todoNameInput" type="text" value="" />
</div>


<div id="taskListDiv">
    <p id="taskList"></p>
</div>

<div id="tasksDiv">
    <p id="tasks"></p>
</div>


</body>

</html>
Personal tools
TOOLBOX
LANGUAGES