Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Minimalistic CMS for Java With Cricket

DZone's Guide to

Minimalistic CMS for Java With Cricket

Learn how Cricket's modular, event-driven architecture lets us use it to create and launch Java microservices at speed.

· Microservices Zone ·
Free Resource

Learn how modern cloud architectures use of microservices has many advantages and enables developers to deliver business software in a CI/CD way.

Cricket is a platform for the fast creation of Java microservices. Its latest "Microsite" release provides a ready-to-use set of functionalities, thanks to which we can also easily run a CMS or web application. In this way, the same platform can be used in both the backend and frontend layers of a larger solution.

Because of its modular, event-driven architecture, Cricket can be used both to build a mini service running on Raspberry Pi Zero, etc. and to deploy distributed systems in cloud infrastructure.

This article shows how to use the platform as a simple CMS to manage a website. Examples include the use of a ready-made Docker Container available on the Docker Hub, and the last chapter also shows how to run it directly on the Java environment.

Table of Contents

  1. Why another CMS?

  2. How to launch a website in less than 5 minutes

  3. The platform architecture

  4. Cricket as a CMS

  5. How to change a static website into managed by CMS

  6. How to run a CMS tailored to your needs

  7. Additional information

1. Why Another CMS?

Java developers face a difficult choice if they need a quick and lightweight solution to run a website or a web application. Web and portal platforms for Java are widely criticized for their excessive size, over-engineering, and high consumption of system resources. Therefore, we often deal with systems built as a conglomerate of many technologies, where Java is possibly used in the backend layer.

Such solutions can perfectly fulfill their goals, while at the same time presenting developers with new challenges and enabling them to acquire new knowledge. However, as the number of technologies used and the complexity of the system increases, the risk of problems also increases if you need to update the technology stack, introduce functional changes, or introduce new people to the team.

The emergence of the microservices concept naturally raises the expectation that we will be able to create prototypes very quickly and strive to reduce our solutions' requirements for system resources.

The Cricket Microsite platform was developed to some extent in response to this situation, offering architects and Java developers appropriate tools.

2. How to Launch a Website in Less Than 5 Minutes

The simplest way to use the platform is to run a static web page. Using the ready-made Docker image we can run our website in a few minutes, without the need to install any additional software.

As an example, we will create a new mywww folder containing a simple HTML page, then run the "cricket-microsite" image stored in Docker Hub.

$ mkdir mywww
$ echo "Hello!">mywww/index.html
$ docker run --name mycricket -d -v "$(pwd)"/mywww:/cricket/www \
-p 127.0.0.1:8080:8080 gskorupa/cricket-microsite:latest

Cricket has a built-in HTTP server, listening on port 8080 by default and serving any files contained in its volume /cricket/www and its subfolders. In this case, our website will be available at http://127.0.0.1:8080 . Now we can try to modify the index.html file and add more pages or files.

NOTE: The platform started in this way cannot automatically refresh the internal cache, so all changes in the files will be visible in the browser only after the container is restarted.

The running Docker container can be stopped by this command:

$ docker stop mycricket

To start the stopped container, use this command:

$ docker start mycricket

3. The Platform's Architecture

Before we go to the next examples, let's first talk about the key components.

Cricket implements the "ports and adapters" (hexagonal) architecture, in which the service functions are implemented by calling specific adapters. The advantage of such a solution is, among other things, the ability to easily and safely change the implementation method of individual adapters. For example, we can change the type of database used or use an external message broker instead of the built-in solution.

Microsite uses, among others, adapters:

  • AuthService - responsible for user authorization in the CM module

  • UserService - user management

  • ContentManager (CM) - content management

  • ContentService (CS) - provides published content from the CM module

  • WwwService - processing and serving content in response to HTTP requests
    Image title

The UserService, AuthService, ContentService and ContentManager adapters make their functionalities available through the REST API.

NOTE: Microsite is offered as a single service by default, however, it can be easily divided into smaller microservices, thus providing better scalability and increasing the level of security of the implemented solution.

4. Cricket as CMS

Content management systems (CMS or in particular WCM) facilitate the management of websites, enabling modification of content presented on websites regardless of its layout.

