Overview

::========::
|| README ||
::========::

Taimen is an Open Source (Apache 2.0 license) lightweight web framework for
Java and other JVM languages: http://code.google.com/p/bitumenframework/

::-----------------::
|| WHAT IS TAIMEN? ||
::-----------------::

- A minimalistic, Servlet based MVC-2 layer for JVM languages
- Pure Java, No XML, Uses Java collections for configuration
- In-process debugging using embedded servlet container, such as Jetty
- Reads a map of REST-compatible route versus action-sequence
- Invokes corresponding action-sequence when the request matches a route
- Integrates easily with view technologies: JSP, StringTemplate, FreeMarker

::-----------------------------------------------------------::
|| WHY SHOULD YOU CONSIDER TAIMEN OVER OTHER WEB FRAMEWORKS? ||
::-----------------------------------------------------------::

Consider features that are going to be useful to you, then compare
- Features
- Ease of use (and learning curve)
- Compatibility with dynamic JVM languages
- Integration with multiple (and future) view technologies
- Footprint
- Dependencies

Taimen introduces no fundamental shift from the very familiar HTTP Servlet
technology, and is quite easy to integrate with leading view technologies
such as JSP, Freemarker, StringTemplate, AJAX etc and IoC frameworks such
as Spring IoC, PicoContainer and Google Guice. The HTML or the view
template you write can remain totally unaware of Taimen, which lets view
designers or content developers not worry about the back end MVC framework.

Taimen ensures 100% separation between model and view making it quite hard
to write bad, spaghetti code while developing the presentation layer.
Taimen is biased in favour of RESTful HTTP and supports developer assisted
Content-Negotiation (conneg). It introduces some powerful concepts such as:
- Route
- Action
- Action Sequence
- Model
- RouteMap (a map with many entries { key: Route, value: Action-sequence })
- Transparent Interception

These concepts are easy to understand and are very intuitive. You may find
yourself using them even before you realize you did!

Taimen draws inspiration (and good ideas) from
- Restlet 2.0M4     -- http://www.restlet.org/
- Struts 1.x        -- http://struts.apache.org/1.3.10/index.html
- Struts 2.x        -- http://struts.apache.org/2.1.6/index.html
- Spring 3.0M4 MVC  -- http://www.springsource.com/download/community
- Wink 0.2 SNAPSHOT -- http://incubator.apache.org/wink/downloads.html
- Compojure         -- http://github.com/weavejester/compojure

::-----------------------------------::
|| IS IT JAX-RS (JSR 311) COMPLIANT? ||
::-----------------------------------::

Taimen is currently *NOT* JAX-RS (JSR 311) compliant. As you would notice
JAX-RS prescribes use of annotations, which are not directly suported by
Clojure as of now (in Clojure version 1.0). You can find the JAX-RS spec
here:

https://jsr311.dev.java.net/nonav/releases/1.0/spec/index.html
https://jsr311.dev.java.net/nonav/releases/1.1/spec/spec.html
https://jsr311.dev.java.net/

Taimen strives to support dynamic JVM languages as well as Java with a
clean Collections based API. Having said that, a future support for JAX-RS
is not at all ruled out -- I am interested in receiving contributions to
build a JAX-RS compatible extension for Taimen.

::------------------------::
|| CONCEPTS & DEFINITIONS ||
::------------------------::

DISCLAIMER: These definitions may come across as very abstract. Do not
            freak out! The real interesting stuff is *after* this section.

*** [ ROUTE ] ***

A route is a flexible bunch of matchers that besides HTTP method and URI,
can also be associated with:

- "Content-Type" for PUT and POST (ConsumesMediaType)
- "Accept" header (ProducesMediaType)
- "Accept-Charset"  header (ProducesCharset)
- "Accept-Language" header (ProducesLanguage)
- "Accept-Encoding" header (ProducesEncoding)

*** [ ACTION ] ***

An action is a bunch of functions (see interface IAction), viz.
- execute
- post-execute
- post-result
- error

Each function is executed on a certain event (self-explanatory), and
generates Model. Illustrated in another section (below).

