Skip to content

mrazjava/moo

Repository files navigation

License Build Status Coverage Status

A simple, modular, extensible chat platform

Moo Logo mooooooooooo


Moo is a Java based chat service written as test bed for various concepts. It features a modular design, which separates the concepts of a UI, client and a server. As a result, a UI can be developed based on a common chat API, without compile time dependency on neither client or a server. Depending on which server is running, a UI only needs a compatible runtime client dependency.

My goal in writing moo was to achieve practical, working example of a modular chat service with at least two client/server implementations that can be simply swapped without affecting UI. Similarly, I wanted to come up with a practical and intuitive API that makes building any user interface straightforward. As a result of my initial goals, moo is not feature rich nor is it optimized for performance. It only provides the very basic chat functionality.

If you're looking for a working example of a chat application, web sockets or JMS, complete test suite powered by Mockito, high code coverage, then you may find moo a happy place to poke around.

Stack

  • Java
  • Web Sockets
  • (J)ava (M)essaging (S)ervice (ActiveMQ)
  • Spring Boot
  • Mockito

Features

  • Distributed Architecture
  • Server JMX reporting
  • Console UI
  • Server generated nick names
  • Single public chat hall

Defaults


By default moo is bound to a web socket client. It expects a running web socket server.

Screenshots


Moo running on web sockets client/server:

Shell UI Screenshot

Moo running on JMS client/server with ActiveMQ broker (not shown):

Shell UI Screenshot

In both screenshots we have a 4 way tmux session. In the left upper corner we're running moo server. In the right upper we have a moo reader which displays chat activity. In both bottom corners, we're running two instances of a writer, simulating user chat experience. In a typical use case, end user would run one instance of a reader and writer only.

There are some subtle but interesting UI behavioral differences depending on which client/server implementation is used. For example, with web sockets when server is aborted messages generated by the writer are lost. This is not the case with a JMS server, as messages are retained by the broker and delivered when server is started again. Another difference is that websocket server tracks activity of connected clients while JMS server does not. As a result, JMS clients can be connected to the broker indefinitely, while websocket clients will be aborted by the server is evictionTimeout defined in websocket server application.properties is exceeded.

First things first


Make a local build:

cd moo/
mvn install

Server


Starting server:

cd moo/moo-server-IMPL/
mvn spring-boot:run

IMPL = one of the available implementations: moo-server-socket or moo-server-jms. Details about each server are available in the server project readme.

Client


Depending on which server is running, a compatible client runtime dependency of a UI app is required. For example, for text based shell UI, a socket compatible client would be enabled by commented out the following in moo-ui-shell/moo-ui-shell-reader/pom.xml and moo-ui-shell/moo-ui-shell-writer/pom.xml:

<!--
only one moo-client implementation can be enabled otherwise spring 
IOC will not resolve injection points due to multiple implementations
-->
<dependency>
  <groupId>pl.zimowski</groupId>
  <artifactId>moo-client-socket</artifactId>
  <scope>runtime</scope>
</dependency>
<!--
<dependency>
  <groupId>pl.zimowski</groupId>
  <artifactId>moo-client-jms</artifactId>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>org.apache.activemq</groupId>
  <artifactId>activemq-core</artifactId>
  <scope>runtime</scope>
</dependency>
-->

UI


Starting console UI requires two terminal sessions. It's probably easiest to split terminal session into two using something like screen or tmux.

First, start UI reader which will allow to view public chats:

cd moo/moo-ui-shell/moo-ui-shell-reader
mvn spring-boot:run

Reader running on websocket client will attempt to connect to server at localhost on port 8000. This can be re-configured via application.properties, or more conveniently, by overriding these spring managed props as command line args. Client aborts immediately if server connection cannot be established.

To be able to actually send chat messages, it is necessary to have a running instance of a writer:

cd moo/moo-ui-shell/moo-ui-shell-writer
mvn spring-boot:run

Because writer uses the same client as reader, same customization strategy applies. If server is based on websockets, then websocket client should be used. If server is based on JMS, then JMS client should be used, etc.

Dockerization


As a convenience, the socket server and a compatible reader are dockerized and can be run with a single command from the root (moo/):

docker-compose up

Docker compose will bring up two images and each can be interacted with:

docker ps

to obtain a container id, then:

docker exec -it <container_id> bash

To produce chat messages we simply start a writer with a standard maven command:

cd moo/moo-ui-shell/moo-ui-shell-writer/
mvn clean spring-boot:run

By default the output from the server and reader will appear where docker-compose up was invoked, so output from server and reader is mixed up and may be difficult to parse to a naked eye. It can be separated by container id using docker logs, though:

docker logs <container_id> -f

Code Coverage


Playing around with Coveralls Github plugin, found it interesting but imperfect. The readme badge is really nice, but it is not reliably updated when coverage changes and there are a lot of complaints about it posted on the web. For me, sometimes it updates instantly, other times takes 24 hours. Don't trust the badge. The sure way to verify code coverage is to invoke suite locally:

cd moo/
mvn clean verify

Then check jacoco reports:

cd moo-reports/target/site/jacoco-aggregate/

and open index.html in your favorite browser.

Miscellaneous


Bumping up version

As moo is a modular maven project, its version is referenced in several places. The easiest way to modify release version is to use the maven plugin. For example, to bump up the version execute the following from project root:

mvn versions:set -DnewVersion=2.2.0-SNAPSHOT

Maven will use version declaration to determine version being replaced and replace it (and all references to it) with the specified new version. It will create temporary backup files to give ability to reverse the change. If upon reviewing changed files everything looks good we tell maven to permanently write our changes with:

mvn versions:commit

In case we do not like version changes performed by maven, we can reverse these with:

mvn versions:revert