Developers Guide for the Brill CMS and for creating React Components and Java server-side functionality

Brill Developers Guide

This guide is designed to help Developers understand the architecture of the Brill Framework and infrastructure. In particular it’s for Developers that need to write new UI Components and new Server Event Handlers.

The client code running on a web browser uses React and is written in Typescript. Communication with the server is via WebSockets. With WebSockets, a TCP/IP connection remains open for the duration of the session. A Message Broker (MB) on the client handles all communication with the server. A “publish subscribe” model is used. All messages are JSON messages. See the Brill Middleware documentation for more details.

The server is written in Java and is a Spring Boot application running on Tomcat. The server has Event Handlers that handle each of the different message types. The server uses WebSockets rather than REST. The server provides the client with access to git repository files, the database and the ability to run JavaScript on the server.

The Content Management System ( CMS ) is used to create application pages and resources. Application pages are encoded using JSON. The client retrieves pages from the server and renders them.

Development Environment

Workstation

Any high spec'ed machine can be used for setting up a development environment. The OS can be MacOS, Microsoft Windows or Linux. It’s recommended that the machine has a fast processor, SSD, at least 8GB of memory and a large monitor or several monitors.

Git

The source code is held in a git repository on BitBucket. To check if you have git installed, just git from the command line. If you don’t already have git installed, follow the instructions at:

https://git-scm.com/book/en/v2/Getting-Started-Installing-Git

Node

To find out if Node is already installed, from the command line enter:

node --version

The latest version can be downloaded from:

https://nodejs.org/en/download/

Node is only used for development, it’s not used in the Production environment.

Yarn

Yarn is used for package management and building the client app. Type yarn --version from the command line to see if it’s already installed. Node is used for running the client Development server. Details on installing Yarn can be found at:

https://yarnpkg.com/

Java

To find out if Java is installed and if so which version, use the command:

java -version

The versions of Java supported are 11 to 15. If you have a version of less than 11, please upgrade to 11, 14 or 15. See the instructions below for your OS.

MacOS

Either install Open JDK 15 using the instructions at:

https://java.tutorials24x7.com/blog/how-to-install-openjdk-15-on-mac

or use Oracle JDK 15 available from:

https://www.oracle.com/java/technologies/javase/jdk15-archive-downloads.html

The advantage of the Oracle version is that it comes with an Installer.

Windows

Either install Open JDK 15 using the instructions at:

https://java.tutorials24x7.com/blog/how-to-install-openjdk-15-on-windows-10

or use Oracle JDK 15 available from:

https://www.oracle.com/java/technologies/javase/jdk15-archive-downloads.html

The advantage of the Oracle version is that it comes with an Installer.

Linux

Either install Open JDK 15 using the instructions at:

https://java.tutorials24x7.com/blog/how-to-install-openjdk-15-on-ubuntu-20-04-lts

or use Oracle JDK 15 available from:

https://www.oracle.com/java/technologies/javase/jdk15-archive-downloads.html

Visual Studio Code

Visual Studio Code is a good lightweight IDE that’s free. Other IDEs such as IntelliJ or Eclipse can also be used. The chosen IDE ideally needs to support editing of TypeScript and JSON.

Instructions on installing Code can be found at:

https://code.visualstudio.com/download

Extensions

You might want to install the following Visual Studio Code extensions:

Java Extension Pack

Debugger for Java

Spring Boot Tools

Spring Boot Dashboard

Cloning the repositories

Bitbucket access

To access the Bitbucket repository, a Public / Private key pair is required for authentication. The instructions for generating a key pair are at:

https://support.atlassian.com/bitbucket-cloud/docs/set-up-an-ssh-key/

The keys need to be placed in the directory ~/.ssh

MacOS

The keys need to be converted from OPENSSH to RSA format using the command:

ssh-keygen -p -f id_rsa -m pem -P "" -N ""

Projects directory

Its suggested that all the projects are kept under a directory of ~/Projects

Make the directory and issue the git clone commands from that directory.

mkdir ~/Projects

cd ~/Projects

Server

Clone the server code using:

git clone git@bitbucket.org:brillsoftware/brill_server.git

Client

Clone the client code using:

git clone git@bitbucket.org:brillsoftware/brill_client.git

Running the code

Server

cd ~/Projects/brill_server

code .

Right click on BrillServerApplication.java and select Run