*** [ ACTION SEQUENCE ] ***

An Action-sequence is a sequence (think Java Collection) of actions invoked
against an HTTP request. Action sequences are of two kinds:

- Common action sequence (unique across all routes)
- Route-associated action sequence (specific for each route)

When an HTTP request matches a Route, the Common Action-sequence is
executed followed by the Route-specific Action-sequence. Traversal of the
Action-sequence is illustrated in another section (below).

*** [ MODEL ] ***

Model is the data (entries in a map { key: String, value: Object })
that is generated upon executing the Actions, and is used to render output.

Some keys in the model have special meaning, which are explained in another
section (below).

*** [ TRANSPARENT INTERCEPTION ] ***

By design, every Action acts as an interceptor to the next one in the
Action-sequence. The generated Model affects how this behaviour is
controlled (through keys that have special meaning).


::----------------::
|| ROUTE EXAMPLES ||
::----------------::

- GET    "/"
- GET    "/blogentry/{entryid}"    -- entryid is in JAX-RS style
- GET    "/blogentry/{entryid}/*"
- PUT    "/blogentry/*/new"
- POST   "/blogentry/{entryid}"
- DELETE "/blogentry/{entryid}/comment/{commentid}"
- GET    "/public/*"
- ANY    "*"


::--------------------------------------::
|| HOW IS THE ACTION-SEQUENCE EXECUTED? ||
::--------------------------------------::

Every action has these methods:
    (1) execute      -- responsible for executing action logic and generating model
    (2) post-execute -- responsible for after-execute activities
    (3) post-result  -- responsible for after-result activities
    (4) error        -- called when an error occurs

For a given action sequence (example: [a1 a2 a3]), the execution-flow is below:

          .---------------------.---------------------.---------------------.
          |         a1          |         a2          |         a3          |
          |---------------------+---------------------+---------------------|
(begin) ==|=> a1.execute =======|=> a2.execute =======|=> a3.execute =======|=.
          |                     |                     |                     | |
        .=|== a1.post-execute <=|== a2.post-execute <=|== a3.post-execute <=|=*
        | |                     |                     |                     |
        *==========================> render-result ===========================.
          |                     |                     |                     | |
(end) <===|== a1.post-result <==|== a2.post-result <==|== a3.post-result <==|=*
          *---------------------+---------------------+---------------------*

An action can terminate the sequence by populating the model with any of these keys:
- "forward"
- "redirect"
- "body" (if "continue" key is populated with value "true", then not terminated)

The postExecute() and postResult() methods for executed actions are invoked
in all cases (like the finally {} clause in Java), even when an action
terminates the sequence. When a sequence is terminated the subsequent
actions are not executed.

::-----------------------------::
|| HOW ARE EXCEPTIONS HANDLED? ||
::-----------------------------::

Exceptions are trapped at each of execute, postExecute, result (sequence-walker
invokes this function) and postResult calls, as illustrated in diagrams below:

[ EXECUTE ]

          .-----------------------.-----------------------.---------------------.
          |          a1           |          a2           |         a3          |
          |-----------------------+-----------------------+---------------------|
(begin) ==|===> a1.execute =======|=====> a2.execute      |   a3.execute        |
          |                       |            |          |                     |
          |                       |            V          |                     |
          |                       |        EXCEPTION      |                     |
          |                       |            |          |                     |
          |                       |            V          |                     |
(end)   <=|== a1.error(EXECUTE)<==|== a2.error(EXECUTE)   |                     |
          *-----------------------+-----------------------+---------------------*

[ POST-EXECUTE ]

          .-----------------------------.--------------------------.---------------------.
          |             a1              |            a2            |         a3          |
          |-----------------------------+--------------------------+---------------------|
(begin) ==|=======> a1.execute =========|======> a2.execute =======|=> a3.execute =======|=.
          |                             |                          |                     | |
          |       a1.post-execute       |      a2.post-execute <===|== a3.post-execute <=|=*
          |                             |             |            |                     |
          |                             |             V            |                     |
          |                             |         EXCEPTION        |                     |
          |                             |             |            |                     |
          |                             |             V            |                     |
