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.
Join the DZone community and get the full member experience.
Join For FreeCricket 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
Why another CMS?
How to launch a website in less than 5 minutes
The platform architecture
Cricket as a CMS
How to change a static website into managed by CMS
How to run a CMS tailored to your needs
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
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.
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.
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:
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
.
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
Published at DZone with permission of Grzegorz Skorupa. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Turbocharge Ab Initio ETL Pipelines: Simple Tweaks for Maximum Performance Boost
-
Data Freshness: Definition, Alerts To Use, and Other Best Practices
-
How To Check IP Addresses for Known Threats and Tor Exit Node Servers in Java
-
What Is Test Pyramid: Getting Started With Test Automation Pyramid
Comments