or install the Spring Boot Dashboard extension and run brill_server.

This will build and run the server process with a Spring Boot profile of local.

The process will listen for Http and WebSocket requests on port 8080.

Client

cd ~/Projects/brill_client

code .

Get a new terminal window a install all the dependencies:

yarn install

Start the development Node server:

yarn start

This will compile the code and run a NodeJs server that’s listening on port 3000.

Use a web browser to access http://localhost:3000 and check the system is running.

Developing new custom components

React and Typescript

The Brill components are developed using React and Typescript. Object Oriented Programming (OOP) is used rather than Functional Programming (FP). We’ve found that using Typescript and OOP results in code that is easier to understand and debug, at least for those of us coming from a Java C++ OOP background.

We use React Components rather than React Hooks, as that fits in with using OOP. But if you wish, you can use JavaScript, FP and Hooks to develop custom components.

Example - Card Component

This is an example Typescript component that displays a Card:

{ return { root: { borderRadius: theme.shape.borderRadius, boxSizing: 'border-box', border: '0.0625rem solid', borderColor: theme.palette.grey.A100, backgroundColor: theme.palette.background.paper, boxShadow: '0 0.125rem 0.3125rem 0 rgba(0,0,0,0.05)' }, title: { backgroundColor: theme.palette.primary.main, lineHeight: '1.5rem', padding: '0.7rem 0.5625rem 0.7rem 0.825rem', borderRadius: '0.1875rem 0.1875rem 0 0', color: theme.palette.primary.contrastText, fontFamily: theme.typography.caption.fontFamily, fontWeight: theme.typography.caption.fontWeight, fontSize: theme.typography.caption.fontSize }, body: { padding: '1rem' }, }} interface Props { id: string theme: ExtendedTheme children: any title: string [propName: string]: any } interface State { } class Card extends Component { render() { const {id, title, theme, classes, children, ...other} = this.props return (
{title}
{children}
) } } export default withStyles(defaultCardStyles, { name: "Card", withTheme: true})(Card)]]>

The first section sets up the styles. Colours are copied from the current Theme.

The Props interface defines the Props that are passed in.

The component doesn’t have any state values.

The render method simply uses div tags to create a Card with a title and child components.

The last line defines the default export class as Card and ensures that the current theme is passed in as a prop.

Interaction with the Server

The Message Broker provides methods that allow a component to subscribe and publish to a topic and also unsubscribe and report errors. When the topic is a server related topic, a message is sent to the server with details of the event. The Middleware documentation contains an example component that interacts with the server using the Message Broker.

Requirements of a Component

All components must reside in a subdirectory under the src/lib/ComponentLibraries directory. This is for security reasons, to prevent pages from referencing code or components outside of the ComponentLibraries directory.

The only other requirement is that the component must export a default class or function. This is required to allow the Router to dynamically load components. A component that’s missing an export default line will result in an error. When re-using previously develop components, you may need to add an export default line.

Application structure

Applications are created using the CMS. The files for an application are held in a directory and subdirectories with the application name.

Each page of the application has a separate JSON page file. The term page is used to refer to a page in the application. This not the same as a web browser page. As far as the web browser is concerned, a React application is just a single web page.

Example application

The page you are currently viewing is part of the brill_software application. These are some of the files that make up the application:

The readEmployeesTable.js file contains JavaScript for retrieving data from the database for the table that’s displayed on the Demo page. The Pages directory holds the pages of the application. The The developers_guide.xml file contains the text you’re currently viewing. The styling is contained in brill_software_theme.json.

Example page

This is the developers_guide.json file:

The ErrorBoundary components catches and handles any errors in the child components.

The ThemeProvider component provides styling to its child components.

The EmbeddedPage component inserts the header and further down the page the footer.

The Container component centres the text area and sets the width.

The ConfluencePage component inserts in texts from the developers_guide.xml file.

IDs within an application

A React component has a key attribute. This is used by React to identify when components have changed and require re-rendering. This is a key feature of React and speeds up the rendering of pages.

The ID on the components in the JSON page file is used as the key. What this means is that a unique ID must be allocated for each component within the application, unless the components really are identical. Should the same ID be used more than once, a component might not get rendered when it should be. The CMS checks the IDs and warns of any issues.

Mapping URL’s and paths to pages

The Router handles mapping of URLs to page files and the loading and rendering of pages. URL’s contain the application name in the path followed by the page. For example:

