<commit_before>#+TITLE:     Immutant Web

* Introduction

  Immutant allows applications to respond to web requests via [[https://github.com/mmcgrana/ring][Ring]] handlers.
  Each application can dynamically register any number of handlers, each with
  a unique context path. This allows you to have multiple Ring webapps
  that share the same deployment lifecycle.

  Immutant provides a session implementation that provides automatic data
  sharing across nodes in a cluster.

  In this chapter, the term /application/ refers to the full deployment itself,
  and /webapp/ refers to a particular web application based around a single 
  Ring handler as its entry point. For most applications, the two will be the
  same thing.

* Context Path
  :PROPERTIES:
  :CUSTOM_ID: web-context-path
  :END:

  The *context path* is a prefix on the path portion of a url that is used as
  a mechanism to route requests to the proper webapp when more than
  one webapp is being served by the same 'container'. If you are running only
  one webapp in a container (which is the typical strategy when deploying
  Clojure webapp via [[http://jetty.codehaus.org/jetty/][Jetty]]), the context path is the /root/ context - =/=.

  A properly constructed webapp needs no knowledge of the context path it is
  mounted under - the container is responsible for routing requests to the webapp
  and providing the webapp specific fragment of the url's path to it. This
  allows the webapp to be moved between contexts (or mounted at multiple
  contexts at once) without any modification to the webapp code itself.

** The Top-Level Context Path

   Every application deployed has a context path assigned on its behalf. Since
   handlers can be registered dynamically from anywhere during the lifecycle of
   the application, we reserve a context path for every application, whether that
   application registers web handlers or not.

   If no context path is provided, a default context path based on the name of
   the deployment is used. For example: an application deployed using a
   descriptor named =some-app.clj= will be given the context path
   =/some-app=. An application deployed using an archive named
   =some-other-app.ima= will be given the context path =/some-other-app=.
   See [[./deployment.html][Deployment]] for the details of deploying Clojure applications.

   You can override the default context path via the =:context-path= key in
   either in the deployment descriptor or the =:immutant= section of the 
   application's =project.clj= (see [[./initialization.html][Initialization]] for the details on setting 
   configuration values).

   This context path is considered the *top-level* context path - you have the
   option to bind a handler to a *sub-context* path that will be nested within
   the top-level path. The full context is stripped from the url's path before
   the request is processed, and the context and remaining path info are made
   available as part of the request map via the =:context= and =:path-info= 
   keys, respectively.

** The Sub-Context Path

   When you register a handler with Immutant, you can optionally provide a
   sub-context path for which the handler will be responsible. This sub-context
   path is appended to the top-level context path for purposes of routing
   requests to the handler, and allows you to have multiple webapps within
   a single application.

* Virtual Host
  :PROPERTIES:
  :CUSTOM_ID: web-virtual-host
  :END:

  In addition to segmenting applications by context path, you can also segment
  by *virtual host*. To specify the virtual host (or hosts) for an application,
  set the =:virtual-host= key in either in the deployment descriptor or the 
  =:immutant= section of the application's =project.clj= (see [[./initialization.html][Initialization]] 
  for the details on setting configuration values). =:virtual-host= must be
  a string specifying a single host or a vector of strings specifying multiple
  hosts. Two applications with different virtual hosts can use the same 
  context path without collision.

* Registering Handlers

  To register a Ring handler, you simply call the [[./apidoc/immutant.web-api.html#immutant.web/start][immutant.web/start]], which
  takes one or two arguments:

  - =sub-context-path= - the sub-context path within the application's context
    path where the handler should be attached. Optional - if omitted,
    "/" is assumed. Only one handler can be attached to any given 
    sub-context path - providing an already attached sub-context will
    replace the previously registered handler.
  - =handler= - the Ring handler to invoke when requests come in on the
    sub context path.

  It also accepts an optional named argument =:reload= that, when
  true, monitors your application =src/= directory for changes and
  reloads the corresponding namespace. Its default value is false.

  Let's take a look at =start= in use. For the following example, assume
  the application has a top-level context path of =/my-app=:

  #+begin_src clojure
    (ns my.ns
      (:require [immutant.web :as web]))
    
    ;; handle requests at the root sub-context (/).
    ;; this handler will receive any request that the app
    ;; receives at /my-app/* *except* for anything captured by another
    ;; sub-context.
    (web/start my-root-handler)
    
    ;; handle requests at the /somewhere sub-context.
    ;; this handler will receive any request that the app
    ;; receives at /my-app/somewhere/*.
    (web/start "/somewhere" my-other-handler)
    
    ;; When you are developing, you want to see your changes immediately
    (web/start your-handler :reload true)
  #+end_src

  You can deregister a registered handler at any time. Immutant will deregister
  any remaining handlers for you when your application is undeployed.

* Deregistering Handlers

  You can deregister a Ring handler via the [[./apidoc/immutant.web-api.html#immutant.web/stop][immutant.web/stop]] function,
  which takes zero or one arguments:

  - =sub-context-path= - the sub-context path within the application's context
    path where the handler was attached. Optional - if omitted, "/" is assumed.

  An example of using =stop=:

  #+begin_src clojure
    (ns my.ns
      (:require [immutant.web :as web]))
    
    ;; deregisters the handler attached to the root sub-context (/)
    (web/stop)
    
    ;; deregisters the handler attached to the /somewhere sub-context
    (web/stop "/somewhere")
  #+end_src
  
* Sessions

  Immutant provides a session store that can be used with the
  [[https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/session.clj][Ring session middleware]] (and any other middleware that uses =ring.middleware.sesion=,
  like [[https://github.com/brentonashworth/sandbar][Sandbar]]). The Immutant session store uses the session provided by
  the underlying JBoss AS7 servlet container, which automatically replicates
  session data across a cluster. You create the store by calling 
  [[./apidoc/immutant.web.session-api.html#immutant.web.session/servlet-store][immutant.web.session/servlet-store]], and use it by passing it as the =:store=
  option to =ring.middleware.session/wrap-session=:

  #+begin_src clojure
    (ns my.ns
      (:require [ring.middleware.session :as ring-session]
                [immutant.web :as web]
                [immutant.web.session :as immutant-session]))
    
    (web/start<commit_msg>Add example to clarify context/sub-context path [IMMUTANT-161]<commit_after>#+TITLE:     Immutant Web

* Introduction

  Immutant allows applications to respond to web requests via [[https://github.com/mmcgrana/ring][Ring]] handlers.
  Each application can dynamically register any number of handlers, each with
  a unique context path. This allows you to have multiple Ring webapps
  that share the same deployment lifecycle.

  Immutant provides a session implementation that provides automatic data
  sharing across nodes in a cluster.

  In this chapter, the term /application/ refers to the full deployment itself,
  and /webapp/ refers to a particular web application based around a single 
  Ring handler as its entry point. For most applications, the two will be the
  same thing.

* Context Path
  :PROPERTIES:
  :CUSTOM_ID: web-context-path
  :END:

  The *context path* is a prefix on the path portion of a url that is used as
  a mechanism to route requests to the proper webapp when more than
  one webapp is being served by the same 'container'. If you are running only
  one webapp in a container (which is the typical strategy when deploying
  Clojure webapp via [[http://jetty.codehaus.org/jetty/][Jetty]]), the context path is the /root/ context - =/=.

  A properly constructed webapp needs no knowledge of the context path it is
  mounted under - the container is responsible for routing requests to the webapp
  and providing the webapp specific fragment of the url's path to it. This
  allows the webapp to be moved between contexts (or mounted at multiple
  contexts at once) without any modification to the webapp code itself.

** The Top-Level Context Path

   Every application deployed has a context path assigned on its behalf. Since
   handlers can be registered dynamically from anywhere during the lifecycle of
   the application, we reserve a context path for every application, whether that
   application registers web handlers or not.

   If no context path is provided, a default context path based on the name of
   the deployment is used. For example: an application deployed using a
   descriptor named =some-app.clj= will be given the context path
   =/some-app=. An application deployed using an archive named
   =some-other-app.ima= will be given the context path =/some-other-app=.
   See [[./deployment.html][Deployment]] for the details of deploying Clojure applications.

   You can override the default context path via the =:context-path= key in
   either in the deployment descriptor or the =:immutant= section of the 
   application's =project.clj= (see [[./initialization.html][Initialization]] for the details on setting 
   configuration values).

   This context path is considered the *top-level* context path - you have the
   option to bind a handler to a *sub-context* path that will be nested within
   the top-level path. The full context is stripped from the url's path before
   the request is processed, and the context and remaining path info are made
   available as part of the request map via the =:context= and =:path-info= 
   keys, respectively.

** The Sub-Context Path

   When you register a handler with Immutant, you can optionally provide a
   sub-context path for which the handler will be responsible. This sub-context
   path is appended to the top-level context path for purposes of routing
   requests to the handler, and allows you to have multiple webapps within
   a single application.

   See below for an [[#web-context-path-example][example]] demonstrating how the context path, sub-context path,
   and path info all work together.

* Virtual Host
  :PROPERTIES:
  :CUSTOM_ID: web-virtual-host
  :END:

  In addition to segmenting applications by context path, you can also segment
  by *virtual host*. To specify the virtual host (or hosts) for an application,
  set the =:virtual-host= key in either in the deployment descriptor or the 
  =:immutant= section of the application's =project.clj= (see [[./initialization.html][Initialization]] 
  for the details on setting configuration values). =:virtual-host= must be
  a string specifying a single host or a vector of strings specifying multiple
  hosts. Two applications with different virtual hosts can use the same 
  context path without collision.

* Registering Handlers

  To register a Ring handler, you simply call the [[./apidoc/immutant.web-api.html#immutant.web/start][immutant.web/start]], which
  takes one or two arguments:

  - =sub-context-path= - the sub-context path within the application's context
    path where the handler should be attached. Optional - if omitted,
    "/" is assumed. Only one handler can be attached to any given 
    sub-context path - providing an already attached sub-context will
    replace the previously registered handler.
  - =handler= - the Ring handler to invoke when requests come in on the
    sub context path.

  It also accepts an optional named argument =:reload= that, when
  true, monitors your application =src/= directory for changes and
  reloads the corresponding namespace. Its default value is false.

  Let's take a look at =start= in use. For the following example, assume
  the application has a top-level context path of =/my-app=:

  #+begin_src clojure
    (ns my.ns
      (:require [immutant.web :as web]))
    
    ;; handle requests at the root sub-context (/).
    ;; this handler will receive any request that the app
    ;; receives at /my-app/* *except* for anything captured by another
    ;; sub-context.
    (web/start my-root-handler)
    
    ;; handle requests at the /somewhere sub-context.
    ;; this handler will receive any request that the app
    ;; receives at /my-app/somewhere/*.
    (web/start "/somewhere" my-other-handler)
    
    ;; When you are developing, you want to see your changes immediately
    (web/start your-handler :reload true)
  #+end_src

  You can deregister a registered handler at any time. Immutant will deregister
  any remaining handlers for you when your application is undeployed.

* Deregistering Handlers

  You can deregister a Ring handler via the [[./apidoc/immutant.web-api.html#immutant.web/stop][immutant.web/stop]] function,
  which takes zero or one arguments:

  - =sub-context-path= - the sub-context path within the application's context
    path where the handler was attached. Optional - if omitted, "/" is assumed.

  An example of using =stop=:

  #+begin_src clojure
    (ns my.ns
      (:require [immutant.web :as web]))
    
    ;; deregisters the handler attached to the root sub-context (/)
    (web/stop)
    
    ;; deregisters the handler attached to the /somewhere sub-context
    (web/stop "/somewhere")
  #+end_src

* Context/Sub-Context Path Example
  :PROPERTIES:
  :CUSTOM_ID: web-context-path-example
  :END:

  Now that we've introduced registering ring handlers, we can give an example
  that makes it clear how the context and sub-context paths work, and how 
  the path info gets set.

  First, we'll set the context path for the entire application in our 
  =project.clj=:
   
   #+begin_src clojure
     (defproject someapp "0.1.0-SNAPSHOT"
       :dependencies [[org.clojure/clojure "1.4.0"]]
       
       :immutant {:init someapp.core/start
                  :context-path "/foo"})
   #+end_src

   Now we'll register two ring handlers with different sub-contexts, both
   of which will be available under the parent context we set in =project.clj=:

   #+begin_src clojure
     (ns someapp.core
       (:require [immutant.web :as web]))
     
     (defn make-handler  [sub-context]
       (fn [{:keys [context path-info] :as request}]
         {:status 200
          :content-type "text/plain"
          :body (pr-str {:mounted-sub-context sub-context
                         :request-context context
                         :request-path-info path-info})}))
     
     (defn start []
       ;; responds to /foo/
       (web/start "/" (make-handler "/"))
       ;; responds to /foo/bar/
       (web/start "/bar" (make-handler "/bar")))
   #+end_src

   When we deploy the app to Immutant, we can see how it sets the =:context= and 
   =:path-info= keys in the request map:

   #+begin_src sh
     $ curl http://localhost:8080/foo/baz
     {:mounted-sub-context "/", :request-context "/foo", :request-path-info "/baz"}
     $ curl http://localhost:8080/foo/baz/sheep
     {:mounted-sub-context "/", :request-context "/foo", :request-path-info "/baz/sheep"}
     $ curl http://localhost:8080/foo/bar/baz
     {:mounted-sub-context "/bar", :request-context "/foo/bar", :request-path-info "/baz"}
     $ curl http://localhost:8080/foo/bar/baz/sheep
     {:mounted-sub-context "/bar", :request-context "/foo/bar", :request-path-info "/baz/sheep"}
     $ curl http://localhost:8080/foo/bar
     {:mounted-sub-context "/bar", :request-context "/foo/bar", :request-path-info "/"}
     $ curl http://localhost:8080/foo/
     {:mounted-sub-context "/", :request-context "/foo", :request-path-info "/"}
   #+end_src
  
* Sessions

  Immutant provides a session store that can be used with the
  [[https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/session.clj][Ring session middleware]] (and any other middleware that uses =ring.middleware.sesion=,
  like [[https://github.com/brentonashworth/sandbar][Sandbar]]). The Immutant session store uses the session provided by
  the underlying JBoss AS7 servlet container, which automatically replicates
  session data across a cluster. You create the store by calling 
  [[./apidoc/immutant.web.session-api.html#immutant.web.session/servlet-store][immutant.web.session/servlet-store]], and use it by passing it as the =:store=
  option to =ring.middleware.session/wrap-session=:

  #+begin_src clojure
    (ns my.ns
      (:require [ring.middleware.session :as ring-session]
                [immutant.web :as web]
                [immutant.web.session :as immutant-session]))
    
    (web/start
{'fraction_non_alphanumeric': 0.08140068886337543, 'fraction_numerical': 0.0021814006888633756, 'mean_word_length': 3.3981317849028025, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3785869', 'n_tokens_mistral': 4950, 'n_tokens_neox': 4690, 'n_words': 2120}