synapticloop / h2zero-extension-routemaster-restful

Repository from Github https://github.comsynapticloop/h2zero-extension-routemaster-restfulRepository from Github https://github.comsynapticloop/h2zero-extension-routemaster-restful

This project requires JVM version of at least 1.7

h2zero-extension-routemaster-restful top

Routemaster extension for h2zero to generate restful services

Table of Contents top

Overview top

This project is an extension to h2zero that generates a restful interface to the database (GET, POST, PUT, DELETE).

What you need to do top

  1. Create an extension class that extends synapticloop.h2zero.extension.Extension
  2. Implement the public void generate(JSONObject extensionOptions, Database database, Options options, File outFile, boolean verbose) throws RenderException, ParseException; method
  3. Set-up the h2zero file:
  4. Away you go

The h2zero configuration file top

see the src/test/resources/sample-include-sqlite3.h2zero file for a configuration example below

A simple (ish) example top

The main class entry point is the RoutemasterRestfulServletExtension.java

{
"options": {
	"metrics": false,
	"database": "sqlite3",

	"generators": [ "java", "sql", "reports" ],

	"extensions" : [
		"synapticloop.h2zero.extension.routemaster.RoutemasterRestfulServletExtension"
	],
	
	"synapticloop.h2zero.extension.routemaster.RoutemasterRestfulServletExtension": {
		"pathPrefix": "extension"
	},

	"validators": {
		"UpdaterNameValidator": {
			"allowablePrefixes": "reset,"
		},

		"FinderNameValidator": {
			"allowablePrefixes": "find,calculate"
		}
	},

	"output": {
		"code": "src/test/java/",
		"resources": "src/test/resources/",
		"build": "build/"
	}
},

"database": {
	"schema": "sample",
	"package": "synapticloop.sample.h2zero.sqlite3",
	"defaultStatementCacheSize": 1024,

	"tables": [
		{ "include": "./user_type.json" },
		{ "include": "./user_title.json" },
		{ "include": "./user.json" },
		{ "include": "./pet.sqlite3.json" },
		{ "include": "./user_pet.json" }
	],

	"views": [
		{ "include": "./view-pet.json" },
	]
}
}

Things to note from the above top

  "options:{
  
  ...
  
  
    "extensions" : [
        "synapticloop.h2zero.extension.routemaster.RoutemasterRestfulServletExtension"
    ],
    
    "synapticloop.h2zero.extension.routemaster.RoutemasterRestfulServletExtension": {
        "pathPrefix": "extension"
    },
    
  ...
  
  }

Extension are placed in the String JSON Array with the extensions key. For any other options or configuration that is required by the extension, place another JSON object within the options object key on the class name that the extension uses.

A simple (ish) example top

The main class entry point is the RoutemasterRestfulServletExtension.java

package synapticloop.h2zero.extension.routemaster;

/*
 * Copyright (c) 2018 synapticloop.
 * 
 * All rights reserved.
 *
 * This source code and any derived binaries are covered by the terms and
 * conditions of the Licence agreement ("the Licence").  You may not use this
 * source code or any derived binaries except in compliance with the Licence.
 * A copy of the Licence is available in the file named LICENCE shipped with
 * this source code or binaries.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * Licence for the specific language governing permissions and limitations
 * under the Licence.
 */

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONObject;

import synapticloop.h2zero.extension.Extension;
import synapticloop.h2zero.model.Database;
import synapticloop.h2zero.model.Options;
import synapticloop.h2zero.model.Table;
import synapticloop.h2zero.validator.BaseValidator;
import synapticloop.templar.Parser;
import synapticloop.templar.exception.ParseException;
import synapticloop.templar.exception.RenderException;
import synapticloop.templar.utils.TemplarContext;

/**
 * This extension generates files that create a RESTful interface to a database 
 * through RouteMaster, based on NanoHTTPD
 */
public class RoutemasterRestfulServletExtension extends Extension {

	@Override
	public void generate(JSONObject extensionOptions, Database database, Options options, File outFile, boolean verbose) throws RenderException, ParseException {
		// you __ALWAYS__ want to get the defaultTemplarContext.
		TemplarContext templarContext = getDefaultTemplarContext(extensionOptions, database, options);

		// write out the BaseRestServant class
		writeBaseRestServant(database, options, outFile, verbose, templarContext);

		// write out the rest servants, one for each table
		writeRestServants(database, options, outFile, verbose, templarContext);

		// write out the routemaster routes file
		writeRestServantRoutes(database, options, outFile, verbose, templarContext);
	}

	/**
	 * Write out the base rest servant - which is a single class, upon which all 
	 * other files are dependent.
	 * 
	 * @param database The h2zero database model
	 * @param options The h2zero options
	 * @param outFile The base directory
	 * @param verbose whether the user wants verbose output
	 * @param templarContext the templar context
	 * 
	 * @throws ParseException If there was an error parsing the templar template
	 * @throws RenderException If there was an error rendering the file
	 */
	private void writeBaseRestServant(Database database, Options options, File outFile, boolean verbose, TemplarContext templarContext) throws ParseException, RenderException {
		// get the templar parser
		Parser baseRestServantTemplarParser = getParser("/java-create-routemaster-base-rest-servant.templar", verbose);

		// determine the file path
		String pathname = outFile + options.getOutputCode() + database.getPackagePath() + "/routemaster/servant/BaseServant.java";

		// render to the file
		renderToFile(templarContext, baseRestServantTemplarParser, pathname, verbose);
	}

