be36ac86ce2c79b5b0e4157e3522bd8877e00e53
[org.ibex.xt.git] / src / org / ibex / xt / Servlet.java
1 package org.ibex.xt;
2 import org.ibex.js.*;
3 import org.ibex.util.*;
4 import org.ibex.io.*;
5 import java.io.*;
6 import java.net.*;
7 import java.util.*;
8 import javax.servlet.*;
9 import javax.servlet.http.*;
10 import com.thoughtworks.xstream.*;
11 import org.prevayler.*;
12 import org.prevayler.implementation.snapshot.*;
13
14 public class Servlet extends HttpServlet {
15
16     private ServletScope servletscope = null;
17     private String path;
18     private Prevayler prevayler;
19     private JS prevalent;
20     private ServletContext cx = null;
21
22     public void destroy() { try {
23         synchronized(this.getClass()) {
24             Prevayler privatePrevayler = prevayler;
25             if (prevayler == null) return;
26             prevayler = null;
27             Prevalence.destroy(cx, prevayler);
28         }
29     } catch (Exception e) { e.printStackTrace(); } }
30
31     public void init(ServletConfig sc) throws ServletException {
32         cx = sc.getServletContext();
33         prevayler = Prevalence.getPrevayler(cx);
34     }
35
36     public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { doGet(request, response); }
37     public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
38         servletscope = new ServletScope(request, response, cx);
39         path = cx.getRealPath(((HttpServletRequest)request).getServletPath());
40         Reader xmlreader = new InputStreamReader(new FileInputStream(path));
41         new Template(servletscope, new JSScope(servletscope), xmlreader).wrap(null).toXML(response.getWriter());
42     }
43
44     public class ServletScope extends JSScope {
45         HttpServletRequest request;
46         HttpServletResponse response;
47         ServletContext cx;
48         public String getRealPath(String s) { return cx.getRealPath(s); }
49         public ServletScope(ServletRequest request, ServletResponse response, ServletContext cx) {
50             super(null);
51             this.request = (HttpServletRequest)request;
52             this.response = (HttpServletResponse)response;
53             this.cx = cx;
54         }
55         private JS params = new JS() {
56                 public Object get(Object key) { return request.getParameter(JS.toString(key)); }
57                 public Enumeration keys() { return request.getParameterNames(); }
58             };
59         private JS cookies = new JS() {
60                 /*
61                 public Object get(Object key) { return request.getCookie(JS.toString(key)); }
62                 public Enumeration keys() { return request.getCookieNames(); }
63                 */
64             };
65         private JS sessionAttributes = new JS() {
66                 public Object get(Object key) { return request.getSession(true).getAttribute(JS.toString(key)); }
67                 public void put(Object key, Object val) {
68                     if (val == null) request.getSession(true).removeAttribute(JS.toString(key));
69                     else request.setAttribute(JS.toString(key), val); }
70                 public Enumeration keys() { return request.getSession(true).getAttributeNames(); }
71             };
72         private JS requestHeader = new JS() {
73                 public Object get(Object key) { return request.getHeader(JS.toString(key)); }
74                 public Enumeration keys() { return request.getHeaderNames(); }
75             };
76         private JS responseHeader = new JS() {
77                 public void put(Object key, Object val) { response.setHeader(JS.toString(key), JS.toString(val)); }
78             };
79
80
81         /** lets us put multi-level get/put/call keys all in the same method */
82         private class Sub extends JS {
83             Object key;
84             Sub(Object key) { this.key = key; }
85             public void put(Object key, Object val) throws JSExn {
86                 ServletScope.this.put(JS.toString(this.key) + "." + JS.toString(key), val); }
87             public Object get(Object key) throws JSExn {
88                 return ServletScope.this.get(JS.toString(this.key) + "." + JS.toString(key)); }
89             public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
90                 return ServletScope.this.callMethod(this.key, a0, a1, a2, rest, nargs);
91             }
92             public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
93                 return ServletScope.this.callMethod(JS.toString(this.key) + "."
94                                                          + JS.toString(method), a0, a1, a2, rest, nargs);
95             }
96         }
97         private Sub getSub(String key) { return new Sub(key); }
98
99         public Object callMethod(Object method, final Object a, final Object b, Object c, Object[] rest, int nargs) throws JSExn {
100             //#switch(method)
101             case "prevalent.query":
102                 try {
103                     return prevayler.execute(new Prevalence.JSQuery(JS.cloneWithNewParentScope((JS)a, null)));
104                 } catch (Exception e) {
105                     e.printStackTrace();
106                     throw new RuntimeException(e); }
107
108             case "session.invalidate":    request.getSession(true).invalidate(); return null;
109             case "context.list":
110                 String path = JS.toString(a);
111                 if (path.indexOf("..") != -1) throw new JSExn("cannot use .. in paths");
112                 File f = new File(cx.getRealPath("/") + File.separatorChar + path);
113                 if (!f.isDirectory()) return null;
114                 String[] contents = f.list();
115                 JSArray ret = new JSArray(contents.length);
116                 for(int i=0; i<contents.length; i++) ret.addElement(contents[i]);
117                 return ret;
118             //#end
119             return null;
120         }
121         public Object get(Object key) throws JSExn {
122             //#switch(key)
123             case "body":
124             case "arg":                   return null;
125             case "prevalent":             return prevalent;
126             case "request":               return getSub("request");
127             case "request.user":          return request.getRemoteUser();
128             case "request.header":        return requestHeader;
129             case "request.method":        return request.getMethod();
130             case "request.remote":        return getSub("request.remote");
131             case "request.remote.ip":     return request.getRemoteAddr();
132             case "request.remote.host":   return request.getRemoteHost();
133             case "request.ssl":           return request.isSecure();
134             case "request.path":          return request.getPathInfo();
135             case "response":              return getSub("response");
136             case "response.header":       return responseHeader;
137             case "session":               return getSub("session");
138             case "session.attr":          return sessionAttributes;
139             case "session.created":       return new JSDate(request.getSession(true).getCreationTime());
140             case "session.accessed":      return new JSDate(request.getSession(true).getLastAccessedTime());
141             case "session.invalidate":    return METHOD;
142             case "page":                  return getSub("page");
143             case "page.lastmodified":     return new JSDate(new File(path).lastModified());
144             case "context":               return getSub("context");
145             case "context.list":          return METHOD;
146             case "params":                return params;
147             case "cookie":                return cookies;
148             //#end
149             return null;
150         }
151         public void put(Object key, Object val) throws JSExn {
152             try {
153             //#switch(JS.toString(key))
154             case "response.code":         response.setStatus(JS.toInt(val));
155             case "response.redirect":     response.sendRedirect(JS.toString(val));
156             case "response.contentType":  response.setContentType(JS.toString(val));
157             case "prevalent":             
158                 try { prevayler.execute(new Prevalence.JSTransaction(JS.cloneWithNewParentScope((JS)val, null)));
159                 } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }
160             //#end
161             } catch (IOException e) {
162                 throw new JSExn(e);
163             }
164         }
165     }
166
167 }