mtwin.web.handler

mtwin.web.Handler

Introduction

A web handler is a class, which, given an URL, can decide which action the server application has to execute.

For instance, the url http://www.domain.com/index.n/user/10/view may be understood as : view the User object which id is 10.

To achieve this the server defines a main Handler, this handler will bound 'user' to another handler which in turn will understand how to deal with User objects.

In our example :

MainApplicationHandler 
    - bind path 'user' -> UserHandler

The UserHandler will provide a method to retrieve a User by its id (10) and will bound the action 'view' to one of its method :

UserHandler (handle User objects)
    - implements findObject(id:Int)
    - bind path 'view' -> doViewUser(u:User)

The mtwin.web.Handler contains some rights restriction features which reduce dramatically the amount of code required to produce clean and secure web applications.

First example

/**
Main web application class.
**/
class MyWebApplication {
    // mtwin.web.Request represents the current http request with url, parameters, etc...
    static var request : mtwin.web.Request;
    // for this example we will use mtwin.templo XHTML template engine
    static var template : mtwin.templo.Loader;
    // this is some dynamic template context for templo
    static var context : Dynamic;

    public static function main(){
        mtwin.templo.Loader.BASE_DIR = "/home/project/tpl/";
        mtwin.templo.Loader.TMP_DIR = "/tmp/";
        context = Reflect.empty();
        template = null;

        request = new mtwin.web.Request();

        // creates the main application handler
        var handler = new MyHandler();

        // little check to avoid index.n in path
        var level = if (r.getPathInfoPart(0) == "index.n") 1 else 0;

        // start processing the request starting from specified path info part
        handler.execute(request, level);

        // if the templo template is defined, we execute it
        if (template != null){
            neko.Web.setHeader("Context-Type", "text/html; charset=UTF-8");
            neko.Lib.print(template.execute(context));
        }
    }
}

class MyHandler extends mtwin.web.Handler<Void> {
    public function new(){
        super();
        // (url = /) default, prepare the home.mtt template, no action associated
        free("default", "home.mtt");
        // (url = /getTime) prepare  the template getTime.mtt then execute doGetTime
        free("getTime", "getTime.mtt", doGetTime);
        // (url = /redirectToDefault) calls doRedirectToDefault
        free("redirectToDefault", doRedirectToDefault);
        // (url = /foo/*) delegate to FooHandler
        free("foo", handler(new FooHandler()));
    }

    public function doGetTime(){
        App.context.now = Date.now();
    }

    public function doRedirectToDefault(){
        neko.Web.redirect("/index.n");
    }

    // mtwin.web.Handler is template independant, we implements this method so 
    // our application will be able to prepare requested templates
    override function prepareTemplate( t:String ){
        App.template = new mtwin.templo.Loader(t);
    }
}

class SubHandler extends mtwin.web.Handler<Void> {

    public function new(){
        super();
        // (url = /foo/doFoo), prepare the foo.mtt template then execute doFoo() 
        free("doFoo", "foo.mtt", doFoo);
    }

    function doFoo(){
        // do something
    }

    // same as above
    override function prepareTemplate( t:String ){
        App.template = new mtwin.templo.Loader(t);
    }
}

Methods your Handlers may implement

prepareTemplate( tname:String ) : Void

Tells the application what template is going to be used, any template system may be used in this method.

isLogged() : Bool

Returns true if the current user is logged.

isAdmin() : Bool

Returns true if the current user is one of the website administrators.

isModerator() : Bool

Returns true if the current user is one of the website moderators.

isOwner(obj:T) : Bool

Returns true if the current user owns the specified object.

findObject(id:Int, lock:Bool) : T

Loads an object (may be from a database), the lock parameter may be used to tell if the object must be locked for modification or if the object has just to be retrieved in ReadOnly mode (default is lock=true).

Action declarators

In the following action declarators :

  • If template is specified, the method prepareTemplate(template) will be called, thus, your template must implements the prepareTemplate() method.
  • If callback is specified, this callback will be called, it may be a regular Void->Void method contained in your handler or some sofisticated wrapper created using Handler wrapper.

free(name, ?template, ?callback)

Any user may call this action.

logged(name, ?template, ?callback)

Requires isLogged() to be implemented and to return true for this user.

admin(name, ?template, ?callback)

Requires isAdmin() to be implemented and to return true for this user.

moderator(name, ?template, ?callback)

Requires isModerator() to be implemented and to return true for this user.

Method wrappers

object(objectCallback, ?lock)

Requires findObject() to be implemented, lock may be false|true or using Handler statics : ReadOnly|ReadWrite.

class DocumentHandler extends mtwin.web.Handler<Document> {

    public function new(){
        super();
        free("objectDefault", object(doView, ReadOnly));
    }

    override function findObject( id:Int, lock:Bool ) : Document {
        return Document.manager.get(id,lock);
    }

    function doView( d:Document ){
        neko.Lib.print(d.html);
    }
}

owner(objectCallback)

Requires isOwner() and findObject() to be implemented.

class DocumentHandler extends mtwin.web.Handler<Document> {

    public function new(){
        super();
        // owner of documents may edit them
        logged("edit", object(owner(doEdit), ReadWrite));
    }

    override function isLogged() : Bool {
        return App.user.id != null;
    }
    
    override function findObject( id:Int, lock:Bool ) : Document {
        return Document.manager.get(id,lock);
    }

    override function isOwner( d:Document ) : Bool {
        return d.authorId == App.user.id;
    }

    function doEdit( d:Document ){
        //...
    }
}

handler(Handler)

Delagates action to a sub Handler.

class OtherHandler extends mtwin.web.Handler<Void> {
}

class MyHandler extends mtwin.web.Handler<Void> {

    public function new(){
        // /other/* are redirected to OtherHandler
        free("other", handler(new OtherHandler())); 
        // /user/* are redirected to UserHandler
        free("user", handler(new UserHandler());
        // /help calls the doHelp method
        free("help", doHelp);
    }

    function doHelp(){
        //...
    }
}

Examples

Please take the time to browse the hxBlog (especially the Actions.hx file) to get a full working example.

version #8355, modified 2010-03-25 02:03:53 by tong