001: package org.python.util;
002:
003: import java.io.*;
004: import java.util.*;
005: import javax.servlet.*;
006: import javax.servlet.http.*;
007: import org.python.core.*;
008:
009: /**
010: * This servlet is used to re-serve JPython servlets. It stores
011: * bytecode for JPython servlets and re-uses it if the underlying .py
012: * file has not changed.
013: * <p>
014: * Many people have been involved with this class:
015: * <ul>
016: * <li>Chris Gokey
017: * <li>David Syer
018: * <li>Finn Bock
019: * </ul>
020: * If somebody is missing from this list, let us know.
021: * <p>
022: *
023: * e.g. http://localhost:8080/test/hello.py
024: * <pre>
025: *
026: * from javax.servlet.http import HttpServlet
027: * class hello(HttpServlet):
028: * def doGet(self, req, res):
029: * res.setContentType("text/html");
030: * out = res.getOutputStream()
031: * print >>out, "<html>"
032: * print >>out, "<head><title>Hello World, How are we?</title></head>"
033: * print >>out, "<body>Hello World, how are we?"
034: * print >>out, "</body>"
035: * print >>out, "</html>"
036: * out.close()
037: * return
038: * </pre>
039: *
040: * in web.xml for the PyServlet context:
041: * <pre>
042: * <web-app>
043: * <servlet>
044: * <servlet-name>PyServlet</servlet-name>
045: * <servlet-class>org.python.util.PyServlet</servlet-class>
046: * <init-param>
047: * <param-name>python.home</param-name>
048: * <param-value>/usr/home/jython-2.1</param-value>
049: * </init-param>
050: * </servlet>
051: * <servlet-mapping>
052: * <servlet-name>PyServlet</servlet-name>
053: * <url-pattern>*.py</url-pattern>
054: * </servlet-mapping>
055: * </web-app>
056: *
057: * </pre>
058: */
059:
060: public class PyServlet extends HttpServlet {
061: private PythonInterpreter interp;
062: private Hashtable cache = new Hashtable();
063: private String rootPath;
064:
065: public void init() {
066: rootPath = getServletContext().getRealPath("/");
067: if (!rootPath.endsWith(File.separator))
068: rootPath += File.separator;
069:
070: Properties props = new Properties();
071: Properties baseProps = PySystemState.getBaseProperties();
072:
073: // Context parameters
074: ServletContext context = getServletContext();
075: Enumeration e = context.getInitParameterNames();
076: while (e.hasMoreElements()) {
077: String name = (String) e.nextElement();
078: props.put(name, context.getInitParameter(name));
079: }
080:
081: // Config parameters
082: e = getInitParameterNames();
083: while (e.hasMoreElements()) {
084: String name = (String) e.nextElement();
085: props.put(name, getInitParameter(name));
086: }
087:
088: if (props.getProperty("python.home") == null
089: && baseProps.getProperty("python.home") == null) {
090: props.put("python.home", rootPath + "WEB-INF"
091: + File.separator + "lib");
092: }
093:
094: PySystemState.initialize(baseProps, props, new String[0]);
095: reset();
096:
097: PySystemState.add_package("javax.servlet");
098: PySystemState.add_package("javax.servlet.http");
099: PySystemState.add_package("javax.servlet.jsp");
100: PySystemState.add_package("javax.servlet.jsp.tagext");
101:
102: PySystemState.add_classdir(rootPath + "WEB-INF"
103: + File.separator + "classes");
104:
105: PySystemState.add_extdir(rootPath + "WEB-INF" + File.separator
106: + "lib", true);
107: }
108:
109: /**
110: * Implementation of the HttpServlet main method.
111: * @param req the request parameter.
112: * @param res the response parameter.
113: * @exception ServletException
114: * @exception IOException
115: */
116: public void service(ServletRequest req, ServletResponse res)
117: throws ServletException, IOException {
118: req.setAttribute("pyservlet", this );
119:
120: String spath = (String) req
121: .getAttribute("javax.servlet.include.servlet_path");
122: if (spath == null) {
123: spath = ((HttpServletRequest) req).getServletPath();
124: if (spath == null || spath.length() == 0) {
125: // Servlet 2.1 puts the path of an extension-matched
126: // servlet in PathInfo.
127: spath = ((HttpServletRequest) req).getPathInfo();
128: }
129: }
130: String rpath = getServletContext().getRealPath(spath);
131:
132: interp.set("__file__", rpath);
133:
134: HttpServlet servlet = getServlet(rpath);
135: if (servlet != null)
136: servlet.service(req, res);
137: else
138: throw new ServletException("No python servlet found at:"
139: + spath);
140: }
141:
142: public void reset() {
143: destroyCache();
144: interp = new PythonInterpreter(null, new PySystemState());
145: cache.clear();
146:
147: PySystemState sys = Py.getSystemState();
148: sys.path.append(new PyString(rootPath));
149:
150: String modulesDir = rootPath + "WEB-INF" + File.separator
151: + "jython";
152: sys.path.append(new PyString(modulesDir));
153: }
154:
155: private synchronized HttpServlet getServlet(String path)
156: throws ServletException, IOException {
157: CacheEntry entry = (CacheEntry) cache.get(path);
158: if (entry == null)
159: return loadServlet(path);
160: File file = new File(path);
161: if (file.lastModified() > entry.date)
162: return loadServlet(path);
163: return entry.servlet;
164: }
165:
166: private HttpServlet loadServlet(String path)
167: throws ServletException, IOException {
168: HttpServlet servlet = null;
169: File file = new File(path);
170:
171: // Extract servlet name from path (strip ".../" and ".py")
172: int start = path.lastIndexOf(File.separator);
173: if (start < 0)
174: start = 0;
175: else
176: start++;
177: int end = path.lastIndexOf('.');
178: if ((end < 0) || (end <= start))
179: end = path.length();
180: String name = path.substring(start, end);
181:
182: try {
183: interp.execfile(path);
184: PyObject cls = interp.get(name);
185: if (cls == null) {
186: throw new ServletException(
187: "No callable (class or function) named " + name
188: + " in " + path);
189: }
190: PyObject pyServlet = cls.__call__();
191: Object o = pyServlet.__tojava__(HttpServlet.class);
192: if (o == Py.NoConversion) {
193: throw new ServletException("The value from " + name
194: + " must extend HttpServlet");
195: }
196: servlet = (HttpServlet) o;
197: servlet.init(getServletConfig());
198:
199: } catch (PyException e) {
200: throw new ServletException(e);
201: }
202: CacheEntry entry = new CacheEntry(servlet, file.lastModified());
203: cache.put(path, entry);
204: return servlet;
205: }
206:
207: public void destroy() {
208: destroyCache();
209: }
210:
211: private void destroyCache() {
212: for (Enumeration e = cache.elements(); e.hasMoreElements();) {
213: CacheEntry entry = (CacheEntry) e.nextElement();
214: entry.servlet.destroy();
215: }
216: }
217:
218: }
219:
220: class CacheEntry {
221: public long date;
222: public HttpServlet servlet;
223:
224: CacheEntry(HttpServlet servlet, long date) {
225: this.servlet = servlet;
226: this.date = date;
227: }
228: }
|