Cricket Microsite belongs to this category of systems, although unlike some of them it is addressed mainly to programmers and website designers. This is due to limited functionality, which may be difficult to accept by business users (e.g. lack of versioning or simplified workflow, allowing for one-step editing and removal of published content).

CM Module

The CM (ContentManager) module is responsible for managing the content elements (documents) stored in the database, enabling their creation, editing, publishing, unpublishing and deleting. Logged in users with administrator or editor roles have access to the module.

We distinguish three types of documents:

  • FILE - storing any file (e.g. a photo)
  • CODE - for storing source code (e.g. CSS, JavaScript, HTML), which can be edited by the user in the CM interface
  • ARTICLE - editable content to be embedded on web pages

Key features of documents:

  • Each document consists of a set of parameters, while a document of the FILE type is additionally linked to a file.
  • The document is uniquely identified in the system by a pair of parameters: uid + language . UID is created by combining the path parameter and the document name.
  • The document can be in one of two states:
    • wip (draft) - visible only to users logged into the CM module
    • published - publicly available via ContentService or WwwService (displayed on the website)
  • Documents in different language versions have the same uid , but they differ in the language parameter.

Starting the Platform

In the previous example, we used a platform to publish pages from the selected folder on the disk (starting the container with the -v option). In this mode, the Content Manager module is not available, so in order to get full functionality, we need to start the Docker container without mounting the local folder:

$ docker run --name mycricket -d -p 127.0.0.1:8080:8080 \
gskorupa/cricket-microsite:latest

The container automatically creates two volumes in the local filesystem to store the work files (e.g. databases and page templates). You can find out the actual location of these volumes by using the command:

$ docker container inspect mycricket

Additional information on how to start the platform is provided at the end of this article.

Creating and Editing Documents

