Hello World

../../_images/example-hello-server.png

Basic Service

Introduction

This example focuses on a single-page application that uses a Baratine server to update an html page.

Because services support a variety of patterns beyond the single-page application, you can browse other patterns after reading this hello example to get a good idea of Baratine’s capabilities.

Maven Archetype for Baratine

When starting an application, you can use the Baratine Maven archetype to creates a skeleton directory with a stub echo service and jUnit tests.

$ mvn archetype:generate \
      -DarchetypeGroupId=io.baratine \
      -DarchetypeArtifactId=baratine-maven-archetype \
      -DarchetypeVersion=0.10.3 \
      -DgroupId=echo \
      -Dpackage=echo \
      -DartifactId=pod \
      -DinteractiveMode=false

In the created directory, build the echo application with mvn package, and start Baratine with baratine:run. Baratine will listen to port 8085 and use /tmp/baratine as its work directory.

$ mvn package baratine:run
baratine>

Browse http://localhost:8085 to run the echo service.

To stop the shell, use the “exit” command:

baratine> exit

Files in the Baratine Archetype

The following files are the minimal required for the single-page application.

  • pom.xml - maven build file
  • src/main/web/index.html - HTML single page
  • src/main/java/echo/EchoService.java - API for Echo service
  • src/main/java/echo/EchoServiceImpl.java - Echo service Impl

The maven archetype creates some additional useful files:

* src/main/resources/META-INF/baratine/config/pods/pod.cf
  - optional pod configuration
* src/test/java/echo/EchoServiceSync.java - Blocking API for Echo
* src/test/java/echo/EchoTest.java        - jUnit Test for Echo

Hello Application Source

  • index.html (HTML main page)
  • EchoService.java (Service API)
  • EchoServiceImpl.java (Service Implementation)
  • pom.xml

Client HTML and JavaScript (index.html)

main/web/index.html:

<html>
<script src="baratine-js.js"></script>

<script>
var host = window.location.host;
var url = "ws://" + host + "/s/pod";
jamp = new Jamp.BaratineClient("http://" + host + "/s/pod");

function execute()
{
  jamp.query("/echo", "echo", ["Hello World"], function (data)
  {
    var out = document.getElementById("output");

    out.innerText = data;
  });
}
</script>

<body style="padding: 1em;">

<input id="btn" name="btn" type="button" onclick="execute()"
       value="Echo 'Hello World!'">

<span id="output" style="padding-left: 1em;"></span>
</body>
</html>

Application API (EchoService.java)

The Application API defines the protocol between the client and the service. Baratine’s protocol is method-based and asynchronous, while allowing for synchronous proxies for older Java clients and testing.

This example has a single method with an asynchronous Result.

Baratine allows plain Java return calls, which would simplify the example, but we wanted to emphasize that Baratine is based around asynchronous calls for scalability.

main/java/example/EchoService.java:

package example;

import io.baratine.core.Result;

public class EchoService
{
  void echo(String arg, Result<String> result);
}

Service Implementation (EchoServiceImpl.java)

main/java/example/EchoServiceImpl.java:

package example;

import io.baratine.core.Service;

@Service("public:///echo")
public class EchoServiceImpl implements EchoService
{
  public void echo(String message, Result<String> result)
  {
    result.complete("echo[" + message + "]");
  }
}

main/web/baratine-js.js

If you’re not using the baratine-js dependency in maven, you can copy the Baratine JavaScript from github.

Download the JavaScript library from github and copy it into main/web:

maven pom.xml

For completeness, here is the generated pom.xml from the archetype.

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>echo</groupId>
  <artifactId>pod</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>bar</packaging>

  <properties>
    <encoding>UTF-8</encoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>io.baratine</groupId>
      <artifactId>baratine</artifactId>
      <version>[0.10,)</version>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>io.baratine</groupId>
      <artifactId>baratine-js</artifactId>
      <version>[0.10,)</version>
      <type>js</type>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.3.2</version>
         <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>

      <plugin>
        <groupId>io.baratine</groupId>
        <artifactId>baratine-maven-plugin</artifactId>
        <version>0.10.3</version>
        <extensions>true</extensions>
       </plugin>
    </plugins>

  </build>