https://www.brill.software/brill_software/home is mapped to the page file brill_software/Pages/home.json

The Pages directory can have subdirectories.

Developing new Server Event Controllers

The Brill Server is written in Java and uses Spring Boot. The web server is Apache Tomcat.

With REST and Spring Boot, a REST Controller is used to handle requests and return responses. With the Brill Server it makes use of Web Sockets rather than REST. The Brill Server uses WebSocket Controllers that are similar to REST Controllers but matching is based on the Event type and topic. The response is published to the client using a call to a Web Socket service method called sendMessageToClient.

Example - Logged in Users

This example Event controller returns a list of currently logged in users. The code assumes there’s a service available that returns a list of the currently logged in users.

The @WebSocketController annotation marks the class as a Web Socket Controller, as opposed to a REST Controller. The @Event annotation marks the method as a method that is to be called for Web Socket messages that match the event type and topic specified. The Event method calls sendMessageToClient to publish the list to the client.

As it stands, the code would only publish the list of users to the client on receipt of a subscribe event from the client. Additional code could be written that publishes an updated list to all the clients that have a subscription when a user logs in or logs out. Thus the client application could display a list that is dynamically updated.

Building a Production release

Client

First build the client with:

cd ~/Projects/brill_client

yarn build

A build of the client code will take a several minutes. The result will be placed in the build directory.

Server

Once the client has been built, the contents of the client build directory need to be copied to the server directorysrc/main/resources/static. This is so that the Spring Boot Server can serve the React static pages and resources. You can copy the files over manually or make use of the copyWebApp Gradle task as follows:

cd ~/Projects/brill_server

./gradlew copyWebApp

Note that the copyWebApp task assumes that the brill_client build is in ../brill_client/build. The location can be changed in the build.gradle file.

Then build the jar file with:

./gradlew clean build

This will create the jar file in build/libs/brill_server/brill_server-latest.jar

The Jar file can be copied over to the Production environment.

Production Environment

The result of the build process is a Jar file. This can be run from the command line or deployed in any one of a number of ways. Below are suggestions as to best practice.

Application.yml configuration

For a Production server on the Internet, a domain name needs to be registered and a SSL certificate obtained. The certificate public and private keys need to be placed in a Java Keystore and made available to the server. The application.yml file contains the configuration details. This is an example of a Production profile:

yaml

The Spring Boot profile is prod. The server will listen for https requests on port 443 and also listen for http requests on port 80. Any http requests will be redirected onto https. A digital certificate and private key are held in a Java Keystore file called site_keystore.jks. The Keystore resides in the default directory the server runs from. The CMS Repo is held in a subdirectory of BrillAppsRepo.

Initial setup of the Production server

It’s probably easiest to initially set the Production server to use only http and leave configuration of https until after http working. In which case the initial configuration would be:

yaml

User account for running the server

It's recommended that a dedicated user account be setup for running the server. The suggested username is brillserver. The account must be a normal user account, not an administrator, privileged or root account. Take care to ensure that the users home directory, subdirectories and files are owned by the user and have the correct file permissions. Make sure that the group only has read access.

It’s suggested that all the server files are placed in a directory called BrillServer.The Jar file will be in BrillServer/brill_server-latest.jar. The logs will be placed in this directory and the Apps Repository will be in BrillServer/BrillAppsRepo.

Running the server

The server can be run as the brillserver user by logging in and running it from the command line:

java brill_server-latest.jar -Dspring.profiles.active=prod

This checks everything is working, but the server needs to be configured so that it will run up automatically when the machine is rebooted and not require any manual intervention. The configuration depends on the OS.

MacOS

Create the following file in the Launch Daemons directory:

sudo nano /Library/LaunchDaemons/brill.server.plist

xml Label brill.server ProcessType Interactive Disabled RunAtLoad KeepAlive SuccessfulExit AfterInitialDemand SessionCreate LaunchOnlyOnce UserName brillserver GroupName staff ExitTimeOut 600 Program /usr/bin/java ProgramArguments /usr/bin/java -jar -Dspring.profiles.active=prod /Users/brillserver/BrillServer/brill_server-latest.jar WorkingDirectory /Users/brillserver/BrillServer StandardErrorPath /Users/brillserver/BrillServer/log.err StandardOutPath /Users/brillserver/BrillServer/log.out ]]>

