Cettia 1.0.0-RC1 released

wrote this on

I’m happy to announce the release of the Cettia 1.0.0-RC1 (Cetita Protocol 1.0.0-RC1, Cettia Java Server 1.0.0-RC1 and Cettia JavaScript Client 1.0.0-RC1). Based on the feedback, we added a small helper to resolve HttpSession from Servlet applications.

HttpSessionResolver httpSessionResolver = new HttpSessionResolver();
HttpSession httpSession = httpSessionResolver.resolve(socket);

Please test this release so that we can handle any issues before releasing GA. And, here’s one more thing.

It’s time to write the reference application and tutorial that demonstrate how to use the Cettia to develop a real-time web application. I guess it will be yet yet another Slack or Gitter ;) Of course, the source code will be open sourced under the Apache 2.0 license.

We are going to define the application details based on the features of the Cettia, choose the tech stack based on the popularity in the Java ecosystem, and so on. If you are interested, feel free to share your thought on this.

You can share your thought at this post.

Here’s the full changelog:

As always, please let us know if you have any question or feedback.


Cettia JavaScript Client 1.0.0-Beta2 released

wrote this on

Cettia JavaScript Client 1.0.0-Beta2 has been released. This release brings support for bundlers such as webpack, Browserify or Rollup.

Kudos to @DDKnoll for the great work. For the details of how to make Cettia work with bundlers, see this pull request.

To require the module for a browser bundle:

import cettia from "cettia-client/cettia-bundler"; // ES6 way
var cettia = require('cettia-client/cettia-bundler'); // CommonJS way

As of this release, for the sake of easy management, we have dropped support for Asynchronous Module Definition (AMD) and Bower and made a decision to use unpkg that serves files from npm packages as a CDN. Accordingly, cettia.min.js has been renamed to cettia-browser.min.js and is available at https://unpkg.com/cettia-client@1.0.0-Beta2/cettia-browser.min.js.

As always, please let us, Cettia Groups, know if you have any question or feedback.


Cettia 1.0.0-Beta1 released

wrote this on

Finally, all functionalities of Cettia 1.0 are implemented. Accordingly, Cetita Protocol 1.0.0-Beta1, Cettia JavaScript Client 1.0.0-Beta1 and Cettia Java Server 1.0.0-Beta1 have been released. This release focuses on binary event which allows to exchange binary data without using binary-to-text encoding and is one of features that many users have requested.

So far, you have had to serialize binary to text and send that text data to send binary, and receive text data and deserialize that text to binary to read binary, using an binary-to-text encoding scheme like Base64. It has inevitably brought about performance degradation as well as payload size increase. Moreover, you have had to figure out which events handle binary in advance and do serialization and deserialization manually.

Thanks to MessagePack which is a schemaless binary interchange format, now it is possible to deal with binary as a first-class citizen. If a given data or its one of properties is evaluated as binary, it will be internally serialized and deserialized according to MessagePack instead of JSON. Besides, it’s designed to work with any binary interchange format so you can let client determine an interchange format it will use e.g. BSON for Rust client and MessagePack for Go client per connection. Just let us know your needs. Anyway, here the most important thing is you don’t need to know about this at all.

Let’s take a look at the new feature. In the following example, both client-side and server-side sockets send text, binary and composite event to their counterpart on open event.

JavaScript Client

// In Node.js, replace 'cettia' with 'require("cettia-client")'
var socket = cettia.open(uri);
socket.on("open", function() {
  // String object is text
  socket.send("discard", "test");

  // According to W3C Encoding standard https://encoding.spec.whatwg.org/
  // encoder.encode takes text and returns binary in the form of ArrayBuffer
  var encoder = new TextEncoder();
  // In Node.js, replace 'encoder.encode("test")' with 'new Buffer("test")'
  socket.send("discard", encoder.encode("test"));

  // Even composite data including both text and binary can be exchanged
  socket.send("discard", {text: "test", binary: encoder.encode("test")});
});
// Prints all received data
socket.on("discard", function(data) {
  console.log(data);
});

Java Server

