Gilhari Microservice Framework
for JSON Persistence

Gilhari Microservice Framework

Using Gilhari™

GilhariTM is a microservice framework to provide persistence for JSON objects in relational databases. This microservice framework, available in a Docker image, is configurable as per an app-specific object and relational models. Gilhari exposes a REST (REpresentational State Transfer) interface to provide APIs (POST, GET, PUT, DELETE…) for CRUD (Create, Retrieve, Update, and Delete) operations on the app-specific JSON objects.

There are five easy steps to configure and use the Gilhari microservice framework for a particular app.

Here are some details of the above steps using the example of an object model comprising just one class corresponding to the Employee type of JSON objects with the following four attributes: id, name, exempt, and compensation.  

1. Define and compile empty Java (container) classes corresponding to the conceptual types of your app-specific JSON objects (domain model classes)

In this example, we define a simple Java ontainer class named JSON_Employee (in a file JSON_Employee.java) corresponding to the Employee type of JSON objects. Here, Employee is a conceptual name for a type of JSON objects; Gilhari does not require an actual EC6 style JavaScript class for Employee.

package com.mycompany.myproject.model;

public class JSON_Employee extends JDX_JSONObject {
       public JSON_Employee(){
	  super();
    }

     public JSON_Employee(JSONObject jsonObject) throws JSONException{
	  super(jsonObject);
    }
}

It is a good practice to define a container class within a package (in this case com.mycompany.myproject.model) to encapsulate and identify it in a modular way. The container class should extend the JDX_JSONObject class provided by JDX ORM, and have two constructors as shown above. This (empty) container class does not need to declare any primitive attributes.  

Please note that for defining any new container class X, you just have to create an X.java file and change JSON_Employee to X at three places in the code above.  

The container classes should be compiled (using javac) for JDX ORM to use them.  

2. Define a declarative Object Relational Mapping (ORM) specification on those domain model classes mapping corresponding attributes of the JSON objects

We define an ORM specification for an app in a mapping file (e.g., myproject.jdx) textually. Here is the declarative ORM specification for the attributes of our Employee JSON objects:

CLASS com.mycompany.myproject.model.JSON_Employee

// First declare all the persistent JSON properties
VIRTUAL_ATTRIB id ATTRIB_TYPE int
VIRTUAL_ATTRIB name ATTRIB_TYPE java.lang.String
VIRTUAL_ATTRIB exempt ATTRIB_TYPE boolean
VIRTUAL_ATTRIB compensation ATTRIB_TYPE double

// Now provide the rest of the mapping specification for this class
PRIMARY_KEY id
SQLMAP FOR compensation COLUMN_NAME salary  
;

The names and Java types of the persistent properties (id, name, exempt, compensation) of the model Employee JSON objects are declared with VIRTUAL_ATTRIB specifications. This mapping specification is non-intrusive to the domain model classes or to the JSON objects of your app.  

Please note that if we have more types of JSON objects in our app, we define the corresponding container classes and add the ORM specification for those classes in the same mapping file.  

The mapping file also contains the JDBC driver name, the JDBC URL of the target database, and the login credentials (for brevity, not shown above in the mapping snippet). The login credentials may be overridden at runtime (see Note 5 below).  

Please make sure that the database is accessible from the container using the specified URL. For example, you may need to change “localhost” to an appropriate IP address applicable for your database instance.  

3. Create a Dockerfile with commands to combine/configure the base Gilhari image (gilhari) with the app-specific artifacts

We create a text file named Dockerfile that contains commands to combine/configure the base Gilhari microservice framework with our app-specific artifacts like domain model classes, ORM specification, JDBC driver, communication ports, etc.

Let’s assuming that we have the following directory structure where angle brackets denote a directory name:

-- <BaseDir>
   -- <bin>  (See Note 1)           
   -- <config>        
      -- myproject.jdx    (See Note 2)
      -- classNamesMapping.js    (See Note 3)
      -- mysql-connector-java-5.1.39-bin.jar    (See Note 4)  
   -- gilhari_service.config    (See Note 5)
   -- Dockerfile    (See Note 6)

Note 1: This directory contains the compiled .class files for the object model.

Note 2: This text file contains the declarative ORM specification.

Note 3: This optional JSON format file contains the mapping between the conceptual type names of the JSON objects and the corresponding Java class names. This is to potentially simplify the usage of the class names in the URIs of the REST calls. For example, by specifying the following mapping, you may use just “Employee” in your REST APIs instead of a fully qualified Java class name:

{"Employee":  "com.mycompany.myproject.model.JSON_Employee"}

Note 4: This is a JDBC driver file for your database.

Note 5: This file contains various configuration information including the location of mapping files, JDBC driver, compiled .class files for the object model, and ports for the app-specific Gilhari microservice. Here is an example gilhari_service.config file:

{"jdx_orm_spec_file": "./config/myproject.jdx",
 "jdbc_driver_path": "./config/mysql-connector-java-5.1.39-bin.jar",
 "db_username": "mySecretUserName",
 "db_password": "mySecretPassword",
 "jdx_debug_level": 3,
 "jdx_force_create_schema": "true",
 "jdx_persistent_classes_location": "./bin",
 "classnames_map_file": "config/classNamesMapping.js",
 "gilhari_rest_server_port": 8081
 }

Most of the settings in the above example are self-explanatory.

Here is a brief explanation:

    "jdx_orm_spec_file": The name and location of the ORM specification file (e.g., myproject.jdx located in the config directory), which contains the mapping specification for the persistent (container) classes used by JDX ORM.

    "jdbc_driver_path": The location of the JDBC driver (.jar) file to be used for accessing the relational data source. A JDBC driver for SQLite database has already been added as a default JDBC driver in the classpath. If you are using a different database, the path to the corresponding JDBC driver (.jar) should be specified here.

    "db_username": This optional setting may be used to override the database username specified in the ORM specification file.

    "db_password": This optional setting may be used to override the database password specified in the ORM specification file.

    "jdx_debug_level": A value in the range from 0 to 5 (e.g., 3) for getting the debug output from the JDX ORM engine. Use 0 for the most verbose output and 5 for the minimal output. A value of 3 will output all the SQL statements used by JDX. Default is 5.

    "jdx_force_create_schema”: Specifies if the database schema should be freshly created every time the server is run. Default is "false".

      A value of "true" means yes => could be useful during development phase when the object model and the mapping are changing frequently.

      A value of "false" means no => the schema will be created only the first time the service is run. Appropriate for using existing data in a legacy relational database where you don’t want to discard the old data by creating a fresh schema.

    "jdx_persistent_classes_location”: Specifies the root location (e.g., ./bin directory) for the compiled persistent (container) classes. This could also be the path of a jar file. Used as a java CLASSPATH.

    "classnames_map_file": This is an optional JSON format file consisting of the mappings between the conceptual JSON class names and the corresponding persistent (container) class names used by JDX ORM. If this file is not specified or if it does not contain the mapping for a conceptual JSON class specified in a REST URL, the specified class name in the URL is used as is by the JDX ORM engine.

    "gilhari_rest_server_port": The port number (e.g., 8081) where the service listens to the RESTful requests. Default is 8081. This port may be mapped to different port number (e.g., 80) by a Docker run command.

Note 6: This (Dockerfile) text file contains the commands to create the app-specific Docker image for the Gilhari microservice starting with a base Gilhari Docker image (gilhari) and then adding the above configuration information. Here is an example of a Dockerfile file:

FROM dperiwal/st_repo:gilhari  (See Note 7)

WORKDIR /opt/gilhari_simple_example   (See Note 8)

ADD bin ./bin
ADD config ./config
ADD gilhari_service.config .

EXPOSE 8081 
CMD <gilhari_rest_server> gilhari_service.config   (See Note 9)

Note 7: This (FROM) command sets the starting image as gilhari, which is the base Docker image for the Gilhari microservice. In the subsequent commands, app-specific configuration information is added on top of this base image.

Note 8: This (WORKDIR ) command changes the active directory in your app-specific Docker container to /opt/gilhari_simple_example. This directory is used to populate the configuration information for your particular app as you can see in the subsequent ADD commands.

Note 9: This command, specified using the CMD keyword, runs an instance of the Gilhari microservice passing it the app-specific configuration information through the command line parameter.

4. Using the Dockerfile, build a Docker image for the app-specific Gilhari microservice (e.g., my_app_gilhari)

Run a docker build command with the Dockerfile file described above, to create the Docker image for the app-specific Gilhari microservice (e.g., my_app_gilhari). For example,

docker build -t my_app_gilhari:1.0 -f ./Dockerfile

Note: The docker build command, by default, works on a local Dockerfile, if available. So the above command may be simplified as:

docker build -t my_app_gilhari:1.0

5. Deploy and run the app-specific Gilhari microservice (my_app_gilhari) in a Docker container to provide the RESTful APIs for persistence of your app-specific JSON objects

You may register the previously built app-specific Gilhari microservice image (my_app_gilhari) in a container registry for subsequent deployment in a Docker container. You may use a Kubernetes service to orchestrate the deployment and scaling of your app-specific Gilhari microservice.

You may also run the app-specific Gilhari microservice image (my_app_gilhari) in a Docker container from the command line as follows:

docker run -p 80:8081 my_app_gilhari:1.0

After the app-specific Gilhari microservice (my_app_gilhari) image starts running in a Docker container, you can start using the REST APIs to persist app-specific JSON objects. The REST APIs exposed by the Gilhari microservice are explained here.