• Stars
    star
    209
  • Rank 187,768 (Top 4 %)
  • Language
    Java
  • License
    MIT License
  • Created about 10 years ago
  • Updated 12 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

CircleCI codecov

Java HTTP-server

server based on my epoll

HttpServer<HttpConnection> server = new HttpServer<>(8080);
server.getUrlMapping()
        .append("/", (request, response) -> response.setBody("It's alive!"));
server.start();

Framework


Installation ↑

Gradle
build.gradle
apply plugin: 'java'
apply plugin: 'application'

repositories {
    jcenter()
    mavenCentral()
    maven {
        url "https://oss.sonatype.org/content/repositories/snapshots/"
    }
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

version = '0.1'

mainClassName = "com.example.MyWebApp"

dependencies {
    compile 'com.wizzardo:http:0.2+'
}

//create a single Jar with all dependencies
task fatJar(type: Jar) {
    manifest {
        attributes(
                "Main-Class": mainClassName
        )
    }
    baseName = project.name + '-all'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

Initialization ↑

import com.wizzardo.http.framework.Controller;
import com.wizzardo.http.framework.Environment;
import com.wizzardo.http.framework.WebApplication;
import com.wizzardo.http.framework.template.Renderer;

public class MyWebApp {

    static class AppController extends Controller {
        public Renderer index() {
            return renderString("It's alive!");
        }
    }

    public static void main(String[] args) {
        WebApplication application = new WebApplication(args);
        application.onSetup(app -> {
            app.getUrlMapping()
                    .append("/", AppController.class, "index");
        });
        application.start();
    }
}

Building and running ↑

./gradlew fatJar
java -jar build/libs/MyWebApp-all.jar env=prod profiles.active=profile_A,profile_B

Url-mapping ↑

Controllers and actions could be mapped to static paths or to something dynamic with variables and wildcards

urlMapping
    .append("/index", AppController.class, "index")
    .append("/books/$id?", AppController.class, "books") // 'id' - is optional
    .append("/optionals/$foo?/$bar?", AppController.class, "optionals") // 'foo' and 'bar' - are optional
    .append("/${foo}-${bar}", AppController.class, "fooBar")
    .append("/any/*", AppController.class, "any")
    .append("*.html", AppController.class, "html")
    .append("/upload", AppController.class, "upload", Request.Method.POST) // only POST method is allowed
    ;

Dependency injection ↑

Framework supports simple dependency injections, to make class or interface injectable simple annotate it with @Injectable.

There are several scopes for it:

  • SINGLETON - one instance per jvm, default
  • PROTOTYPE - new instance for every injection
  • SESSION - one instance per user-session
  • REQUEST - new instance every request
  • THREAD_LOCAL - one instance per thread

Controllers are stateful so their scope is PROTOTYPE, Services - SINGLETON.

static class AppController extends Controller {
    AppService appService;

    public Renderer index() {
        return renderString(appService.getMessage());
    }
}

To make dependency injection work with implicit dependencies, you need to specify package for scan:

    application.onSetup(app -> {
        DependencyFactory.get(ResourceTools.class)
                .addClasspathFilter(className -> className.startsWith("com.example"));
    });
Raw usage of DI
DependencyFactory.get().register(CustomBean.class, new SingletonDependency<>(CustomBean.class));
CustomBean bean = DependencyFactory.get(CustomBean.class);

Configuration ↑

src/main/resources/Config.groovy
server {
    host = '0.0.0.0'
    port = 8080
    ioWorkersCount = 1
    ttl = 5 * 60 * 1000
    context = 'myApp'
    basicAuth {
        username = 'user'
        password = 'pass'
        token = true
        tokenTTL = 7 * 24 * 60 * 60 * 1000l
        tokenized { // creates mapping with path '/resourceName/*' and respective name for static resources available by token
            resourceName = 'path/to/resource'
        }
    }

    ssl {
        cert = '/etc/ssl/certs/hostname.crt'
        key = '/etc/ssl/private/hostname.key'
    }
    
    session {
        ttl = 30 * 60
    }
    
    resources {
        path = 'public' // load static files from resource folder 'public'
        mapping = '/static'
        cache = {
            enabled = true
            gzip = true
            ttl = -1L
            memoryLimit = 32 * 1024 * 1024L
            maxFileSize = 5 * 1024 * 1024L
        }
    }
    debugOutput = false // dump of all requests and responses to System.out
}
//this configuration will be only applied for certain environment
environments {
    dev {
        custom.key = true
    }
    prod {
        custom.key = false
        server.ioWorkersCount = 4
    }
}

//this configuration will be only applied for certain profiles
profiles {
    profile_A {
        environments {
            dev {
                value = 'value_dev_A'
            }
            prod {
                value = 'value_prod_A'
            }
        }
    }
    profile_B {
        value = 'value_B'
    }
}

Configuration stored in Holders:

    boolean key = Holders.getConfig().config("custom").get("key", defaulValue);

or it can be mapped to pojo and injected to other objects:

public class CustomConfig implements Configuration {
    public boolean key;

    @Override
    public String prefix() {
        return "custom";
    }
}

Configuration is loaded in this order:

  • Default configuration and manifest
  • Config.groovy
  • External configuration (webApp.onLoadConfiguration(app -> app.loadConfig("MyCustomConfig.groovy")))
  • Profiles and environments
  • OS environment variables (System.getenv())
  • Java System properties (System.getProperties())
  • Command line arguments

Template engine ↑

This framework has it's own template engine, inspired and based on Groovy Server Pages (GSP)

static class AppController extends Controller {
    public Renderer index() {
        model().append("name", params().get("name", "%user name%"));
        return renderView();
    }
}

Engine will try to render html from template 'resources/views/controller_name/view_name.gsp', by default 'view_name' is 'action_name':

src/main/resources/views/app/index.gsp
<html>
   <head>
      <title>Hello</title>
   </head>
   <body>
      Hello, ${name}!
   </body>
</html>

i18n ↑

    MessageBundle ms = DependencyFactory.get(MessageBundle.class);

    //load message bundle from resources/i18n/messages.properties
    //and lazy load any other language, for example messages_en.properties, messages_fr.properties
    ms.load("messages");

    String foo = ms.get("foo");
    String fooDe = ms.get(Locale.GERMANY,"foo");

    //it also supports templates
    //foobar = {0} {1}
    String foobar = ms.get("foobar", "foo", "bar"); // "foo bar"

Taglib ↑


checkBox ↑

Generates a checkbox form field.

Template:
<g:checkBox name="myCheckbox" value="${true}"/>
<g:checkBox name="myCheckbox" id="myCheckbox_${1}" checked="${true}"/>
Result:
<input type="checkbox" name="myCheckbox" id="myCheckbox" value="true"/>
<input type="checkbox" name="myCheckbox" id="myCheckbox_1" checked="checked"/>
Attributes
  • name - The name of the checkbox
  • value (optional) - The value of the checkbox
  • checked (optional) - Expression if evaluates to true sets to checkbox to checked

collect ↑

Iterate over each element of the specified collection transforming the result using the expression in the closure

Template:
<div>
    <g:collect in="${books}" expr="${it.title}">
        $it<br/>
    </g:collect>
</div>
Action:
model().append("books", Arrays.asList(new Book("Book one"), new Book("Book two")))
Book.java:
public class Book {
    public final String title;

    public Book(String title) {
        this.title = title;
    }
}
Result:
<div>
    Book one
    <br/>
    Book two
    <br/>
</div>
Attributes
  • in - The object to iterative over
  • expr - A expression

createLink ↑

Creates a link that can be used where necessary (for example in an href, JavaScript, Ajax call etc.)

Controller:

public class BookController extends Controller {

    public Renderer list() {
        return renderString("list of books");
    }

    public Renderer show() {
        return renderString("some book");
    }
}

url-mapping:

app.getUrlMapping()
        .append("/book/list", BookController.class, "list")
        .append("/book/$id", BookController.class, "show");
Template:
// generates <a href="/book/1">link</a>
<a href="${createLink([controller:'book', action:'show', id: 1])}">link</a>

// generates "/book/show?foo=bar&boo=far"
<g:createLink controller="book" action="show" params="[foo: 'bar', boo: 'far']"/>

// generates "/book/list"
<g:createLink controller="book" action="list" />

// generates "http://localhost:8080/book/list"
<g:createLink controller="book" action="list" absolute="true"/>

// generates "http://ya.ru/book/list"
<g:createLink controller="book" action="list" base="http://ya.ru"/>
Attributes:
  • action (optional) - The name of the action to use in the link; if not specified the current action will be linked
  • controller (optional) - The name of the controller to use in the link; if not specified the current controller will be linked
  • id (optional) - The id to use in the link
  • fragment (optional) - The link fragment (often called anchor tag) to use
  • mapping (optional) - The named URL mapping to use, default mapping = controllerName + '.' + actionName
  • params (optional) - A Map of request parameters
  • absolute (optional) - If true will prefix the link target address with the value of the server.host property from config
  • base (optional) - Sets the prefix to be added to the link target address, typically an absolute server URL. This overrides the behaviour of the absolute property if both are specified.

each ↑

Iterate over each element of the specified collection.

Template:
<div>
    <g:each in="[1,2,3]" var="i">
        $i<br/>
    </g:each>
</div>
Result:
<div>
    1
    <br/>
    2
    <br/>
    3
    <br/>
</div>
Attributes:
  • in - The collection to iterate over
  • status (optional) - The name of a variable to store the iteration index in. Starts with 0 and increments for each iteration.
  • var (optional) - The name of the item, defaults to "it".

else ↑

The logical else tag

Template:
<g:if test="${false}">
    never happen
</g:if>
<g:else>
    Hello, world!
</g:else>
Result:
    Hello, world!

elseif ↑

The logical elseif tag

Template:
<g:if test="${false}">
    never happen
</g:if>
<g:elseif test="${true}">
    Hello, world!
</g:elseif>
Result:
    Hello, world!
Attributes:
  • test - The expression to test

form ↑

Creates a form, extends 'createLink' tag


##### formatBoolean [↑](#taglib) Outputs the given boolean as the specified text label.
Template:
<g:formatBoolean boolean="${myBoolean}" />
<g:formatBoolean boolean="${myBoolean}" true="True!" false="False!" />
Result:
true
True!
Attributes:
  • boolean - Variable to evaluate
  • true (optional) - Output if value is true. If not specified, 'boolean.true' or 'default.boolean.true' is looked up from the Message Source
  • false (optional) - Output if value is false. If not specified, 'boolean.false' or 'default.boolean.false' is looked up from the Message Source

hiddenField ↑

Creates a input of type 'hidden' (a hidden field).

Template:
<g:hiddenField name="myField" value="myValue" />
Result:
<input type="hidden" name="myField" id="myField" value="myValue"/>
Attributes:
  • name - The name of the text field
  • value (optional) - The value of the text field

if ↑

The logical if tag to switch on an expression.

Template:
<g:if test="${true}">
    Hello!
</g:if>
Result:
    Hello!
Attributes:
  • test - The expression to test

join ↑

Concatenate the toString() representation of each item in this collection with the given separator.

Template:
<g:join in="['Hello', 'World!']" delimiter=", "/>
Result:
Hello, World!
Attributes:
  • in - The collection to iterate over
  • delimiter (optional) - The value of the delimiter to use during the join. Default: ', '

layoutBody ↑

Used in layouts to output the contents of the body tag of the decorated page.

Decorated page template:
<html>
   <head>
        <meta name="layout" content="myLayout" />
        <script src="myscript.js" />
   </head>
   <body>Page to be decorated</body>
</html>
Layout template views/layouts/myLayout.gsp:
<html>
   <head>
        <script src="global.js" />
        <g:layoutHead />
   </head>
   <body><g:layoutBody /></body>
</html>
Result:
<html>
   <head>
        <script src="global.js" />
        <script src="myscript.js" />
   </head>
   <body>Page to be decorated</body>
</html>

layoutHead ↑

Used in layouts to render the contents of the head tag of the decorated page

Decorated page template:
<html>
   <head>
        <meta name="layout" content="myLayout" />
        <script src="myscript.js" />
   </head>
   <body>Page to be decorated</body>
</html>
Layout template views/layouts/myLayout.gsp:
<html>
   <head>
        <script src="global.js" />
        <g:layoutHead />
   </head>
   <body><g:layoutBody /></body>
</html>
Result:
<html>
   <head>
        <script src="global.js" />
        <script src="myscript.js" />
   </head>
   <body>Page to be decorated</body>
</html>

layoutTitle ↑

Used in layouts to render the contents of the title tag of the decorated page

Decorated page template:
<html>
   <head>
        <meta name="layout" content="myLayout" />
        <title>Hello World!</title>
        <script src="myscript.js" />
   </head>
   <body>Page to be decorated</body>
</html>
Layout template views/layouts/myLayout.gsp:
<html>
   <head>
		<title><g:layoutTitle default="Some Title" /></title>
        <script src="global.js" />
        <g:layoutHead />
   </head>
   <body><g:layoutBody /></body>
</html>
Result:
<html>
   <head>
        <title>Hello World!</title>
        <script src="global.js" />
        <script src="myscript.js" />
   </head>
   <body>Page to be decorated</body>
</html>

link ↑

Creates an html anchor tag with the href set based on the specified parameters. Extends 'createLink' tag.

Template:
<g:link controller="book" action="show" params="[id: 1]">link</g:link>
Result:
<a href="/book/1">link</a>
Attributes:

same as in createLink tag


message ↑

Resolves a message from the given code.

Template:
// test.message.1.args = test message: {0}
<g:message code="test.message.${1}.args" args="['one']"/>
Result:
test message: one
Attributes:
  • code - The code to resolve the message for.
  • default (optional) - The default message to output if the error or code cannot be found in messages.properties.
  • args (optional) - A list of argument values to apply to the message when code is used.
  • locale (optional) Override Locale to use instead of the one detected

passwordField ↑

Creates a input of type 'password' (a password field). An implicit "id" attribute is given the same value as name unless you explicitly specify one.

Template:
<g:passwordField name="myPasswordField" value="${'myPassword'}" />
Result:
<input type="password" name="myPasswordField" id="myPasswordField" value="myPassword" />
Attributes:
  • name - The name of the password field
  • value - The value of the password field

radio ↑

Generates a radio button

Template:
<g:radio name="myGroup" value="1"/>
<g:radio name="myGroup" value="2" checked="true"/>
Result:
<input type="radio" name="myGroup" value="1" />
<input type="radio" name="myGroup" checked="checked" value="2" />
Attributes:
  • value - The value of the radio button
  • name - The name of the radio button
  • checked - boolean to indicate that the radio button should be checked

resource ↑

Generates a link (URI) string for static resources. Can be used in an href, JavaScript, Ajax call, etc.

Template:
<g:resource dir="css" file="main.css" />
<g:resource dir="css" file="main.css" absolute="true" />
<g:resource dir="js" file="test.js"/>
<img src="${resource(dir:'img', file:'logo.jpg')}">
<g:resource dir="js" file="test.tag" tag="script" url="src" type="riot/tag"/>
Result:
<link rel="stylesheet" href="/static/css/main.vEA6A.css">
<link rel="stylesheet" href="http://localhost:8080/static/css/main.vEA6A.css">
<script type="text/javascript" src="/static/js/test.v207A.js"></script>
<img src="/static/img/logo.v53B0.jpg"/>
<script type="riot/tag" src="/static/js/test.v73CF.tag"></script>
Attributes:
  • dir - the name of the directory containing the resource
  • file - the name of the resource file
  • tag - the name of the html tag
  • url - the name of the attribute for the url
  • absolute - If true will prefix the link target address with the value of the host property from Config.groovy.

set ↑

Sets the value of a variable accessible with the GSP page.

Template:
<g:set var="counter" value="${0}" />
<g:while test="${counter < 3}">
    <p>Current i = ${i}</p>
    <g:set var="counter" value="${counter + 1}" />
</g:while>
Result:
    <p>Current i = 0</p>
    <p>Current i = 1</p>
    <p>Current i = 2</p>
Attributes:
  • var - The name of the variable
  • value - The initial value

textArea ↑

Creates a HTML text area element. An implicit "id" attribute is given the same value as name unless you explicitly specify one.

Template:
<g:textArea name="myField" value="myValue" rows="5" cols="40"/>
Result:
<textarea name="myField" id="myField" rows="5" cols="40" >
myValue
</textarea>>
Attributes:
  • name - The name of the text area
  • value - The initial text to display in the text area. By default the text area will be empty.

textField ↑

Creates a input of type 'text' (a text field). An implicit "id" attribute is given the same value as the name unless you explicitly specify one.

Template:
<g:textField name="myField" value="${'input'}" />
Result:
<input type="text" name="myField" id="myField" value="input" />
Attributes:
  • name - The name of the text field
  • value - The initial text to display in the text field. By default the text field will be empty.

while ↑

Executes a condition in a loop until the condition returns false.

Template:
<g:while test="${i < 3}">
    <p>Current i = ${i++}</p>
</g:while>
Result:
    <p>Current i = 0</p>
    <p>Current i = 1</p>
    <p>Current i = 2</p>
Attributes:
  • test - The conditional expression