Getting started with Makai/JAMP

From Resin 4.0 Wiki

Revision as of 08:50, 16 June 2013 by Rick (Talk | contribs)
Jump to: navigation, search

Brief introduction to Makai and JAMP

Makai (TM) is not the final name for this technology. Makai (TM) is a services model based on concepts of high speed, mechanical sympathy computing. Underneath the covers, Makai (TM) is a super charged race engine for maximizing throughput. It is an inherently non-blocking, multithreaded model. It is similar in concept to the LMAX disruptor, apartment thread model, actor model and active objects model. It is none of these, and it is all of these.

From a developer standpoint Makai (TM) allows you to write services that look like regular Java services. It takes care of thread management, marshaling (JSON or Hessian), and many more things that we will introduce later. Makai (TM) is super charged SOA. With Makai (TM), you can even turn on journaling and use its high speed, reliable async storage to manage all of your operational data with speeds up to 1,000,000 operations per second on commodity server hardware and several million operations per second with souped up servers.

Makai (TM) services that you write can be accessible within a JVM, or via REST or Websockets.


Example Java App to manage a TODO list

package example;


import io.makai.core.Export;
import io.makai.core.Service;

import java.util.HashSet;
import java.util.Set;


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

    TaskManager manager = new TaskManager();
    OwnerRepo repo = new OwnerRepo();
    Group group = new Group(repo, "shared");

    public String addTask(String taskName) {
          Task task = new Task(taskName);
          manager.addTask(group, task);
          return task.id();
    }

    public boolean changeDescription(String id, String description) {
        Task task = manager.getTaskBy(id);
        task.setDescription(description);
        return true;
    }


    public Set<TaskData> tasks() {
        Set<TaskData> taskData = new HashSet<>();

        for (Task task : manager.tasks()) {
            taskData.add(new TaskData(task)) ;
        }
        return taskData;
    }

}

Files for this project:

.
├── makaiExample.iml
├── pom.xml
├── taskListModel
│   ├── model.iml
│   ├── pom.xml
│   ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   │   └── example
│   │   │   │       ├── Group.java
│   │   │   │       ├── OwnerRepo.java
│   │   │   │       ├── Person.java
│   │   │   │       ├── Task.java
│   │   │   │       ├── TaskManager.java
│   │   │   │       ├── TaskOwner.java
│   │   │   │       └── Utils.java
│   │   │   └── resources
│   │   └── test
│   │       └── java
│   │           └── io
│   │               └── jamp
│   │                   └── example
│   │                       └── model
│   │                           └── TaskManagerTest.java
│   └── taskListModel.iml
└── taskListService
    ├── pom.xml
    ├── src
    │   └── main
    │       ├── java
    │       │   ├── example
    │       │   │   ├── TaskData.java
    │       │   │   └── TaskService.java
    │       │   └── io
    │       │       └── makai
    │       │           └── example
    │       ├── resources
    │       │   └── META-INF
    │       │       └── beans.xml
    │       └── webapp
    │           ├── META-INF
    │           │   └── MANIFEST.MF
    │           ├── WEB-INF
    │           │   └── resin-web.xml
    │           └── todo.html
    └── taskListService.iml

Support classes, Task.java and TaskManager.java

package example;


import java.util.Random;

public class Task {

    private static final String NULL = "NULL";

    private static int count =0;
    private long timestamp;
    private String objectId=NULL;
    private String name=NULL;
    private String description=NULL;
    private TaskOwner owner = TaskOwner.NO_OWNER;

    public Task task(String name) {
        Task task = new Task(name);
        return task;
    }
    public Task(String name) {
         this.timestamp = System.currentTimeMillis();
         this.name = name;
         this.objectId = String.format("%s-%s-%s-%s",
                 name, new Random().nextLong(), System.nanoTime(), count++);
    }

    public TaskOwner owner() {return owner;}
    public String id() {return objectId;}

    public void setOwner(TaskOwner owner) {
        this.owner = owner;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public boolean equals(Object o) {
        Task task = (Task) o;
        if (objectId != null ? !objectId.equals(task.objectId) : task.objectId != null) return false;
        return true;
    }

    @Override
    public int hashCode() {
        return objectId.hashCode();
    }

    @Override
    public String toString() {
        return "Task{" +
                "timestamp=" + timestamp +
                ", objectId='" + objectId + '\'' +
                ", name='" + name + '\'' +
                ", description='" + description + '\'' +
                ", owner=" + owner +
                '}';
    }

    public long getTimestamp() {
        return timestamp;
    }
}

package example;

import java.util.*;

public class TaskManager {

    private Set<Task> tasks = new HashSet<Task>();
    private transient Map<TaskOwner, Set<Task>> ownerToTaskMap = new HashMap<>();
    private transient Map<String, Task> idToTask = new HashMap<>();

    public void addTask(TaskOwner owner, Task task) {
        task.setOwner(owner);
        tasks.add(task);

        Set<Task> ownerTasks = ownerToTaskMap.get(owner);
        if (ownerTasks == null) {
            ownerTasks = new HashSet<>();
        }
        ownerTasks.add(task);
        idToTask.put(task.id(), task);

    }

    public void removeTask(Task task) {
        tasks.remove(task);
        idToTask.remove(task.id());

        Set<Task> ownerTasks = ownerToTaskMap.get(task.owner());
        if (ownerTasks == null) {
            ownerTasks = new HashSet<>();
        }
        ownerTasks.remove(task);

    }

    public Set<Task> tasks() {
        return tasks;
    }

    public Set<Task> listTasksForOwner(TaskOwner doer) {
        return ownerToTaskMap.get(doer);
    }

    public Task getTaskBy(String id) {
        return idToTask.get(id);
    }
}

<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 todoService = {
            version : "1.0",
            webSocketURL : buildWebSocketURL(),
            webSocket : null,//WebSocket
            userName : null
        };


        function invokeJampMethod(serviceName, methodName, callback, args) {

            var list = new Array();
            list.push("query");
            list.push({});
            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>");


                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  + "/tasks/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>");

        }


        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 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 {
            }

        }

        function replyRecieved (qid, returnValue, data) {
            var call = calls[qid];
            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);
            });

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

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

                    if (textMessage=="bye!") {
                        todoService.leaveChat();
                    } else {
                        $("#todoNameInput").val("");
                        $("#hint").hide(500);
                        todoService.createTask(textMessage);
                    }
                }
                event.stopPropagation();
            });
        });
    </script>

</head>

<body>

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


<div id="statusBar">
    <p id="statusBarPara1">Welcome to Todo App, Click to hide</p>
</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="tasksDiv">
    <p id="tasks"></p>
</div>

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


</body>

</html>


JAMP in a nutshell

["query",{},"me",1,"/taskService","addTask","buy milk"]

["reply",{},"me",1,"buy milk--4566919316225680390-1371372542772964000-7"]

["query",{},"me",2,"/taskService","addTask","call wife"]

["reply",{},"me",2,"call wife-7108026654197322644-1371372545793514000-8"]

Personal tools
TOOLBOX
LANGUAGES