The file must be owned by root have have the read/write/execute permissions set. Check the ownership and permissions with:

ls -l /Library/LaunchDaemons/brill.server.plist

Start the server with:

sudo launchctl load /Library/LaunchDaemons/brill.server.plist

To stop the server:

sudo launchctl unload /Library/LaunchDaemons/brill.server.plist

Windows

Use a Windows Server version of Windows rather than Windows 10.

Set up a system process to run the sever.

Linux

Setup a task to run the server on system startup.

Certificates

Any web site that involves user authentication or transactions needs to use https, so that the communications between the client and server are encrypted. This requires a digital certificate to be generated and installed on the server.

Self Signed Certificate

Initially you might want to start with a Keystore that contains a Self Signed Certificate. This can be placed in the same directory as the application.yml file and referenced as:

key-store: classpath:self_signed_cert_keystore.jks

A self signed certificate can be created using keytool. For example:

keytool -genkey -alias selfsigned_localhost_sslserver -keyalg RSA -keysize 2048 -validity 700 -keypass changeit -storepass changeit -keystore ssl-server.jks

The Web Browser will complain about the certificate and say that it’s not trusted but for initially testing thats ok. For Intranet sites, the Self Signed Certificate can be added to the Web Browser's list of Trusted Certificates.

CA Signed Certificate

For an Internet site, the certificate must be signed by a trusted CA. A certificate can be purchased from any one a large number of CA’s. The process depends on the CA but normally involves creating a Certificate Signing Request (CSR) on the Production server and some verification process that confirms that you own and have access to the server.

This is the Namecheap help for creating a CSR using the Java keytool :

https://www.namecheap.com/support/knowledgebase/article.aspx/9422/14/generating-a-csr-on-tomcat-using-a-keytool/

Namecheap has very good documentation but there are of course other providers available!

Use keytool to create the Keystore. For example:

keytool -certreq -alias tomcat -file wwwmysite.csr -keystore my_keystore.jks

For security reasons you might not want to keep the Production Keystore file in git. It needs to be placed in the location specified in the application.yml file.

Once setup correctly, the web site should be accessible using https. Clicking on the lock symbol in the web browser address bar will display the certificate details.

Search Engine Optimisation ( SEO )

Web crawlers such as the Google bot understand JavaScript and will make an attempt to index a React web application. Unfortunately most bots block the JavaScript from making WebSockets connections to the Server. They also block the WebSockets fallback modes and other connections from the client to the server. Given that the pages and content are retrieved using WebSockets or a fallback mode, this presents a problem for getting the pages indexed correctly.

Rather than attempt to put various work arounds into the React application, the Brill Framework allows a set of static pages to be set up and fed to the bots. The static pages match the URLs and structure of the React application. This allows metadata, titles, keywords and content to be optimised for the search engines, without having to modify the main application.

Bots website configuration

To enable a website of static pages for bots, set the server.botsWebsite configuration parametertrue in the application.yml file. For example:

yaml

The bot pages need to be created in the Brill Client project under the directory /public/bots. The directory needs to include all the files that are to be served to bots such as the site_index.html, robots.txt and sitemaps.xml files. Subdirectories need to mirror the React application URLs and have an index.html containing the static HTML for each page.

The Brill Server checks the User-Agent string of http requests and if it’s a bot, serves the bot website. It’s worth copying the robots.txt and sitemaps.xml to the /public directory just in case not all bots are identified. Also copy the any styles.css file to /public in case the search engine caches the page and subsequently requests the styles.css , without identifying itself as a bot.

Google and Bing

Google has a 87% market share of the search engine market with Bing at 7% and Yahoo at 3%. Getting Google and Bing to crawl your site is probably all you’ll need. Yahoo uses Bing.

The first task is to use the Google Search Console to prove to Google that you own and control the site. This can be done by adding a Google supplied identifier to your home page or adding a TX DNS entry with the Google identifier.

The next step is to use the Bing Webmaster Tools to prove who you are. Bing will accept the Google identifier, which is very handy.

Then you need to check the pages using both Bing Webmaster Tools and Google Search Console. There’s a faster turnaround using the Bing Tools. It’s therefore suggested that you use Bing first and then move onto Google.

Your search results raking will largely depend on the number of existing websites that have links to your website.

Brill Software

Brill Demo

Brill CMS

Brill Middleware

Brill Developers Guide

Pricing

Downloads

Contact Us