Server server = new DefaultServer();
server.onsocket((ServerSocket socket) -> {
  socket.onopen((Void v) -> {
    // String instance is text
    socket.send("discard", "test");

    // Byte array is binary
    socket.send("discard", "test".getBytes());

    // ByteBuffer is regarded as binary as well
    socket.send("discard", ByteBuffer.wrap("test".getBytes());

    // Even POJO as well as plain map including both text and binary can be exchanged
    socket.send("discard", new LinkedHashMap<String, Object>() {{
      put("text", "test");
      put("binary", "test".getBytes());
    }});
  });
  // Prints all received data
  socket.on("discard", (Object data) -> System.out.println(data));
});

Also, cettia.js’s size is notably reduced from 5.18KB to 4.6KB minified and gzipped by dropping support for Internet Explorer 6-8 and now works pretty well in Node 4/5.

Here’s the full changelog:

As always, please let us know if you have any question or feedback.


Cettia Java Platform is now Asity

wrote this on

Cettia Java Platform is now called Asity, which is created to run Java web applications on any platform on top of the Java Virtual Machine seamlessly. Today, Asity 1.0.0-Beta1 and accordingly Cettia Java Server 1.0.0-Alpha3 are released.

Asity is a lightweight abstraction layer for I/O frameworks which is designed to build applications that can run on any full-stack framework, any micro framework or any raw server on the JVM.

With Asity, you can build I/O framework-agnostic applications on the JVM with ease. Now an application based on Asity can run on Atmosphere, Grizzly, Java WebSocket API, Netty, Play, Servlet and Vert.x transparently.

Visit the asity.cettia.io for full documentation.

How to migrate

Here’s how to migrate from Cettia Java Platform 1.0.0-Alpha1 to Asity 1.0.0-Beta1. Just rename the followings:

  • GAV from io.cettia.platform:cettia-platform-xxx:1.0.0-Alpha1 to to io.cettia.asity:asity-xxx:1.0.0-Beta1.
  • Package from io.cettia.platform to io.cettia.asity.
  • Class from CettiaXXX to AsityXXX.

Please let us, Cettia Groups, know if you have any question or feedback.


Cettia 1.0.0-Alpha2 released

wrote this on

I’m pleased to announce that Cetita Protocol 1.0.0-Alpha2, Cettia JavaScript Client 1.0.0-Alpha2 and Cettia Java Server 1.0.0-Alpha2 have been released. The theme of this release is offline application, which provides a flexible way to deal with disconnection making it highly annoying to build real-time application.

In the real world, losing connection is not uncommon so that it is pretty important to make applications relying on full-duplex connection functional while offline in some way. For example, users lose connection every time they navigate from one page to another page and may lose network while on the move. Even if the time between disconnection and reconnection is very short, it’s true that any message can’t be sent and received after every disconnection and authentication which is a process to verify a user is who they say they are should be done and messages which couldn’t be sent and received meanwhile should be synchronized after every reconnection. Also if reconnection doesn’t occur for a long time, these messages might have to be sent through each user’s email.

To solve such problems, it has been required to design and implement application’s own protocol on top of the full duplex connection. With this feature, you can handle sockets regardless of their online/offline state as well as deal with such issues with ease just by handling some reserved socket events. Moreover, a reference to socket is not affected by disconnection and reconnection at all and doing authentication once is enough for socket. Of course, it applies to every transport not just HTTP based ones.

Let’s take a look at the new feature through code snippet.

JavaScript Client

var socket = cettia.open(uri, {
    // 'name' option allows for the socket of the next page to inherit the lifecycle of the socket of the current page
    // This means the server can cache events which couldn't be sent to the socket of the previous page 
    // due to temporary disconnection during page navigation and send them to the socket of the next page on reconnection
    // With this option, you don't need to follow single page application model to workaround such issues
    name: "main"
});

// A queue containing events the client couldn't send to the server while disconnection
var cache = [];

// Fired when the server issues a new id for this socket as the beginning of the new lifecycle and the end of the old lifecycle
// The 'open' event always follows this event but not vice versa
socket.on("new", function() {
    // You can reset resources having been used for the old lifecycle for the new lifecycle here
    cache.length = 0;
});

// Fired when the underlying transport establishes a connection
socket.on("open", function() {
    // Now that communication is possible, you can flush the cache
    while(socket.state() === "opened" && cache.length) {
        // Removes the first event from the cache and sends it to the server one by one
        var args = cache.shift();
        socket.send.apply(socket, args);
    }
});

// Fired if some event is sent via this socket while there is no connection
socket.on("cache", function(args) {
    // You can determine whether or not to cache this arguments used to call the 'send' method
    // For example, in some cases, you may want to avoid caching to deliver live data in time
    cache.push(args);
});

// You don't need to pay attention to socket's online/offline state at all
// Internally, it will be delegated to the underlying transport while online and the 'cache' event while offline
socket.send("event", data);

Java Server

// Fired when a socket has been created as the beginning of the lifecycle
// However the handshake is not performed yet and it is not allowed to exchange events
server.onsocket(new Action<ServerSocket>() {
    @Override
    public void on(final ServerSocket socket) {
        // You can authenticate a given socket here e.g. using token-based approach or cookie-based approach
        final Map<String, String> authentication = new TokenVerifier().verify(new Uri(socket.uri()).parameter("token"));

        // Once is enough because this reference is unaffected by disconnection and reconnection
        socket.tag(authentication.get("username"));
        // Then, it's possible to send events to a specific user who may have used multiple devices by username
        // The given socket represents a specific device like desktop, phone, tablet and so on
        // e.g. server.byTag("flowersinthesand", socket -> socket.send("directmessage", "Hello there!"));
        
        // A queue containing events the server couldn't send to the client while disconnection
        final Queue<Object[]> cache = new ConcurrentLinkedQueue<>();
        
        // Fired when the handshake is performed successfully
        socket.onopen(new VoidAction() {
            @Override
            public void on() {
                // Now that communication is possible, you can flush the cache
                while (socket.state() == ServerSocket.State.OPENED && !cache.isEmpty()) {
                    // Removes the first event from the cache and sends it to the client one by one
                    Object[] args = cache.poll();
                    socket.send((String) args[0], args[1], (Action<?>) args[2], (Action<?>) args[3]);
                }
            }
        });

        // Fired if some event is sent via this socket while there is no connection
        socket.oncache(new Action<Object[]>() {
            @Override
            public void on(Object[] args) {
                // You can determine whether or not to cache this arguments used to call the 'send' method
                // For example, in some cases, you may want to avoid caching to deliver live data in time
                cache.offer(args);
            }
        });

        // Fired if the socket has been closed for a long time i.e. 1 minute and deleted from the server as the end of the lifecycle
        // A deleted socket can't be and shouldn't be used
        socket.ondelete(new VoidAction() {
            @Override
            public void on() {
                // If the cache is not empty, that is to say, there are still some messages user should receive
                // you can send an email to notify user or store them to database for user to check on next logging in
                if (!cache.isEmpty()) {
                    Account account = Account.findByUsername(authentication.get("username"));
                    // Assumes this method checks if user have not really received the unread messages
                    // or some of them through other devices or other sockets and sends an email 
                    // to notify user of the final unread messages if they exist
                    account.notifyUnreadMessages(cache);
                }
            }
        });        
    }
});
    
// You can pass a socket action to server at any time not paying attention to given socket's online/offline state
server.all(new Action<ServerSocket>() {
    @Override
    public void on(final ServerSocket socket) {
        // It will be delegated to the underlying transport while online or the cache event while offline
        socket.send("event", data);
    }
});

For your information, TokenVerifier, Uri and Account are imaginary classes to help describe a scenario matching with this feature well. As you can see that the above code snippets are just boilerplate, we have agonized over introducing helper classes to remove these boilerplate but have decided to wait for the community’s feedback. So don’t hesitate to give us your thought about this.

Here’s the full changelog:

As always, please let us, Cettia Groups, know if you have any question or feedback.


Cettia 1.0.0-Alpha1 released

wrote this on

After a year and a half of research and experiment, it is my pleasure to announce that the first alpha of Cettia, a real-time web application framework, is now available.

Cettia is a new web framework to write real-time web application and service based on its own polyglot protocol built over transport such as HTTP and WebSocket. Cettia focuses on providing reliable full duplex connection and making the best use of it for modern enterprise applications so that teams can focus on event handling itself without unnecessary ties to low-level details and integrate application with any high-level technologies or patterns for enterprise application with ease.

The Cettia project consists of protocol and implementations and as implementation Java Server and JavaScript Client are provided. Please note that each project has many more useful features besides its name suggests.

Here’s a very simple example demonstrating essential functionalities. For working example, please refer to the quick start guide of Java Server and JavaScript Client or visit repository for a lot of examples.

Java Server

final Server server = new DefaultServer();
server.onsocket(new Action<ServerSocket>() {
    @Override
    public void on(final ServerSocket socket) {
        socket.on("echo", new Action<String>() {
            @Override
            public void on(String data) {
                socket.send("echo", data);
            }
        });
        socket.on("chat", new Action<String>() {
            @Override
            public void on(String data) {
                server.all().send("chat", data);
            }
        });
    }
});
// And bridge the above server to your favorite platform like 
// Atmosphere, Grizzly, Netty, Play, Servlet, Vert.x and so on

JavaScript Client

var socket = cettia.open("http://localhost:8080/cettia");
socket.on("open", function() {
    socket.send("echo", "An echo message");
    socket.send("chat", "A chat message");
});
socket.on("echo", function(data) {
    console.log("on echo event:", data);
});
socket.on("chat", function(data) {
    console.log("on chat event:", data);
});

Here is a summary of key features in Cettia overall:

  • Based on protocol - Real-time web will be everywhere soon. You will need more features to write a just simple real-time webapp. The separated protocol is the baseline to build such features.
  • Polyglot - It’s not just for Java and JavaScript but for any language. With the reference implementation and test suite, you can easily not only implement the protocol in any language but also verify your client and server.
  • Standards - As component of the protocol, RFC and W3C standards are mainly adopted. Just use existing implementation as desired. You don’t need to reinvent the wheel.
  • Transport layer - Any transport technology besides WebSocket and HTTP can be used to bridge client and server as long as it meets requirements of Cettia transport. Along that way, you can control sockets backed by hetero transports through one server.
  • Event not message - The unit of data to be sent and received from the semantic point of view is an event object associated with a customizable type, which is easy to compose a controller from MVC.
  • Remote Procedure Call - It also allows to attach callbacks in sending event and to call those callbacks with the result of the event processing in receiving event. It’s useful where request-response model is more suited than notification model.
  • Server and Socket - All the interfaces you need to know to handle server are Server producing and managing socket and Socket representing the remote client. Select some sockets from server and do something with them like manipulating DOM using jQuery.
  • Entity as well as connection - Tag gives you a way to handle a specific entity in the real world as an identifier of a group of sockets. For example, you can use it to model a user logged in using multiple devices or subscribers to a specific topic.
  • Dependency injection friendly - A use case with DI framework is definite. Define a server as a singleton and inject it wherever you want to handle socket just like when using EntityManager from JPA.
  • Scalability - A publish-subscribe messaging system is enough to scale your application. Because servers don’t share any data, you can scale application horizontally with ease as well as don’t need to prepare for data grid system or NoSQL solution.
  • Run on any platform - Because server is built on a simple abstraction layer for various application platforms running on JVM, you can run your application on any supported platform seamlessly. Now Atmosphere, Grizzly, Java WebSocket API, Netty, Play, Servlet and Vert.x are supported.
  • Lightweight - JavaScript client takes 5.1KB minified and gzipped. Compare it to others: Socket.IO 1.3.4 - 19.96KB, Sockjs 0.3.4 - 10.09KB and Autobahn latest - 37.17KB.
  • Wide browser support - Wherever jQuery 1 is available, you can write a real-time webapp. A multitude of browsers are supported according to jQuery 1’s browser support policy embracing IE 6.
  • Proved flexibility - It is flexible enough to integrate with any technologies, patterns or frameworks for enterprise application with ease, which has been proved by a lot of examples.
  • 100% open source - All projects are distributed under the Apache Software License 2.0 which is one of the most flexible open source licenses.

And here is the roadmap of Cettia 1.0:

  • Offline application - It is necessary to handle sockets whose connection is disconnected for a little while. This feature will provide events you can utilize to deal with such case properly by making socket to be backed by multiple transports not just one. cettia-protocol#1
  • Binary support - Cettia transport can carry binary data but how to make use of it for event object is not yet determined. With this feature, you will be able to use an object containing binary data as event’s data and exchange it without binary-to-text conversion.
  • Complete Play support - The current implementation written in Play’s Java API misses some functionalities. To fix that issue, new implementation will be written in Play’s Scala API and also come with helpers making it easy to bridge application and Play. cettia-java-platform#3
  • More examples - A reference application to illustrate how Cettia can be used to build modern web application and more archetype applications to demonstrate how Cettia can be integrated with other technologies and frameworks will be provided.

For full documentation and information on Cettia, please visit the website.

Thanks for all the feedback from early adopters. The feedback has been and will be very important to us, so please feel free to get in touch with us, Cettia Groups, if you have any question or feedback.