	/**
	 * Write out the RESTful servant, one for each table
	 * 
	 * @param database The h2zero database model
	 * @param options The h2zero options
	 * @param outFile The base directory
	 * @param verbose whether the user wants verbose output
	 * @param templarContext the templar context
	 * 
	 * @throws ParseException If there was an error parsing the templar template
	 * @throws RenderException If there was an error rendering the file
	 */
	private void writeRestServants(Database database, Options options, File outFile, boolean verbose, TemplarContext templarContext) throws RenderException, ParseException {
		// get the templar parser
		Parser restServantTemplarParser = getParser("/java-create-routemaster-rest-servant.templar", verbose);

		// get all of the tables
		List<Table> tables = database.getTables();
		for (Table table : tables) {
			// for each table, add it to the context
			templarContext.add("table", table);

			// determine the file path
			String pathname = outFile + options.getOutputCode() + database.getPackagePath() + "/routemaster/servant/" + table.getJavaClassName() + "Servant.java";

			// render to the file
			renderToFile(templarContext, restServantTemplarParser, pathname, verbose);
		}
	}

	/**
	 * Write out the example routes for the RESTful interface
	 * 
	 * @param database The h2zero database model
	 * @param options The h2zero options
	 * @param outFile The base directory
	 * @param verbose whether the user wants verbose output
	 * @param templarContext the templar context
	 * 
	 * @throws ParseException If there was an error parsing the templar template
	 * @throws RenderException If there was an error rendering the file
	 */
	private void writeRestServantRoutes(Database database, Options options, File outFile, boolean verbose, TemplarContext templarContext) throws ParseException, RenderException {
		// get the templar parser
		Parser baseRestServantTemplarParser = getParser("/java-create-routemaster-rest-servant-routes.templar", verbose);

		// render to the file
		String pathname = outFile + options.getOutputResources() + "routemaster.rest.properties";

		// render to the file
		renderToFile(templarContext, baseRestServantTemplarParser, pathname, verbose);
	}

	@Override
	public List<BaseValidator> getValidators() {
		return(new ArrayList<BaseValidator>());
	}

}


Things to note top

Looking at the above class, it is relatively straight-forward to generate multiple files. Below is a list of things to note:

Always get the default context top

        // you __ALWAYS__ want to get the defaultTemplarContext.
        TemplarContext templarContext = getDefaultTemplarContext(extensionOptions, database, options);

This will set everything up, and place the following things into the context.

		TemplarContext templarContext = new TemplarContext(templarConfiguration);
		templarContext.add(JSONKeyConstants.DATABASE, database);                    // key is "database"
		templarContext.add(JSONKeyConstants.OPTIONS, options);                      // key is "options"
		templarContext.add(JSONKeyConstants.EXTENSION_OPTIONS, extensionOptions);   // key is "extensionOptions"

Get the parser top

Use the getParser("/classpath/to/template.templar", verbose) method which will set up the parser for you.

Render top

Use the renderToFile(templarContext, templarParserFile, "output/path/file.name", verbose); which will also add the output to the summary statistics.

Building the Package top

*NIX/Mac OS X top

From the root of the project, simply run

./gradlew build

Windows top

./gradlew.bat build

This will compile and assemble the artefacts into the build/libs/ directory.

Note that this may also run tests (if applicable see the Testing notes)

How to test top

As the extension will generate additional code for the project, there is a slight roundabout way of testing the code.

  1. build the code and publish it to maven local
  2. have a separate build.gradle file that will reference the class path (including maven local repository)

The simplest way is to:

gradle build -x test

then

gradle -b build.h2zero.sqlite3.gradle h2zero

or more simply (for *NIX machines)

gradle build -x test; gradle -b build.h2zero.sqlite3.gradle h2zero

Running the Tests top

*NIX/Mac OS X top

From the root of the project, simply run

gradle --info test

if you do not have gradle installed, try:

gradlew --info test

Windows top

From the root of the project, simply run

gradle --info test

if you do not have gradle installed, try:

./gradlew.bat --info test

The --info switch will also output logging for the tests

Dependencies - Gradle top

dependencies {
	runtime(group: 'synapticloop', name: 'h2zero-extension-routemaster-restful', version: '2.1.0', ext: 'jar')

	compile(group: 'synapticloop', name: 'h2zero-extension-routemaster-restful', version: '2.1.0', ext: 'jar')
}

or, more simply for versions of gradle greater than 2.1

dependencies {
	runtime 'synapticloop:h2zero-extension-routemaster-restful:2.1.0'

	compile 'synapticloop:h2zero-extension-routemaster-restful:2.1.0'
}

Dependencies - Maven top

<dependency>
	<groupId>synapticloop</groupId>
	<artifactId>h2zero-extension-routemaster-restful</artifactId>
	<version>2.1.0</version>
	<type>jar</type>
</dependency>

Dependencies - Downloads top

You will also need to download the following dependencies:

cobertura dependencies

  • net.sourceforge.cobertura:cobertura:2.1.1: (It may be available on one of: bintray mvn central)

compile dependencies

runtime dependencies

shadow dependencies

testCompile dependencies

testRuntime dependencies

NOTE: You may need to download any dependencies of the above dependencies in turn (i.e. the transitive dependencies)

--

This README.md file was hand-crafted with care utilising synapticlooptemplar->documentr

--

About


Languages

Language:Java 99.8%Language:Shell 0.2%