All Projects → cettia → cettia-java-server

cettia / cettia-java-server

Licence: Apache-2.0 license
A full-featured real-time web application framework for Java

Programming Languages

java
68154 projects - #9 most used programming language
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to cettia-java-server

comet
A http long polling comet implementation for nodejs and browser
Stars: ✭ 20 (-50%)
Mutual labels:  comet, long-polling
morfeo
Morfeo is a tool to build design systems based on a theme. It helps you to follow a design language and write consistent UIs, whatever it is the framework of your choice. It's easy to use and, with the browser extension, your theme and your components are automatically documented.
Stars: ✭ 30 (-25%)
Mutual labels:  framework-agnostic
fence
🔰 Framework-agnostic package who provides powerful ACL abilities to JavaScript
Stars: ✭ 64 (+60%)
Mutual labels:  framework-agnostic
lightning-hydra-template
PyTorch Lightning + Hydra. A very user-friendly template for rapid and reproducible ML experimentation with best practices. ⚡🔥⚡
Stars: ✭ 1,905 (+4662.5%)
Mutual labels:  comet
namecase
This package allows you to convert names into the correct case where possible.
Stars: ✭ 70 (+75%)
Mutual labels:  framework-agnostic
permissionary
Tiny and framework-agnostic role-based permission management using composition over inheritance
Stars: ✭ 19 (-52.5%)
Mutual labels:  framework-agnostic
repl
Framework Agnostic REPL For Node.js. Used by AdonisJS
Stars: ✭ 76 (+90%)
Mutual labels:  framework-agnostic
vercel-toast
💬 Framework-agnostic vercel design's toast component (≈1KB Gzipped)
Stars: ✭ 67 (+67.5%)
Mutual labels:  framework-agnostic
xoid
Framework-agnostic state management library designed for simplicity and scalability ⚛
Stars: ✭ 96 (+140%)
Mutual labels:  framework-agnostic
aiosfstream
Salesforce Streaming API client for asyncio
Stars: ✭ 46 (+15%)
Mutual labels:  comet
comet-server
CppComet - easy to use and fast in work.
Stars: ✭ 57 (+42.5%)
Mutual labels:  comet
glory
The world fastest framework agonistic CSS-in-JS library. Available in any frontend framework you use, like React, Vue and Svelte.
Stars: ✭ 20 (-50%)
Mutual labels:  framework-agnostic
Restbed
Corvusoft's Restbed framework brings asynchronous RESTful functionality to C++14 applications.
Stars: ✭ 1,551 (+3777.5%)
Mutual labels:  comet
magnetar
A framework-agnostic syncing solution that auto-connects any DB/API with your local data store and has optimistic-UI built in 🌟
Stars: ✭ 36 (-10%)
Mutual labels:  framework-agnostic
Router5
Flexible and powerful universal routing solution
Stars: ✭ 1,704 (+4160%)
Mutual labels:  framework-agnostic
watson-personality-insights-php
Framework Agnostic Watson Personality Insights Client
Stars: ✭ 13 (-67.5%)
Mutual labels:  framework-agnostic
PAW pipeline
A Comet-based, best practices proteomics pipeline.
Stars: ✭ 22 (-45%)
Mutual labels:  comet
CometJS
Desktop Development built up on, Javascript, HTML, CSS, Chromium and Firefox.
Stars: ✭ 12 (-70%)
Mutual labels:  comet
zkit
zKit, components for modern web.
Stars: ✭ 38 (-5%)
Mutual labels:  framework-agnostic
laravel-chat
chat application build with laravel and gopusher gateway.
Stars: ✭ 32 (-20%)
Mutual labels:  comet

Cettia

Cettia is a full-featured real-time web application framework for Java that you can use to exchange events between server and client in real-time. It is meant for when you run into issues which are tricky to resolve with WebSocket, JSON, and switch statement per se:

  • Avoiding repetitive boilerplate code
  • Supporting environments where WebSocket is not available
  • Handling both text and binary data together
  • Recovering missed events
  • Providing multi-device user experience
  • Scaling out an application, and so on.

It offers a reliable full duplex message channel and elegant patterns to achieve better user experience in the real-time web, and is compatible with any web frameworks on the Java Virtual Machine.


The following is a summary of the Cettia starter kit to help you get started quickly. In the summary, comments starting with ## refer to a title of a related chapter in the tutorial, Building Real-Time Web Applications With Cettia, where you can find a detailed explanation. You may want to highlight the ##.

Maven dependencies.

<!-- ## Setting Up the Project -->
<!-- To write a Cettia application -->
<dependency>
  <groupId>io.cettia</groupId>
  <artifactId>cettia-server</artifactId>
  <version>1.2.0</version>