</project>

Service Explanation

../../_images/service-inbox-outbox.png

Because Baratine’s service mechanism is intended to be invisible to existing applications, the hello example might seem simple. In actuality, that application API is hiding significant capabilities.

A Baratine service is a queue (inbox) with a service thread that processes method calls from the inbox. The internal mechanism is generally invisible because services use application APIs. By design, it’s possible for a service implementation and its clients to ignore that they’re using Baratine, because Baratine is designed to work with existing applications.

While the application code can ignore that it’s using Baratine, developers should know a bit more. The important things to know are:

  • Client proxies are thread-safe, intended to be used by multiple threads.
  • Services are single-threaded (see @Workers for a multi-threaded model)
  • The client thread is isolated from the service thread
  • An inbox queue is the main thread-decoupling mechanism
  • Methods are processed in order
  • Calls and results are asynchronous
  • Blocking calls internally use futures to wait for the result.

The order of a method call looks like the following:

  1. Client calls Hello API proxy with hello()
  2. Proxy creates query message and adds to the service inbox (queue)
  3. If service is idle, wake a thread for the service.
  4. — an async client can move on at this point
  5. Service thread reads request from inbox and executes the method.
  6. On return, the service drops the reply into the outbox
  • If the client is a service, put the reply into the client’s inbox.
  • If the client is blocking, wake the caller.
  • If the client is a non-service async, spawn a thread for the callback.

See @Service Guide for more details.

jUnit Testing

The Baratine archetype creates simple jUnit test cases for its echo service. The tests create an embedded echo service, look up a proxy, and test the methods.

EchoTest

EchoTest.java:

package qa;

import com.caucho.junit.ConfigurationBaratine;
import com.caucho.junit.RunnerBaratine;

import org.junit.*;

import javax.inject.Inject;

import io.baratine.core.*;

@RunWith(RunnerBaratine.class)
@ConfigurationBaratine(services = {EchoServiceImpl.class})
public class EchoTest
{
  @Inject @Lookup("/echo")
  private EchoServiceSync _echo;

  @Test
  public void test()
  {
    String message = "Hello World!";

    Assert.assertEquals(message, _echo.echo(message));
  }
}

EchoServiceSync

EchoServiceSync is a variation of the service API for synchronous proxies, such as the jUnit tests. Other uses include integration with existing Java applications.

EchoServiceSync.java:

package echo;

public interface EchoServiceSync extends EchoService
{
  public String echo(String message);
}

GitHub Repository

The code for this example is generated by the maven archetype. It is also available in GitHub.

Downloading Baratine

Download Baratine from <http://baratine.io/download> and extract it to any directory.

Deploying on a Baratine Server

Although the maven baratine:run is useful for development, Baratine is normally started with its start command.

$ baratine start
Baratine/0.10-SNAPSHOT start with watchdog at 127.0.0.1:6700
Baratine/0.10-SNAPSHOT launching watchdog at 127.0.0.1:6700
  starting *:8085 (cluster-8085)

Deploying a service is also from the command line with the deploy command.

$ baratine deploy hello-1.0-SNAPSHOT.bar
  deployed hello-1.0-SNAPSHOT.bar to bfs:///config/pods/50-pod.cf

As with the maven baratine:run, the application can be browsed at:

http://localhost:8085/pod

Baratine Archive (.bar file)

The Baratine archive is a jar file with the following structure:

* lib/my-lib.jar - any jar files, including libraries
* classes/*      - direct classes
* web/index.html - static pages

JAMP async-RPC protocol

The service itself can be tested on the command line:

$ baratine jamp /echo echo hello
["echo[hello]"]

Information on JAMP is available in the HTTP/WebSocket Clients documentation.

JAMP (JSON async method protocol) is an asynchronous RPC protocol using JSON for method arguments and return values. Because it’s asynchronous, multiple requests can be in flight at any time, and responses can return out of order.

When WebSockets is available, JAMP will use it for efficiency, and will fallback to HTTP long polling when it’s not available.

After Hello

Download:

Examples:

Papers:

Examples on GitHub:

Client libraries on GitHub: