Kawa makes it easy to set up a web site without configuration files. Instead, the mapping from request URL to web page script matches the layout of files in the application directory.
Many web servers make it easy to execute a script using a script
processor which is selected depending on the extension of the
requested URL. That is why you see lots of URLs that end in
.cgi
, .php
, or .jsp
. This is bad, because it
exposes the server-side implementation to the user: Not only are such
URLs ugly, but they make it difficult to change the server without
breaking people’s bookmarks and search engines. A server will usually
provide a mechanism to use prettier URLs, but doing so requires extra
effort, so many web-masters don’t.
If you want a script to be executed in response to a URL
http://host/app/foo/bar
you give the script the name
app/foo/bar
, in the appropriate server “application”
directory (as explained below). You get to pick the name bar
.
Or you can use the name bar.html
, even though the file named
bar.html
isn’t actually
an html file - rather it produces html when evaluated. Or better: just use
a name without an extension at all.
Kawa figures
out what kind of script it is based on the content of the file,
rather than the file name. Once Kawa has
found a script, it looks at the first line to see if it can recognize
the kind (language) of the script. Normally this would be a comment
that contains the name of a programming language that Kawa
knows about. For example:
;; Hello world page script written in -*- scheme -*- #<p>Hello, <b>&(request-remote-host)</b>!</p>
(Using the funny-looking string -*- scheme -*-
has the
bonus is that it recognized by the Emacs text editor.)
A script named +default+
is run if there isn’t a matching script.
For example assume the following is a file named +default
.
;; This is -*- scheme -*- (make-element 'p "servlet-path: " (request-servlet-path))
This becomes the default script for HTTP requests that aren’t handled
by a more specific script.
The request-servlet-path
function
returns the "servlet path", which is the part of the requested URL
that is relative to the current web application. Thus a request for
http://host:port/app/this/is/a/test
will return:
servlet-path: /this/is/a/test
You can use the feature variable in-http-server
in a cond-expand
to test if the code is executing
in a web server.
The easiest way to run a Kawa web server is to use the web server built in to JDK 6 or later.
kawa --http-auto-handlercontext-path
appdir
--http-startport
This starts a web server that listens on the given port
,
using the files in directory appdir
to handle
requests that start with the given context-path
.
The context-path
must start with a "/"
(one is added if
needed), and it is recommended that it also end with a "/"
(otherwise you might get some surprising behavior).
You can specify multiple --http-auto-handler
options.
For example use the files in the current directory to handle all requests on the standard port 80 do:
kawa --http-auto-handler / . --http-start 80
There are some examples in the testsuite/webtest
directory
the Kawa source distribution. You can start the server thus:
bin/kawa --http-auto-handler / testsuite/webtest/ --http-start 8888
and then for example browse to http://localhost:8888/adder.scm
.
For lots of information about the HTTP request, browse to
http://localhost:8888/info/
.
anything
You can also can use a “servlet container”
such as Tomcat or Glassfish with self-configuring script.
See Servlets for information on how to install
these servers, and the concept of web applications.
Once you have these server installed, you create a
web application with the following in the
configuration file:
appdir
/WEB-INF/web.xml
<web-app> <display-name>Kawa auto-servlet</display-name> <servlet> <servlet-name>KawaPageServlet</servlet-name> <servlet-class>gnu.kawa.servlet.KawaPageServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>KawaPageServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
This creates a web application where all URLs
are handled by the gnu.kawa.servlet.KawaPageServlet
servlet class,
which is included in the Kawa jar file.
The KawaPageServlet
class handles the searching
and compiling described in this page.
When Kawa receives a request for:
http://host:port/appname/a/b/anything
it will look for a file:
appdir
/a/b/anything
If such a file exists, the script will be executed, as described
below. If not, it will look for a file name +default+
in the same
directory. If that desn’t exist either, it will look for +default+
in the parent
directory, then the grand-parent directory, and so on until it gets to
the appname web application root directory. So the default script is
this:
.
appdir
/+default
If that doesn’t exist then Kawa returns a 404 "page not found" error.
Once Kawa has found a script file corresponding to a request URL, it needs to determine if this is a data file or a web page script, and in the latter case, what language it is written in.
Kawa recognizes the following "magic strings" in the first line of a script:
kawa:scheme
The Scheme language.
kawa:xquery
The XQuery language.
kawa:language
Some other language known to Kawa.
Kawa also recognizes Emacs-style "mode specifiers":
-*- scheme -*-
The Scheme language.
-*- xquery -*-
The XQuery language (though Emacs doesn’t know about XQuery).
-*- emacs-lisp -*-
-*- elisp -*-
The Emacs Lisp extension language.
-*- common-lisp -*-
-*- lisp -*-
The Common Lisp language.
Also, it also recognizes comments in the first two columns of the line:
;;
A Scheme or Lisp comment - assumed to be in the Scheme language.
(:
Start of an XQuery comment, so assumed to be in the XQuery language.
If Kawa doesn’t recognize the language of a script (and it isn’t named +default+) then it assumes the file is a data file. It asks the servlet engine to figure out the content type (using the getMimeType method of ServletContext), and just copies the file into the response.
Kawa automatically compiles a script into a class. The
class is internal to the server, and is not written out to
disk. (There is an unsupported option to write the compiled file to a
class file, but there is no support to use previously-compiled
classes.) The server then creates a module instance to handle the
actual request, and runs the body (the run
method)
of the script class. On subsequence
requests for the same script, the same class and instance are reused;
only the run
is re-executed.
If the script is changed, then it is re-compiled and a new module instance created. This makes it very easy to develop and modify a script. (Kawa for performance reasons doesn’t check more than once a second whether a script has been modified.)