</dependency>
<!-- To run a Cettia application on Servlet 3 and Java WebSocket API 1 -->
<!-- Besides them, you can also use Spring WebFlux, Spring MVC, Grizzly, Vert.x, Netty, and so on -->
<dependency>
  <groupId>io.cettia.asity</groupId>
  <artifactId>asity-bridge-servlet3</artifactId>
  <version>2.0.0</version>
</dependency>
<dependency>
  <groupId>io.cettia.asity</groupId>
  <artifactId>asity-bridge-jwa1</artifactId>
  <version>2.0.0</version>
</dependency>

A class to play with the Cettia server. Import statements, verbose try-catch blocks, empty methods, etc. are skipped for brevity.

@WebListener
public class CettiaConfigListener implements ServletContextListener {
  public void contextInitialized(ServletContextEvent event) {
    // Cettia part
    // If you don't want to form a cluster,
    // replace the following line with 'Server server = new DefaultServer();'
    ClusteredServer server = new ClusteredServer();
    HttpTransportServer httpAction = new HttpTransportServer().ontransport(server);
    WebSocketTransportServer wsAction = new WebSocketTransportServer().ontransport(server);

    // If a client opens a socket, the server creates and passes a socket to socket handlers
    server.onsocket((ServerSocket socket) -> {
      // ## Socket Lifecycle
      Action<Void> logState = v -> System.out.println(socket + " " + socket.state());
      socket.onopen(logState).onclose(logState).ondelete(logState);

      // ## Sending and Receiving Events
      // An 'echo' event handler where any received echo event is sent back
      socket.on("echo", data -> socket.send("echo", data));

      // ## Attributes and Tags
      // Attributes and tags are contexts to store the socket state in the form of Map and Set
      String username = findParam(socket.uri(), "username");
      if (username == null) {
        // Attaches a tag to the socket
        socket.tag("nonmember");
      } else {
        // Associates an attribute with the the socket
        socket.set("username", username);
      }

      // ## Working with Sockets
      // A 'chat' event handler to send a given chat event to every socket in every server in the cluster
      socket.on("chat", data -> server.find(ServerSocketPredicates.all()).send("chat", data));

      // ## Advanced Sockets Handling
      if (username != null) {
        // A group of sockets representing the same user, whose username is the given one
        Sentence user = server.find(ServerSocketPredicates.attr("username", username));
        // A 'myself' event handler to send a given myself event to myself whose username is the same
        socket.on("myself", data -> {
          // You can directly handle each socket through the execute method of Sentence if needed
          user.execute(s -> s.send("myself"));
        });

        // Limits only one socket per user
        boolean onlyOneSocket = Boolean.parseBoolean(findParam(socket.uri(), "onlyOneSocket"));
        if (onlyOneSocket) {
          // Finds sockets opened by whose username is the same other than this socket and
          // sends a 'signout' event to prevent reconnection and closes a connection
          user.find(id(socket).negate()).send("signout").close();
        }
      }

      // ## Disconnection Handling
      Queue<Object[]> queue = new ConcurrentLinkedQueue<>();
      // Caches events that fail to send due to disconnection
      socket.oncache(args -> queue.offer(args));
      // Sends cached events on the next connection
      socket.onopen(v -> {
        while (socket.state() == ServerSocket.State.OPENED && !queue.isEmpty()) {
          Object[] args = queue.poll();
          socket.send((String) args[0], args[1], (Action<?>) args[2], (Action<?>) args[3]);
        }
      });
      // If the client fails to connect within 1 minute after disconnection,
      // You may want to consider notifying the user of finally missed events, like push notifications
      socket.ondelete(v -> queue.forEach(args -> {
        System.out.println(socket + " missed event - name: " + args[0] + ", data: " + args[1]);
      }));
    });

    // ## Working with Sockets
    // To deal with sockets, inject the server wherever you want
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    // Sends a 'welcome' event to sockets representing user not signed in every 5 seconds
    executor.scheduleAtFixedRate(() -> server.byTag("nonmember").send("welcome"), 0, 5, SECONDS);

    // ## Plugging Into the Web Framework
    // Cettia is designed to run on any web framework seamlessly on the JVM
    // Note how 'httpAction' and 'wsAction' are plugged into Servlet and Java API for Websocket
    ServletContext context = event.getServletContext();
    AsityServlet asityServlet = new AsityServlet().onhttp(/* ㅇㅅㅇ */ httpAction);
    ServletRegistration.Dynamic reg = context.addServlet(AsityServlet.class.getName(), asityServlet);
    reg.setAsyncSupported(true);
    reg.addMapping("/cettia");

    ServerContainer container = (ServerContainer) context.getAttribute(ServerContainer.class.getName());
    ServerEndpointConfig.Configurator configurator = new ServerEndpointConfig.Configurator() {
      public <T> T getEndpointInstance(Class<T> endpointClass) {
        AsityServerEndpoint asityServerEndpoint = new AsityServerEndpoint();
        asityServerEndpoint.onwebsocket(/* ㅇㅅㅇ */ wsAction);
        return endpointClass.cast(asityServerEndpoint);
      }
    };
    container.addEndpoint(ServerEndpointConfig.Builder.create(AsityServerEndpoint.class, "/cettia")
      .configurator(configurator).build());

    // ## Scaling a Cettia Application
    // Any publish-subscribe messaging system can be used to scale a Cettia application horizontally,
    // and it doesn’t require any modification in the existing application.
    HazelcastInstance hazelcast = HazelcastInstanceFactory.newHazelcastInstance(new Config());
    ITopic<Map<String, Object>> topic = hazelcast.getTopic("cettia");
    // It publishes messages given by the server
    server.onpublish(message -> topic.publish(message));
    // It relays published messages to the server
    topic.addMessageListener(message -> server.messageAction().on(message.getMessageObject()));
  }
}