After starting the system, we can log into the Content Management module ( http://127.0.0.1:8080/admin ) as a user admin with the password cricket .

After choosing the option Content > Documents from the menu, we can see the screen presenting the list of documents in the selected status, for the selected language.

Documents

The Content Manager administration module has been built using Riot and Bootstrap libraries, supporting RWD application development technology, so that the interface can also be used using smartphones.

Image title

Publishing

Just after saving, the document status is wip and it is available only to users of the Content Manager module. To be publicly available, it must be published. This is done by clicking on the "Status" icon (shown in the "Documents" illustration). The document changes status to published without asking for confirmation and disappears from the list of wip documents.

The unpublishing of documents is done in a similar way.

NOTE: Published documents can be edited and changes made to them will be visible to the public immediately after saving the document!

5. How to Change a Static Website Into Managed by CMS

Cricket Microsite enables smooth migration of static pages to a WCM solution. This is possible thanks to the specific way of serving files by the built-in HTTP server.

When receiving a GET request that indicates a specific path to the file, the server first searches for a document of the FILE or CODE type whose identifier (UID) is the same as this path. They are searched one by one:

  • WwwService adapter cache
  • ContentService adapter database
  • internal filesystem

Thanks to the procedure described above, we can quickly run a prototype of a static website using files from a selected template, and then successively replace the files on the disk with corresponding documents in the CM module.

Example

Cricket contains a built-in default page template that you will see at (http://127.0.0.1:8080). We are not going to analyze it now, because we want to replace it with our own dynamically managed website.

1. Log in to the CM module and create a new document with the following parameters:

Parameter Value
Type CODE
Name index.html
Path /
Content Hello!
Mime Type

text/html

2. Save the document and publish'.

3. Check if the content of the main page (http://127.0.0.1:8080) has changed to the one specified in the document.

NOTE: There is no need to restart the service when it is running in this mode. Document changes made in the CM module will be visible on the website immediately.

4. Display the list of published documents in the CM module and go on to edit our index.html document. In the Content field, enter the HTML code as follows:

<html>
    <head>
        <link rel="stylesheet" type="text/css" href="theme.css">
    </head>
    <body>
        <img src="/images/logo.png"/>
        <h1>Hello World!</h1>
    </body>
</html>

5. Save and check how the page has changed.

6. Create a document with style definitions:

Parameter Value
Type CODE
Name theme.css
Path /
Mime Type

text/css

body {
    color: darkblue;
    text-align: center;
}

7. Create a document with the attached logo file:

Parameter Value
Type CODE
Name logo.png
Path /images
Mime Type image/png
File

select a file from the disk

8. After publishing all created documents, our site should look like this:

Image title

In the same way, we can create and manage subsequent pages, expanding our website as needed.

6. How to Run a CMS Tailored to Your Needs

Publishing information on pages by modifying their source code is inconvenient. Web Content Management (WCM) platforms, such as for instance WordPress, simplify this process by enabling content editing without the need to modify a webpage source code. This makes it possible to separate website development process from the editorial work.
Cricket Microsite allows us to get the same effect by using an ARTICLE document.

Thanks to the platform features, we can design and build the solution tailored to our needs, without excessive requirements for system resources and easier to use than all-in-one systems.

Describing all aspects of designing dynamic pages, navigating between them, searching for documents and reacting to user actions goes far beyond the concept of this article. For this reason, the description below is only an example of one possible solution. Experienced readers should easily develop their own solutions on this basis.

Required Features

We will launch an RWD news website that will be composed of:

  • Menu
  • Homepage presenting the introductory article and the list of the last news (articles)
  • News page
  • A page presenting the full text of the article

Technologies Used

To develop page templates, we will use libraries that perfectly fit the idea of minimalism that characterizes Cricket Microsite:

  • Bootstrap 4.0 - to make the HTML code of a page easy to create in accordance with the RWD.
  • Riot - for convenient connection of data to visual elements of the user interface.

Building Blocks

Our website will be built from several types of documents stored in the Content Management module:

  • The page template
  • Riot components
  • Stylesheet
  • News articles
UID Purpose
/index.html Template for the homepage
/local/js/routing.js Routing functions for Riot components
/local/components/app_main.tag Riot component with the functionality of the homepage
/local/components/app_menu.tag Riot component with a simple menu
/local/components/app_list.tag Riot component for article list presentation
/local/components/app_articleview.tag Riot component downloading the selected message
/local/components/app_article.tag Riot component presenting the content of an ARTICLE document
/tags/raw.tag Riot component allows us to inject a fragment of HTML into another component.
/local/css/styles.css Stylesheet
/welcome_text Content displayed on the homepage
/news/art1 Example news
/news/art2

Example news

NOTE: The raw component (raw.tag file) and the data access functions (data-api.js file) are part of the Cricket Microsite distribution and will not be discussed here.

Homepage Template

The file's task is to load the required JavaScript libraries, style sheets, and Riot components. Once created, it will need to be modified later only if you modify the list of used components.

Parameter Value
Type CODE
Name index.html
Path /
Mime Type

text/html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
        <!-- Custom styles -->
        <link rel="stylesheet" href="/local/css/styles.css">
    </head>
    <body>
      <app_main></app_main>
      <!-- SCRIPTS: jQuery first, then Bootstrap JS, then Riot -->
      <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
      <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/riot/3.9.3/riot+compiler.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/riot-route@3.1.2/dist/route.min.js"></script>
      <!-- Application scripts -->
      <script src="/local/js/routing.js"></script>
      <script src="/js/data-api.js"></script>
      <!-- Riot components -->
      <script data-src="/tags/raw.tag" type="riot/tag"></script>
      <script data-src="/local/components/app_article.tag" type="riot/tag"></script>
      <script data-src="/local/components/app_main.tag" type="riot/tag"></script>
      <script data-src="/local/components/app_menu.tag" type="riot/tag"></script>
      <script data-src="/local/components/app_list.tag" type="riot/tag"></script>
      <script data-src="/local/components/app_articleview.tag" type="riot/tag"></script>
      <script>
        app.csAPI = "http://localhost:8080/api/cs";
        riot.mount('*');
        route.start(true);
      </script>
    </body>
</html>

Riot Components

The routing function is triggered by events related to movement within the page. It allows you to define the activities related to navigation in a browser (clicking the link in the menu, refreshing the page, the "back" key).

Parameter Value
Type CODE
Name routing.js
Path /local/js
Mime Type

text/javascript

route(function (id) {
  if(id.startsWith('news')){
    app.currentPage='news'
    app.selectedDoc = id.substring(4).replace(/,/g , '/')
  }else{
    app.currentPage='home'
    app.selectedDoc=''
  }
  globalEvents.trigger('pageselected')
  riot.update()
})

The app_main component is responsible for embedding other components into the page, making their visibility dependent on the current state of the application: in our case, on the selected page and document.

Parameter Value
Type CODE
Name app_main.tag
Path /local/components
Mime Type

text/html

<app_main>
  <app_menu></app_menu>
  <app_articleview if={app.currentPage=='home'} uri='/welcome_text' mode='intro'></app_articleview>
  <app_list if={app.currentPage=='home'} limit='1'></app_list>
  <app_articleview if={app.currentPage=='news' && app.selectedDoc!=''} uri={app.selectedDoc} mode='view'></app_articleview>
  <app_list if={app.currentPage=='news' && app.selectedDoc==''}></app_list>
</app_main>

app_menu renders a simple menu.

Parameter Value
Type CODE
Name app_menu.html
Path /local/components
Mime Type

text/html

<app_menu>
  <div class="container menu">
    <div class="row" >
      <div class="col">
        <a href="/">Home</a> <a href="#news">News</a>
      </div>
    </div>
  </div>
</app_menu>

app_list loads the list of documents with the required path parameter using the REST API of the CS module and then renders the shortcuts of these documents using the app_article component.

Parameter Value
Type CODE
Name app_list.html
Path /local/components
Mime Type

text/html

<app_list>
  <div class="container">
    <virtual each={item in list}>
      <div class="row">
        <div class="col">
          <app_article title={item.title} summary={item.summary} mode='list' page='#news' uid={ item.uid } />
        </div>
      </div>
    </virtual>
  </div>
  <script>
    var self=this
    self.limit=0
    self.list=[]
    self.on('mount', function(){
      self.limit=opts.limit
      loadDocs()
    })
    var loadDocs = function () {
      getData(app.csAPI + '?path=/news/&language=' + app.language, null, null, setDocList, self)
    }
    var setDocList = function (text) {
      self.list = JSON.parse(text)
      if(self.limit>0){
        self.list=self.list.slice(0,self.limit)
      }
      var i
      for (i = 0; i < self.list.length; i++) { 
        self.list[i]=decodeDocument(self.list[i])
      }
      self.update()
    }
  </script>
</app_list>

app_articleview loads an article with a specified uid using the REST API of the CS module, and then transfers the JSON object representing this document to the app_article component.

Parameter Value
Type CODE
Name app_articleview.tag
Path /local/components
Mime Type

text/html

<app_articleview>
  <div class="container">
    <div class="row" >
      <div class="col">
        <app_article title={doc.title} mode={mode} />
      </div>
    </div>
  </div>
  <script>
    var self=this
    self.doc={ title: '.....'}
    self.on('mount', function(){
      self.uri=opts.uri
      self.mode=opts.mode
      self.articleTag=self.tags.app_article
      getData(app.csAPI + self.uri+'?language=en', null, null, setDocument, self)
    })
    var setDocument = function (text) {
      self.doc = decodeDocument(JSON.parse(text))
      self.articleTag.update(self.doc)
      self.articleTag.update({mode:self.mode})
    }
  </script>
</app_articleview>

The app_article component task is to embed the selected document on the page, using the appropriate formatting. Depending on the mode selected in the options, the corresponding document parameters and links are rendered.

Parameter Value
Type CODE
Name app_article.tag
Path /local/components
Mime Type

text/html

<app_article>
  <article class='standard'>
    <header>
      <h1 class={mode}>{title}</h1>
      <div class='intro' if={summary}><raw html={summary}/></div>
    </header>
    <div if={content}><raw html={content}/></div>
    <footer>
{ published }</div></footer>
    <div if={ mode=='view' }><a href="#" onClick="history.back()" }>Back</a></div>
    <div  if={ mode=='list' }><a href={detailsLink}>More ...</a></div>
  </article>
  <script>
    var self=this
    self.title=opts.title
    self.summary=opts.summary
    self.content=opts.content
    self.author=opts.author
    self.published=opts.published
    self.type=opts.type
    self.page=opts.page
    self.uid=opts.uid
    if(opts.mode){
      self.mode=opts.mode
    }else{
      self.mode='default'
    }
    self.detailsLink=''+self.page+self.uid
    self.detailsLink=self.detailsLink.replace(/\//g , ',')
  </script>
</app_article>

Stylesheet

The stylesheet document can be used to manage the appearance of the site.

Parameter Value
Type CODE
Name styles.css
Path /local/css
Mime Type

text/css

article > header {
  margin-top: 20px;
}
article > header > h1 {
  font-size: x-large;
  font-weight: bold;
}
article > header > h1.view {
  font-size: xx-large;
  font-weight: bold;
  color: green;
}
.menu {
  padding: 10px;
  background: linear-gradient(white,lightgray);
}

The Content

The homepage prepared by us displays the content of the article stored in the CM module, with the uid identifier equal to /welcome_text , i.e. the article located on the / path, named welcome_text . If we haven't created such an article yet, it's time to do so.

The homepage presents a list of all articles in the /news path. For simplicity, the code has no limitations on the number of documents displayed, and there is no paging mechanism.

The Result

If we have done all the steps as described, we can see the result of our work at http://127.0.0.1:8080 .

Image title

7. Additional Information

Document Parameters

Parameter Meaning
uid The unique document identifier (path+name)
path Location (path) of the document in the structure of the repository
name Document name unique to the path (alphanumeric, without spaces)
type Document type. One of: ARTICLE, CODE, FILE
author Document author
title Title
summary Summary, abstract of the document
content Document content. For FILE documents: the path to the file in the platform's local file system
tags (not used)
language Two-character document language code
commentable (not used)
mime-type Document MIME type
status Document status. One of: wip, published
size The file size
created Creation date
modified Date of the last modification
published Date of the last publication
createdBy

Login of the document creator

Docker Container Run Options

1. Standard run options

$ docker run --name cricketsite -d -e CRICKET_URL='https//www.mysite.com' \
 -p 127.0.0.1:8080:8080 gskorupa/cricket-microsite:latest
Argument Meaning
-- name The name assigned to the container. It will make it easier to identify the container later.
-d Running container in the background
-e Setting the environmental variable value for the container. The CRICKET_URL environment variable stores the address we use for our service. Setting this variable is necessary if you want to refer to the service asynchronously from the browser (the mechanism used by the web application of the CM module).
-p

Port mapping. Here we can specify the IP address on which Cricket's http server will be listening and the port number exposed by Docker.

2. Local file server mode (with connected volume)

$ docker run --name mycricket -d -v "$(pwd)"/mywww:/cricket/www \
-p 127.0.0.1:8080:8080 gskorupa/cricket-microsite:latest
Argument Meaning
-v

connecting the specified folder from the local file system as a container volume

Running the Platform on JVM

If we do not want to use Docker, we can run the system directly on Java Runtime Environment. It is also an option for those who want to be able to experiment with the platform itself: modify the static page template, change the database or extend the solution with their own backend components.

1. Download the latest release and extract it to the folder of our choice.

$ wget https://github.com/gskorupa/Cricket/releases/download/1.2.41/cricket-microsite.zip
$ mkdir myservice
$ unzip cricket-microsite.zip -d myservice

2. Start the service

$ cd myservice
$ sh run.sh

NOTE: The service's runtime parameters are appropriate for Java version 9 or 10, but it can be changed by editing the run.sh file.

3. Modify and expand the service according to requirements.

We can modify files and subfolder structure in the myservice/work/www folder.

External Resources

https://www.cricketmsf.org/

https://docker.io/

https://hub.docker.com/

https://getbootstrap.com/

http://riotjs.com/

https://en.wikipedia.org/wiki/Responsive_web_design

Discover how to deploy pre-built sample microservices OR create simple microservices from scratch.

Topics:
java ,docker ,hexagonal architecture ,microservices ,cms ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}