This is an implementation of a very small subset of the Servlet standards. It does not claim to comply with any particular level of specification, but rather it implements those calls used (so far) in my trivially simple servlets.
It is sufficient to host small web sites including simple servlets.
There is a class of servlet which don't require full blown application servers (such as WebSphere) to host them. They might not require EJBs, might need to consume very little memory or CPU, and perhaps might only utililise just a few of the Servlet APIs. A large number of vendor products now provide simple web interfaces to their products, and often the functionality is basic, perhaps being restricted to read-only status viewing (eg: the Tivoli monitor agent, Best/1 performance capacity/trend graphing review, etc.).
This Servlet Engine is designed to be extremely lightweight.
In fact, at this time, the .jar file is <35KB.
To host a Servlet, you need the Servlet itself, a "Server" which you write
(which basically instantiates an instance of the Servlet Engine, and registers
the Servlet into it), and the .jar file.
It is also designed to allow the construction 'tightly packaged' servers.
When looking for properties files (or content via
ServletContext.getResourceAsStream) or static web content,
it uses the classloader first, and then the filesystem.
This allows the bundling of Servlets, "Server", properties files and static web
content into a single .jar file.
eg: You could have hello.jar containing :-
HelloServlet.class HelloServlet.props HelloServer.class HelloServer.props
and you'd run it via :-
java -cp nyangau-se.jar:hello.jar HelloServer
The Servlet Engine compiles up to form a .jar file, containing
classes in the javax.servlet. namespace and below.
Thus servlets compiled up to run in WebSphere, JRun, WebLogic, Tomcat etc.,
should require zero modification to run in this environment (providing they
only use the subset of APIs supported by this Servlet Engine).
public class ServletException extends Exception
{
public ServletException();
public ServletException(String s);
}
public abstract class ServletOutputStream extends OutputStream
{
public abstract void print(String s)
throws IOException;
public abstract void println()
throws IOException;
public abstract void println(String s)
throws IOException;
}
public interface ServletContext
{
public abstract String getInitParameter(String n);
public abstract Enumeration getInitParameterNames();
public abstract String getMimeType(String fn);
public abstract ServletContext getContext(String uripath);
public abstract InputStream getResourceAsStream(String path);
}
public interface ServletConfig
{
public abstract ServletContext getServletContext();
public abstract String getInitParameter(String n);
public abstract Enumeration getInitParameterNames();
}
public interface ServletRequest
{
public abstract String getProtocol();
public abstract String getParameter(String p);
public abstract Enumeration getParameterNames();
public abstract String[] getParameterValues(String p);
}
public interface ServletResponse
{
public abstract boolean isCommitted();
public abstract void setContentType(String ct);
public abstract void setContentLength(int length);
public abstract ServletOutputStream getOutputStream()
throws IOException;
public abstract PrintWriter getWriter()
throws IOException;
}
public interface Servlet
{
public abstract void init(ServletConfig sc)
throws ServletException;
public abstract ServletConfig getServletConfig();
public abstract void service(ServletRequest req, ServletResponse resp)
throws ServletException, IOException;
}
public abstract class GenericServlet implements Servlet
{
public void init()
throws ServletException;
public void init(javax.servlet.ServletConfig sc)
throws ServletException;
public ServletConfig getServletConfig()
public abstract void service(ServletRequest req, ServletResponse resp)
throws ServletException, IOException;
}
public interface HttpServletRequest extends ServletRequest
{
public abstract String getMethod();
public abstract String getRequestURI();
public abstract String getQueryString();
public abstract int getIntHeader(String h)
throws NumberFormatException;
public abstract Enumeration getHeaders(String h);
public abstract Enumeration getHeaderNames();
}
public interface HttpServletResponse extends ServletResponse
{
static final int SC_OK = 200;
static final int SC_MULTIPLE_CHOICES = 300;
static final int SC_MOVED_PERMANENTLY = 301;
static final int SC_MOVED_TEMPORARILY = 302;
static final int SC_BAD_REQUEST = 400;
static final int SC_UNAUTHORIZED = 401;
static final int SC_FORBIDDEN = 403;
static final int SC_NOT_FOUND = 404;
static final int SC_METHOD_NOT_ALLOWED = 405;
static final int SC_GONE = 410;
static final int SC_INTERNAL_SERVER_ERROR = 500;
static final int SC_NOT_IMPLEMENTED = 501;
static final int SC_SERVICE_UNAVAILABLE = 503;
public abstract boolean containsHeader(String h);
public abstract void addHeader(String h, String v);
public abstract void setHeader(String h, String v);
public abstract void addIntHeader(String h, int v);
public abstract void setIntHeader(String h, int v);
public abstract void setStatus(int sc);
public abstract void sendError(int sc)
throws IOException;
public abstract void sendError(int sc, String message)
throws IOException;
public void sendRedirect(String url)
throws IOException;
public String encodeURL(String url);
public String encodeRedirectURL(String url);
}
public abstract class HttpServlet extends GenericServlet
{
public void service(ServletRequest req, ServletResponse resp)
throws ServletException, IOException;
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException;
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException;
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException;
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException;
}
Lets assume we have a simple servlet called HelloServlet, which we wish to host.
//
// HelloServlet.java
//
import java.io.*;
import java.servlet.*;
import java.servlet.http.*;
public class HelloServlet extends HttpServlet
{
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
resp.setContentType("text/html");
ServletOutputStream os = resp.getOutputStream();
os.println("<H1>Hello</H1>");
}
}
We need to construct a Servlet Engine to run it in :-
//
// HelloServer.java - Hello Server
//
import java.net.*;
import java.io.*;
import java.util.*;
import nyangau.se.*;
public class HelloServer
{
public static void main(String args[])
{
try
{
ServletContext sctx = new ServletContext("HelloServer.props", "docroot");
ServletEngine seng = new ServletEngine(sctx);
ServletConfig scfg = new ServletConfig("HelloServlet.props");
seng.registerServlet("/", new HelloServlet(), scfg);
seng.serve();
}
catch ( javax.servlet.ServletException e )
{
System.err.println("HelloServer: "+e.toString());
}
catch ( IOException e )
{
System.err.println("HelloServer: "+e.toString());
}
}
}
You can see where a new instance of HelloServlet is registered
into the URI space (at / in the example).
The ServletEngine.serve method is where the server begins
listening for inbound web requests and responds to them.
Just for completeness, we display any exceptions which occur during initialisation. Exceptions which occur during the serving of individual pages will be logged to stderr.
HelloServer.props is a Java properties file containing
servlet-context wide properties.
As there is only one servlet context (ie: one web application) in this
servlet engine, these properties are effectively global to the entire server.
The most important property in this file is the port property.
Without this, ServletEngine will use port 7777 (which probably clashes with
some other program).
This file can also contain MIME mappings in the form
mime.extension=mimetype, eg:
mime.png=image/png
The Servlet Engine will use these when serving static pages. If the file extension in question is not listed here, the Servlet Engine will fall back on its internal hard coded list of around 70 common MIME types.
Note also that where the ServletContext is set, a
document root is chosen.
This is for any static web content to be included.
HelloServlet.props is a Java properties file containing
initialisation time parameters for the servlet. ie: the values returned from
the getInitParameter method of the
javax.servlet.ServletConfig class.
Assuming $n is the path to find nyangau-se.jar :-
When compiling with javac, be sure to
-extdirs nyangau-se.jar.
javac -extdirs $n HelloServlet.java javac -extdirs $n HelloServer.java jar -cf hello.jar *.class *.props
When running your servlet engine with java, be sure to include
nyangau-se.jar on the classpath.
java -cp $n/nyangau-se.jar:hello.jar HelloServer
If I write servlets which need APIs not implemented so far, I may well add them.
Feel free to copy, its public domain. Caveat Emptor.