1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/tools/JavaServlet/classes/uk/org/boddie/webstack/util/PyServlet.java Sun Aug 29 19:09:25 2004 +0000
1.3 @@ -0,0 +1,242 @@
1.4 +package uk.org.boddie.webstack.util;
1.5 +
1.6 +import java.io.*;
1.7 +import java.util.*;
1.8 +import javax.servlet.*;
1.9 +import javax.servlet.http.*;
1.10 +import org.python.core.*;
1.11 +import org.python.util.PythonInterpreter;
1.12 +
1.13 +/**
1.14 + * This servlet is used to re-serve JPython servlets. It stores
1.15 + * bytecode for JPython servlets and re-uses it if the underlying .py
1.16 + * file has not changed.
1.17 + * <p>
1.18 + * Many people have been involved with this class:
1.19 + * <ul>
1.20 + * <li>Chris Gokey
1.21 + * <li>David Syer
1.22 + * <li>Finn Bock
1.23 + * </ul>
1.24 + * If somebody is missing from this list, let us know.
1.25 + * <p>
1.26 + *
1.27 + * e.g. http://localhost:8080/test/hello.py
1.28 + * <pre>
1.29 + *
1.30 + * from javax.servlet.http import HttpServlet
1.31 + * class hello(HttpServlet):
1.32 + * def doGet(self, req, res):
1.33 + * res.setContentType("text/html");
1.34 + * out = res.getOutputStream()
1.35 + * print >>out, "<html>"
1.36 + * print >>out, "<head><title>Hello World, How are we?</title></head>"
1.37 + * print >>out, "<body>Hello World, how are we?"
1.38 + * print >>out, "</body>"
1.39 + * print >>out, "</html>"
1.40 + * out.close()
1.41 + * return
1.42 + * </pre>
1.43 + *
1.44 + * in web.xml for the PyServlet context:
1.45 + * <pre>
1.46 + * <web-app>
1.47 + * <servlet>
1.48 + * <servlet-name>PyServlet</servlet-name>
1.49 + * <servlet-class>uk.org.boddie.webstack.util.PyServlet</servlet-class>
1.50 + * <init-param>
1.51 + * <param-name>python.home</param-name>
1.52 + * <param-value>/usr/home/jython-2.1</param-value>
1.53 + * </init-param>
1.54 + * <init-param>
1.55 + * <param-name>servlet.file</param-name>
1.56 + * <param-value>hello.py</param-value>
1.57 + * </init-param>
1.58 + * </servlet>
1.59 + * <servlet-mapping>
1.60 + * <servlet-name>PyServlet</servlet-name>
1.61 + * <url-pattern>/*</url-pattern>
1.62 + * </servlet-mapping>
1.63 + * </web-app>
1.64 + *
1.65 + * </pre>
1.66 + */
1.67 +public class PyServlet extends HttpServlet {
1.68 + private PythonInterpreter interp;
1.69 + private Hashtable cache = new Hashtable();
1.70 + private String rootPath;
1.71 + private String servletFile = null;
1.72 +
1.73 + public void init() {
1.74 + rootPath = getServletContext().getRealPath("/");
1.75 + if (!rootPath.endsWith(File.separator))
1.76 + rootPath += File.separator;
1.77 +
1.78 + Properties props = new Properties();
1.79 +
1.80 + // Context parameters
1.81 + ServletContext context = getServletContext();
1.82 + Enumeration e = context.getInitParameterNames();
1.83 + while (e.hasMoreElements()) {
1.84 + String name = (String) e.nextElement();
1.85 + props.put(name, context.getInitParameter(name));
1.86 + }
1.87 +
1.88 + // Config parameters
1.89 + e = getInitParameterNames();
1.90 + while (e.hasMoreElements()) {
1.91 + String name = (String) e.nextElement();
1.92 + props.put(name, getInitParameter(name));
1.93 + }
1.94 +
1.95 + if (props.getProperty("python.home") == null &&
1.96 + System.getProperty("python.home") == null) {
1.97 + props.put("python.home", rootPath + "WEB-INF" +
1.98 + File.separator + "lib");
1.99 + }
1.100 +
1.101 + // Define the servlet file.
1.102 + servletFile = props.getProperty("servlet.file");
1.103 +
1.104 + PythonInterpreter.initialize(System.getProperties(), props,
1.105 + new String[0]);
1.106 + reset();
1.107 +
1.108 + PySystemState sys = Py.getSystemState();
1.109 + sys.add_package("javax.servlet");
1.110 + sys.add_package("javax.servlet.http");
1.111 + sys.add_package("javax.servlet.jsp");
1.112 + sys.add_package("javax.servlet.jsp.tagext");
1.113 +
1.114 + sys.add_classdir(rootPath + "WEB-INF" +
1.115 + File.separator + "classes");
1.116 +
1.117 + sys.add_extdir(rootPath + "WEB-INF" + File.separator + "lib", true);
1.118 + }
1.119 +
1.120 + /**
1.121 + * Implementation of the HttpServlet main method.
1.122 + * @param req the request parameter.
1.123 + * @param res the response parameter.
1.124 + * @exception ServletException
1.125 + * @exception IOException
1.126 + */
1.127 + public void service(ServletRequest req, ServletResponse res)
1.128 + throws ServletException, IOException
1.129 + {
1.130 + req.setAttribute("pyservlet", this);
1.131 +
1.132 + String spath = (String)req.getAttribute(
1.133 + "javax.servlet.include.servlet_path");
1.134 + if (spath == null) {
1.135 + spath = ((HttpServletRequest) req).getServletPath();
1.136 + if (spath == null || spath.length() == 0) {
1.137 + // Servlet 2.1 puts the path of an extension-matched
1.138 + // servlet in PathInfo.
1.139 + spath = ((HttpServletRequest) req).getPathInfo();
1.140 + }
1.141 + }
1.142 + String rpath = getServletContext().getRealPath(spath);
1.143 +
1.144 + interp.set("__file__", rpath);
1.145 +
1.146 + // Instead of using the URL to find the Jython servlet, use a supplied
1.147 + // property instead.
1.148 +
1.149 + if (servletFile == null)
1.150 + throw new ServletException("No servlet.file specified in configuration.");
1.151 +
1.152 + HttpServlet servlet = getServlet(rootPath + servletFile);
1.153 + if (servlet != null)
1.154 + servlet.service(req, res);
1.155 + else
1.156 + throw new ServletException("No python servlet found for: " + rpath);
1.157 + }
1.158 +
1.159 + public void reset() {
1.160 + destroyCache();
1.161 + interp = new PythonInterpreter(null, new PySystemState());
1.162 + cache.clear();
1.163 + PySystemState sys = Py.getSystemState();
1.164 + sys.path.append(new PyString(rootPath));
1.165 +
1.166 + String modulesDir = rootPath + "WEB-INF" +
1.167 + File.separator + "jython";
1.168 + sys.path.append(new PyString(modulesDir));
1.169 + }
1.170 +
1.171 + private synchronized HttpServlet getServlet(String path)
1.172 + throws ServletException, IOException
1.173 + {
1.174 + CacheEntry entry = (CacheEntry) cache.get(path);
1.175 + if (entry == null)
1.176 + return loadServlet(path);
1.177 + File file = new File(path);
1.178 + if (file.lastModified() > entry.date)
1.179 + return loadServlet(path);
1.180 + return entry.servlet;
1.181 + }
1.182 +
1.183 + private HttpServlet loadServlet(String path)
1.184 + throws ServletException, IOException
1.185 + {
1.186 + HttpServlet servlet = null;
1.187 + File file = new File(path);
1.188 +
1.189 + // Extract servlet name from path (strip ".../" and ".py")
1.190 + int start = path.lastIndexOf(File.separator);
1.191 + if (start < 0)
1.192 + start = 0;
1.193 + else
1.194 + start++;
1.195 + int end = path.lastIndexOf('.');
1.196 + if ((end < 0) || (end <= start))
1.197 + end = path.length();
1.198 + String name = path.substring(start, end);
1.199 +
1.200 + try {
1.201 + interp.execfile(path);
1.202 + PyObject cls = interp.get(name);
1.203 + if (cls == null)
1.204 + throw new ServletException("No callable (class or function) "+
1.205 + "named " + name + " in " + path);
1.206 +
1.207 + PyObject pyServlet = cls.__call__();
1.208 + Object o = pyServlet.__tojava__(HttpServlet.class);
1.209 + if (o == Py.NoConversion)
1.210 + throw new ServletException("The value from " + name +
1.211 + "must extend HttpServlet");
1.212 + servlet = (HttpServlet)o;
1.213 + servlet.init(getServletConfig());
1.214 +
1.215 + } catch (PyException e) {
1.216 + throw new ServletException("Could not create "+
1.217 + "Jython servlet" + e.toString());
1.218 + }
1.219 + CacheEntry entry = new CacheEntry(servlet, file.lastModified());
1.220 + cache.put(path, entry);
1.221 + return servlet;
1.222 + }
1.223 +
1.224 + public void destroy() {
1.225 + destroyCache();
1.226 + }
1.227 +
1.228 + private void destroyCache() {
1.229 + for (Enumeration e = cache.elements(); e.hasMoreElements(); ) {
1.230 + CacheEntry entry = (CacheEntry) e.nextElement();
1.231 + entry.servlet.destroy();
1.232 + }
1.233 + }
1.234 +
1.235 +}
1.236 +
1.237 +class CacheEntry {
1.238 + public long date;
1.239 + public HttpServlet servlet;
1.240 +
1.241 + CacheEntry(HttpServlet servlet, long date) {
1.242 + this.servlet = servlet;
1.243 + this.date = date;
1.244 + }
1.245 +}