001: /*
002: * HttpScriptServlet.java
003: *
004: * @version 1.0
005: * @author Mike Grogan
006: * @reated on March 2, 2004, 3:50 PM
007: */
008:
009: package javax.script.http;
010:
011: import javax.servlet.*;
012: import javax.servlet.http.*;
013: import java.io.IOException;
014: import javax.script.*;
015: import java.io.Reader;
016: import java.io.Writer;
017: import java.util.*;
018:
019: /**
020: * A <code>HttpScriptServlet</code> uses a <code>ScriptEngine</code> supplied by
021: * calling its <code>getEngine</code> method to execute a script in a
022: * <code>HttpScriptContext</code> returned by its <code>getContext</code> method.
023: */
024: public abstract class HttpScriptServlet extends GenericServlet {
025:
026: /**
027: * Returns a <code>HttpScriptContext</code> initialized using the specified
028: * <code>HttpServletRequest</code>, <code>HttpServletResponse</code> and a
029: * reference to this <code>HttpScriptServlet</code>
030: * @param req The specified <code>HttpServletRequest</code>.
031: * @param res The specified <code>HttpServletResponse</code>.
032: * @return the initialized <code>HttpScriptContext</code>.
033: * @throws ServletException if error occurrs
034: */
035: public abstract HttpScriptContext getContext(
036: HttpServletRequest req, HttpServletResponse res)
037: throws ServletException;
038:
039: /**
040: * Returns a <code>ScriptEngine</code> that is used by the <code>HttpScriptServlet</code>
041: * to execute a single request.<p>
042: * The implementation must ensure that if the same engine is used to service
043: * requests concurrently on multiple threads that side-effects of script execution
044: * on any thread will not be visible in the engine scopes of other threads. This
045: * will be the case if the returned <code>ScriptEngine</code> implements a class
046: * associated with a <code>ScriptEngineInfo</code> where either
047: * <code>getParameter("THREAD-ISOLATED")</code> or <code>getParameter("STATELESS")</code> returns
048: * <code>java.lang.Boolean.TRUE</code>.
049: * @param request The current request.
050: * @return The <code>ScriptEngine</code> used by this <code>HttpScriptServlet</code> to
051: * execute requests.
052: */
053: public abstract ScriptEngine getEngine(HttpServletRequest request);
054:
055: /**
056: * Called to indicate that a <code>ScriptEngine</code> retruned by a call to
057: * <code>getEngine</code> is no longer in use.
058: * @param engine The <code>ScriptEngine</code>
059: */
060: public abstract void releaseEngine(ScriptEngine engine);
061:
062: /**
063: * Executes a request using the <code>HttpScriptContext</code> returned by
064: * <code>getContext</code> and the <code>ScriptEngine</code> returned by
065: * <code>getEngine</code>.
066: * <p>
067: * A default implementation is provided:
068: * <p>
069: * @param req The current request. Must be an instance of <code>HttpServletRequest</code>.
070: * @param res The current response. Must be an instance of <code>HttpServletResponse</code>.
071: * @throws IllegalArgumentException If either req is not an instance of <code>HttpServletRequest</code>
072: * or res is not an instance of <code>HttpServletResponse</code>
073: * @throws ServletException
074: * @throws IOException
075: */
076:
077: public void service(ServletRequest req, ServletResponse res)
078: throws ServletException, IOException {
079: if (!(req instanceof HttpServletRequest)
080: || !(res instanceof HttpServletResponse)) {
081: throw new IllegalArgumentException();
082: }
083:
084: HttpServletRequest httpreq = (HttpServletRequest) req;
085: HttpServletResponse httpres = (HttpServletResponse) res;
086: Writer httpwriter = httpres.getWriter();
087:
088: HttpScriptContext ctxt = getContext(httpreq, httpres);
089:
090: //if script-disable init parameter is set return "403 Forbidden"
091: if (ctxt.disableScript()) {
092: httpres.setStatus(HttpServletResponse.SC_FORBIDDEN);
093: return;
094: }
095:
096: //if request method is not among those listed in script-method
097: //init parameter, return "405 Method Not Allowed"
098: String[] methods = ctxt.getMethods();
099: int numMethods = methods.length;
100: String method = httpreq.getMethod();
101:
102: int i = 0;
103: for (i = 0; i < numMethods; i++) {
104: if (method.compareToIgnoreCase(methods[i]) == 0) {
105: break;
106: }
107: }
108:
109: if (i == numMethods) {
110: httpres
111: .setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
112: return;
113: }
114:
115: ScriptEngine engine = null;
116:
117: try {
118:
119: engine = getEngine(httpreq);
120:
121: //if allowable languages are constrained in the configuration
122: //check that the engine handles one of the allowed ones.
123: String[] languages = ctxt.getAllowedLanguages();
124:
125: if (languages != null) {
126:
127: checkLanguages: {
128: List<String> names = engine.getFactory().getNames();
129: int lenLanguages = languages.length;
130:
131: for (String name : names) {
132: for (int j = 0; j < lenLanguages; j++) {
133: if (name.equals(languages[j])) {
134: break checkLanguages;
135: }
136: }
137: }
138: httpres.setStatus(HttpServletResponse.SC_FORBIDDEN);
139: return;
140: }
141: }
142:
143: Reader reader = ctxt.getScriptSource();
144:
145: ctxt.getBindings(ScriptContext.ENGINE_SCOPE).put(
146: ScriptEngine.FILENAME, httpreq.getRequestURI());
147:
148: if (reader == null) {
149: httpres.setStatus(HttpServletResponse.SC_NOT_FOUND);
150: return;
151: }
152:
153: //add required objects to script bindings
154:
155: ctxt.getBindings(ScriptContext.ENGINE_SCOPE).put("request",
156: ctxt.getRequest());
157: ctxt.getBindings(ScriptContext.ENGINE_SCOPE).put(
158: "response", ctxt.getResponse());
159: ctxt.getBindings(ScriptContext.ENGINE_SCOPE).put("context",
160: ctxt);
161: ctxt.getBindings(ScriptContext.ENGINE_SCOPE).put("servlet",
162: this );
163:
164: res.setContentType("text/html");
165:
166: //eval the script
167: Object ret = engine.eval(ctxt.getScriptSource(), ctxt);
168:
169: //display the toString value of the return value unless
170: //the script-display-results InitParameter is "false"
171: if (ret != null && ctxt.displayResults()) {
172: httpwriter.write(ret.toString());
173: }
174:
175: httpwriter.flush();
176: reader.close();
177:
178: } catch (ScriptException e) {
179: httpres
180: .setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
181: throw new ServletException(e);
182: } finally {
183:
184: if (engine != null) {
185: releaseEngine(engine);
186: }
187:
188: ctxt.release();
189: }
190: }
191:
192: }
|