This is an experimental web framework by me, the documentation for my own use.

Hello World

add libs
* toolkit.jar
* javalightning.jar
create web.xml
<web-app xmlns:xsi=""
	xmlns="" xmlns:web=""
	id="eriklievaart" version="3.0">


create your first url mapping
GET / com.example.HelloWorld#get
create backing bean
package com.example;

import com.eriklievaart.javalightning.api.ResponseBuilder;
import com.eriklievaart.javalightning.api.render.StringRenderer;

public class HelloWorld {
	public void get(ResponseBuilder response) {
		response.setRenderer(new StringRenderer("It Works!"));
open browser @ localhost:8080

URL mapping in route.txt

every entry in this file has 3 whitespace separated entries([METHOD] [PATH] [COMMAND]).

specify a fully qualified path a hash '#' and the method name to indicate a controller method to call as in the hello world example:

GET / com.example.HelloWorld#get
You can specify any HTTP method, so the following example will call HelloWorld.get on a HTTP POST.
POST * com.example.HelloWorld#get
It is possible to use wildcards for the first two fields, the following will pass ALL GET requests to HelloWorld#get:
GET * com.example.HelloWorld#get
If no URL without wildcard matches, then the entries will be processed in order of entry, so the second wildcard will never be called here:
GET /foo/*     com.example.HelloWorld#foo
GET /foo/bar/* com.example.HelloWorld#bar
Use * as command to have an url processed by tomcat normally:
GET /static/test.html *
To process everything in /static normally
GET /static/* *
add the following line to the end of route.txt to have all unmapped urls processed normally by tomcat
* * *


The method name referred to from route.txt must be unique for the class.Parameters are injected dynamically from amongst the following:
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
The easiest way to return a response is using the StringRenderer:
response.setRenderer(new StringRenderer("It Works!"));
By default the FreemarkerRenderer is used, set the view name to load the template (requires freemarker jar on build path)

For example, to load "/WEB-INF/freemarker/render.tpl":

public void get(ResponseBuilder response) {
Use DownloadRenderer to upload a file to the client browser
public void upload(ResponseBuilder response) throws FileNotFoundException {
	response.setRenderer(new DownloadRenderer(new File("/tmp/file.txt")));
Client side redirect (tell the client browser to perform a redirect):
public void external() {
	throw new ExternalRedirectException(new UrlMapping("home", "/"));
Server side redirect (resolve another result internally and push the results to the client)
public void internal() {
	throw new InternalRedirectException(new UrlMapping("home", "/"));
Use ServletReponseRenderer for custom behavior


the main configuration.ini file is loaded from the "/data" directory.This can be changed with a init param for the MvcFilter
add the following to [mvc.config.dir]/config.ini to override the freemarker settings.
The refresh setting is freemarker's template update delay in milliseconds (see the freemarker documentation).The template.dir property can be used as an override for loading templates.The defaults are production settings with a 10 second refresh timeout and templates are loaded from the classpath only.Overriding both settings allows zero turnaround for freemarker template changes.


javalightning makes it possible to create aspects in two simple steps.First we need a java class that implements the AspectController interface:
package com.example;


import javax.servlet.ServletException;

import com.eriklievaart.javalightning.api.FilterContext;
import com.eriklievaart.javalightning.api.aspect.AspectController;
import com.eriklievaart.javalightning.control.RequestController;

public class Aspect implements AspectController {

	private RequestController delegate;

	public void invoke(FilterContext context) throws IOException, ServletException {
		long start = System.currentTimeMillis();
		long spent = System.currentTimeMillis() - start;
		System.out.println("Total time spent on request in millis: " + spent);

	public void setDelegate(RequestController delegate) {
		this.delegate = delegate;
next we need to add a line to "/WEB-INF/mvc/aspects.txt" in the same syntax as used when creating a route:
* * com.example.Aspect
Now the aspect will be called for all configured paths. Only paths filtered by the MvcFilter will be affected.Aspects are processed in order of occurrence in "aspects.txt".Remember to invoke the delegate in the aspect or the request will not be processed further.

Documentation todo's:


antastic config


main-compile toolkit
main-compile javalightning

Javalightning OSGI version


The most basic example of a route (the PageService must be registered as an OSGI service in the activator):
public class SimplePageService implements PageService {
	public String getPrefix() {
		return "prefix";
	public Route[] getRoutes() {
		return new Route[] { new Route("example", EnumSet.of(RouteType.GET), () -> new StringRendererController()) };
associated controller
public class StringRendererController implements PageController {
	public void invoke(ResponseBuilder builder) {
		builder.setRenderer(new StringRenderer("hello<br/><br/>" + new Date()));
accessing the resulting page
firefox localhost:[port]/mvc/prefix/example
wildcard capture
new Route("wildcard/*", EnumSet.of(RouteType.GET), () -> new StringRendererController())
rendering a (freemarker) template
public void invoke(ResponseBuilder response) {
	response.getModel().put("date", new Date());
	response.setRenderer(new TemplateRenderer("/example/freemarker.tpl"));
performing an internal redirect
public void invoke(ResponseBuilder builder) {
	throw new InternalRedirectException(new UrlMapping("internal", "/mvc/prefix/example"));
performing an external redirect
public void invoke(ResponseBuilder builder) {
	throw new ExternalRedirectException(new UrlMapping("github", ""));
dependency injection
public class BeanController implements PageController {
	private HttpServletRequest request;
	private HttpServletResponse response;
	private RequestContext context;
	private HttpSession session;
	private Parameters parameters;

	public void invoke(ResponseBuilder rb) {


making (freemarker) template available in the activator
private ServiceRegistration<TemplateSource> templates;
public void start(BundleContext context) throws Exception {
	ClasspathTemplateSource templateSource = new ClasspathTemplateSource(getClass(), "[prefix]");
	templates = context.registerService(TemplateSource.class, templateSource, new Hashtable<>());
public void stop(BundleContext context) throws Exception {
global variables are exposed through the TemplateSource
ClasspathTemplateSource templateSource = new ClasspathTemplateSource(getClass(), "[prefix]");
templateSource.addGlobal("date", () -> new Date());
referencing the global in the (freemarker) template
referencing a HTTP parameter in the template
${parameter.get('key', 'default')}
getting the remote url of a route
${lightning.getRemotePath('service', 'id')}

osgi properties for configuring the framework (defaults after '=')

remote URL (used in redirects)
a rules file can be used to block urls and to redirect requested paths (e.g. favicon) to different internal paths
com.eriklievaart.javalightning.bundle.rules=[load defaults from classpath]
redirect incoming requests on root to home path
specify directory containing freemarker templates (for real time editing during development)
email properties
logging properties
log to an osgi service
example logging format HH:mm:ss