(end) <===|=== a1.error(POST_EXECUTE)<==|== a2.error(POST_EXECUTE) |                     |
          *-----------------------------+--------------------------+---------------------*

[ RESULT ]

          .---------------------------.---------------------------.---------------------.
          |             a1            |            a2             |         a3          |
          |---------------------------+---------------------------+---------------------|
(begin) ==|=======> a1.execute =======|=======> a2.execute        |      a3.execute     |
          |                           |   (sequence terminated)   |                     |
          |                           |             |             |                     |
          |                           |             V             |                     |
        .=|===== a1.post-execute <====|===== a2.post-execute      |   a3.post-execute   |
        | |                           |                           |                     |
        *===================================> render-result       |                     |
          |                           |             |             |                     |
          |                           |             V             |                     |
          |                           |         EXCEPTION         |                     |
          |                           |             |             |                     |
          |                           |             V             |                     |
(end) <===|===== a1.error(RESULT) <===|===== a2.error(RESULT)     |                     |
          *---------------------------+---------------------------+---------------------*

[ POST-RESULT ]

          .---------------------------.---------------------------.---------------------.
          |             a1            |            a2             |         a3          |
          |---------------------------+---------------------------+---------------------|
(begin) ==|=======> a1.execute =======|=======> a2.execute =======|=> a3.execute =======|=.
          |                           |                           |                     | |
        .=|===== a1.post-execute <====|===== a2.post-execute <====|== a3.post-execute <=|=*
        | |                           |                           |                     |
        *============================================================> render-result =====.
          |                           |                           |                     | |
          |      a1.post-result       |      a2.post-result <=====|== a3.post-result <==|=*
          |                           |             |             |                     |
          |                           |             V             |                     |
          |                           |         EXCEPTION         |                     |
          |                           |             |             |                     |
          |                           |             V             |                     |
(end) <===|== a1.error(POST_RESULT) <=|== a2.error(POST_RESULT)   |                     |
          *---------------------------+---------------------------+---------------------*

::-----------------------------::
|| HOW IS THE MODEL EXPRESSED? ||
::-----------------------------::

- The model is a Map<String, Object> object. The response is generated from the value:

  Key      Action
  ---      -----
  forward  Forwards request to the specified URL
  redirect Redirects the browser to specified URL
  body     Generates response from the value (any of following types):
           String, CharSequence, char[], Character[], Reader - String content
           InputStream, byte[], Byte[]                       - Binary content
           File, URL                                         - Either
           IResponseGenerator                                - Arbitrary content

::---------------------------::
|| CODE EXAMPLE (QUICKSTART) ||
::---------------------------::

See README-Java.txt and/or README-Clojure.txt files.

::-------------::
|| INTEGRATION ||
::-------------::

- Taimen can be easily integrated (by writing code) with
  - View technologies (StringTemplate, JSP, Freemarker etc)
  - IoC containers (Spring, Guice, Pico-container)
  - JVM-languages (both Statically typed and Dynamically typed languages)
  - File uploads (use Apache FileUpload)
  - AJAX
  - Comet support is planned (likely once Servlet 3.0 spec is final)
- Clojure integration is supported through Taimen-Clojure extension

::------::
|| TODO ||
::------::

[ Primary ]
- Multiple file uploads
- GET Caching (integration with caching products / frameworks)
- Lock-token action like Struts 2 (to avoid duplicate submissions)
- Waiting page intercepting-action like Struts 2

[ Secondary ]
- Integrate security - authorization / rights (Acegi?)
- Integrate menu generation (another project probably)

[ Documentation / Tutorials / Examples ]
- Docbook based manual (auto-convert to PDF, using Ant task)
- Servlet instance discovery using
  - Static ServletTracker.register() method
  - Servlet context (application scope, lookup by servlet name)
- Immutable routes using Java + Spring annotations (mention Guice and Pico)
- Mutable routes in Java
- Mutable routes in Clojure (modify route-map in transaction - STM)
- Files upload
- Example RESTful service layer implementation