Here's an example with the Spring WebFlux 5 to show Cettia's framework-agnostic nature. Consult Asity’s Run Anywhere section for how to plug a Cettia application into other various frameworks.

@SpringBootApplication
@EnableWebFlux
public class CettiaServer {
  @Bean
  public RouterFunction<ServerResponse> httpMapping(HttpTransportServer httpAction) {
    AsityHandlerFunction asityHandlerFunction = new AsityHandlerFunction();
    asityHandlerFunction.onhttp(/* ㅇㅅㅇ */ httpAction);

    RequestPredicate isNotWebSocket = headers(h -> !"websocket".equalsIgnoreCase(h.asHttpHeaders().getUpgrade()));
    return route(path("/cettia").and(isNotWebSocket), asityHandlerFunction);
  }

  @Bean
  public HandlerMapping wsMapping(WebSocketTransportServer wsAction) {
    AsityWebSocketHandler asityWebSocketHandler = new AsityWebSocketHandler();
    asityWebSocketHandler.onwebsocket(/* ㅇㅅㅇ */ wsAction);
    Map<String, WebSocketHandler> map = new LinkedHashMap<>();
    map.put("/cettia", asityWebSocketHandler);

    SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
    mapping.setUrlMap(map);

    return mapping;
  }
}

You need minimal HTML to load the cettia object. Also, if you have a cettia-client npm module installed, you should be able to load the cettia object with require("cettia-client/cettia-bundler"); and require("cettia-client"); in Webpack and Node, respectively.

 <!DOCTYPE html>
 <title>index</title>
 <script src="https://unpkg.com/[email protected]/cettia-browser.min.js"></script>

Below is the JavaScript code to play with the cettia object. Open the above page and its developer console in several browsers, run the script, and watch results on the fly.

// ## Opening a Socket
// Manipulates the below params object to play with the server implementation
var params = {
  username: "flowersinthesand",
  onlyOneSocket: true
};
// Let's assume that each key and value are already encoding safe
var query = Object.keys(params).filter(k => params[k]).map(k => `${k}=${params[k]}`).join("&");
var socket = cettia.open("/cettia?" + query);

// ## Socket Lifecycle
var logState = () => console.log(socket.state());
socket.on("connecting", logState).on("open", logState).on("close", logState);
socket.on("waiting", (delay, attempts) => console.log(socket.state(), delay, attempts));

// ## Sending and Receiving Events
["echo", "chat", "myself", "welcome"].forEach(event => {
  socket.on(event, data => console.log(event, data));
});
socket.on("signout", () => {
  console.log("signout", "You've been signed out since you signed in on another device");
  // It prevents reconnection
  socket.close();
});

// This open event handler registered through `once` is called at maximum once
socket.once("open", () => {
  // Sends an echo event to be returned
  socket.send("echo", "Hello world");
  // Sends a chat event to be broadcast to every sockets in the server
  socket.send("chat", {text: "I'm a text"});
  // Sends an event to sockets whose username is the same
  // with composite data consisting of text data and binary data
  socket.send("myself", {text: "I'm a text", binary: new TextEncoder().encode("I'm a binary")});
});

The full source code for the starter kit is available at the repository, https://github.com/cettia/cettia-starter-kit. If you want to dig deeper, read an introductory tutorial to Cettia, Building Real-Time Web Applications With Cettia. It explains the reason behind key design decisions that the Cettia team have made in the Cettia, as well as various patterns and features required to build real-time oriented applications without compromise with Cettia.


If you run into issues or have questions or are interested and would like to be more involved, feel free to join the mailing list and share your feedback. Also, follow @cettia_project or @flowersits on Twitter for the latest news and updates.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].