{#========================================== Docs : "overview" ==========================================#}

Spincast overview

{#========================================== Section "overview / introduction" ==========================================#}

Introduction

Spincast is based on the shoulders of a giant, Guice (from Google). Other Java web frameworks may claim they support Guice, and maybe even have a section of their documentation dedicated to the topic. Spincast is one of those that is totally built on Guice, from the ground up! If you already know Guice, Spincast will be really easy to grasp for you.

Guice is not only (in our opinion) the best dependency injection library of the Java ecosystem, but also a fantastic base to build modular applications. Everything is divided into modules which are swappable and overridable. Each module can declare which dependencies it requires from other modules. In fact, Guice is so flexible that you may even find ways of using Spincast we haven't think about!

If you know another dependency injection library, like Spring, it can also help but you'll probably have to learn one of two new tricks!

Here's what using Spincast looks like at a very high level:

Users make requests to your web application. This application can have an HTML interface, built using popular tools like jQuery, React, Ember, Angular, etc. That HTML interface can be generated by Spincast (using a built-in templating engine) or can be a Single Page Application where Spincast is used as a bootstrapper and a data provider (JSON or XML) for the SPA.

Spincast is also a good platform to build REST web services or microservices, without any user interface, since it "talks" JSON and XML natively.

{#========================================== Section "architecture / architecture" ==========================================#}

Architecture

The core of a Spincast application is its Guice modules. Most of the time, your application's main Guice module will extend the default SpincastDefaultGuiceModule, so you start with a default implementation for all the required components, and not from scratch. Many components are provided by the various Plugins, but your application will also bind components specific to it business logic : controllers, services, etc.

As you can see :

{#========================================== Section "architecture / request handling" ==========================================#}

Request handling

Now that we have an idea on how is structured a Spincast application, let's see how it handles requests and what are the components involved.

First, the embedded HTTP Server receives a request from a user. This server consists of a Server interface and an implementation. The default implementation is provided by the spincast-plugins-undertow plugin which uses the Undertow HTTP/Websocket server.

If the request is for a static resource, the server serves it directly without even reaching the framework. Note that it's also possible to generate the resource, using a standard route, so the request does enter the framework. There is even a third option which is what we call dynamic resources: if a request is made for a request which currently doesn't exist, the server will pass the request to the framework, the framework can then create the resource and return it... The following requests for the same resource will use the generated resource and won't reach the framework anymore!

If the request is not for a static resource, the server passes it to the first Spincast component involved : the Front Controller. The Front Controller is at the very center of Spincast! This is one of the very few components which is not provided by a Plugin, but that is actually included in the spincast-core Maven artifact itself. Note that you still can extend the default Front Controller and override some of its methods, though, if you need to tweak one thing or two.

The job of the Front Controller is to:

  • Ask the Router for the appropriate route to use when a request arrives.
  • Call the Route Handlers of the matching route. A route can have many handlers : they are Filters which are run before the Main Handler, the Main Handler itself, and some Filters which are run after the Main Handler.
  • If the request is for a WebSocket connection, the handling of the request is made by a WebSocket Controller instead of a Route Handler. Also, the result is not a simple response but a permanent and full duplex connection where each side can send messages to the other side. Have a look at the WebSockets section for more information!
  • If no matching route is returned by the Router, the Front Controller will use a Not Found route. The Not Found route can be a custom one, or the default one provided by Spincast.
  • If any exception occures during any of those steps, the Front Controller will use an Exception route. The Exception route can be a custom one, or the default one provided by Spincast.

The job of the Router is to determine the appropriate route to use, given the URL of the request, its HTTP method, etc. It will also extract the value of the dynamic path tokens, if any. For example, a route path could be "/user/${userId}/tasks". If a "/user/42/tasks" request is made, the router will extract "42" as the value of the userId parameter and make this available to the rest of the framework.

Finally:

  • The Route Handlers receive a Request Context (which represents the request), and decide what to return as the response. This can be anything: Json, HTML, XML or even bytes.
    or:
  • A WebSocket Controller receives the request for a WebSocket connection, allows or denies it, and then receives and sends messages on that connection.

{#========================================== Section "architecture / Required components and their default implementations" ==========================================#}

The required components and their default implementations

The required components are those without which a Spincast application can't even run. Any class, any Plugin, can assume those components are available, so they can inject them and use them!

It is Spincast's core module, SpincastCoreGuiceModule, which validates that an implementation for those components is actually bound. If something is missing, an exception is thrown and the appliation is not started.

Default implementations for those required components are bound by the SpincastDefaultGuiceModule Guice module, which is provided by the spincast-default Maven artifact. Using the SpincastDefaultGuiceModule Guice module as a base is the easiest way to develop a Spincast application since you are assured that all the required components will have been taken care of.

What are those required components and what are their default implementations?

{#========================================== Section "architecture / Transitive dependencies" ==========================================#}

Transitive dependencies

The spincast-core Maven artifact only has 3 direct dependencies which are external to Spincast:

The versions used for those dependencies are defined in the spincast-parent Maven artifact's pom.xml.

Spincast core also uses some Apache commons libraries, but those are shaded, their classes have been relocated under Spincast's org.spincast.shaded package, so they won't conflit with your own dependencies.

That said, each Plugin also adds its own dependencies! If you start with the spincast-default Maven artifact, a bunch of transitive dependencies will be included. If you need full control over the transitives dependencies added to your application, start with the spincast-core Maven artifact and pick, one by one, the plugins and implementations you want to use.