logo

const abstract class

web::WebService

sys::Obj
  sys::Thread
    web::WebService
   1  //
   2  // Copyright (c) 2007, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //   21 Dec 07  Brian Frank  Creation
   7  //
   8  
   9  **
  10  ** WebService implements the standard pipeline for
  11  ** processing  a web request.
  12  **
  13  abstract const class WebService : Thread
  14  {
  15  
  16  //////////////////////////////////////////////////////////////////////////
  17  // Construction
  18  //////////////////////////////////////////////////////////////////////////
  19  
  20    **
  21    ** Constructor with thread name.
  22    **
  23    new make(Str name) : super(name) {}
  24  
  25  //////////////////////////////////////////////////////////////////////////
  26  // Pipeline
  27  //////////////////////////////////////////////////////////////////////////
  28  
  29    **
  30    ** Run the standard pipeline of steps needed to process
  31    ** a web request.  This call routes to a series of method
  32    ** calls which all begin with "step".
  33    **
  34    virtual Void pipeline(WebReq req, WebRes res)
  35    {
  36      if (!stepInit(req, res)) return
  37      try
  38      {
  39        if (!stepResource(req, res)) return
  40        if (!stepWeblet(req, res)) return
  41        if (!stepService(req, res)) return
  42      }
  43      catch (Err err)
  44      {
  45        err.trace
  46      }
  47      finally
  48      {
  49        stepCleanup(req, res)
  50      }
  51    }
  52  
  53    **
  54    ** The init step is responsible for initializing thread
  55    ** local state before any processing is started.  Return
  56    ** if processing should continue.
  57    **
  58    virtual Bool stepInit(WebReq req, WebRes res)
  59    {
  60      if (log.isDebug)
  61      {
  62        log.debug("==============================")
  63        log.debug("stepInit [$req.uri]")
  64      }
  65  
  66      // mount request, response as thread locals
  67      Thread.locals["web.req"] = req
  68      Thread.locals["web.res"] = res
  69      return true
  70    }
  71  
  72    **
  73    ** Resolve the request Uri to a Resource in my
  74    ** namespace.  Return if processing should continue.
  75    **
  76    virtual Bool stepResource(WebReq req, WebRes res)
  77    {
  78      if (log.isDebug) log.debug("stepResolve [$req.uri]")
  79  
  80      // attempt to resolve
  81      r := req.uri.resolve(null, false)
  82      if (log.isDebug) log.debug("  resolved = $r")
  83  
  84      // if resolved successfully we are done
  85      if (r != null)
  86      {
  87        req.resource = r
  88        return true
  89      }
  90  
  91      // if not resolved, return 401
  92      res.statusCode = 404
  93      res.headers.clear
  94      res.headers["Content-Type"] = "text/plain"
  95      res.out.print("Not found: $req.uri\n")
  96      return false
  97    }
  98  
  99    **
 100    ** Resolve the weblet to use for servicing request on
 101    ** the resource.  Return if processing should continue.
 102    **
 103    virtual Bool stepWeblet(WebReq req, WebRes res)
 104    {
 105      if (log.isDebug) log.debug("stepWeblet[$req.uri]")
 106  
 107      // TODO: use fixed weblet for now
 108      Weblet weblet := null
 109      if (req.resource is File && !req.resource.isDir)
 110      {
 111        weblet = FileWeblet.make
 112      }
 113      else
 114      {
 115        weblet = Type.find("webui::DefaultPage").make
 116      }
 117  
 118      if (log.isDebug) log.debug("  weblet = $weblet.type")
 119  
 120      // save to thread local
 121      Thread.locals["web.weblet"] = weblet
 122      return true
 123    }
 124  
 125    **
 126    ** Use the page and widget to service the request.
 127    **
 128    virtual Bool stepService(WebReq req, WebRes res)
 129    {
 130      Weblet weblet := Thread.locals["web.weblet"]
 131      weblet.service
 132      return true
 133    }
 134  
 135    **
 136    ** The cleanup step is always run to cleanup
 137    ** thread local state.
 138    **
 139    virtual Void stepCleanup(WebReq req, WebRes res)
 140    {
 141      if (log.isDebug) log.debug("stepCleanup [$req.uri]")
 142  
 143      // cleanup thread locals
 144      Thread.locals.remove("web.req")
 145      Thread.locals.remove("web.res")
 146      Thread.locals.remove("web.weblet")
 147    }
 148  
 149    internal const static Log log := Log.get("web.pipeline")
 150  }