001: /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the Hypersonic SQL Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: *
030: * This software consists of voluntary contributions made by many individuals
031: * on behalf of the Hypersonic SQL Group.
032: *
033: *
034: * For work added by the HSQL Development Group:
035: *
036: * Copyright (c) 2001-2005, The HSQL Development Group
037: * All rights reserved.
038: *
039: * Redistribution and use in source and binary forms, with or without
040: * modification, are permitted provided that the following conditions are met:
041: *
042: * Redistributions of source code must retain the above copyright notice, this
043: * list of conditions and the following disclaimer.
044: *
045: * Redistributions in binary form must reproduce the above copyright notice,
046: * this list of conditions and the following disclaimer in the documentation
047: * and/or other materials provided with the distribution.
048: *
049: * Neither the name of the HSQL Development Group nor the names of its
050: * contributors may be used to endorse or promote products derived from this
051: * software without specific prior written permission.
052: *
053: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
054: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
055: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
056: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
057: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
058: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
059: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
060: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
061: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
062: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
063: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
064: */
065:
066: package org.hsqldb;
067:
068: import java.io.DataInputStream;
069: import java.io.IOException;
070: import java.io.PrintWriter;
071:
072: import javax.servlet.ServletConfig;
073: import javax.servlet.ServletException;
074: import javax.servlet.ServletOutputStream;
075: import javax.servlet.http.HttpServletRequest;
076: import javax.servlet.http.HttpServletResponse;
077:
078: import org.hsqldb.persist.HsqlProperties;
079: import org.hsqldb.rowio.RowInputBinary;
080: import org.hsqldb.rowio.RowOutputBinary;
081:
082: // fredt@users 20020130 - patch 475586 by wreissen@users
083: // fredt@users 20020328 - patch 1.7.0 by fredt - error trapping
084: // fredt@users 20030630 - patch 1.7.2 - new protocol, persistent sessions
085: // fredt@users 20041112 - patch by Willian Crick - use web_inf directory
086:
087: /**
088: * Servlet can act as an interface between the client and the database for the
089: * the client / server mode of HSQL Database Engine. It uses the HTTP protocol
090: * for communication. This class is not required if the included HSQLDB
091: * Weberver is used on the server host. But if the host is running a J2EE
092: * application server or a servlet container such as Tomcat, the Servlet class
093: * can be hosted on this server / container to serve external requests from
094: * external hosts.<p>
095: * The remote applet / application should
096: * use the normal JDBC interfaces to connect to the URL of this servlet. An
097: * example URL is:
098: * <pre>
099: * jdbc:hsqldb:http://localhost.com:8080/servlet/org.hsqldb.Servlet
100: * </pre>
101: * The database path/name is taken from the servlet engine property:
102: * <pre>
103: * hsqldb.server.database
104: * </pre>
105: * <p>
106: * If the database is deployed in the WEB-INF directory of the servlet container,
107: * the property:
108: * <pre>
109: * hsqldb.server.use_web-inf_path
110: * </pre>
111: * should be set "true" in the web.xml file of the servlet container.
112: * In this case, the database path should not begin with a "/".
113: *
114: * From version 1.7.2 JDBC connections via the HTTP protocol are persistent
115: * in the JDBC sense. The JDBC Connection that is established can support
116: * transactions spanning several Statement calls and real PreparedStatement
117: * calls are supported. This class has been rewritten to support the new
118: * features.<p>
119: * (fredt@users)<p>
120: *
121: * Extensively rewritten for HSQLDB.
122: *
123: * @author Thomas Mueller (Hypersonic SQL Group)
124: * @version 1.7.2
125: * @since Hypersonic SQL
126: */
127: public class Servlet extends javax.servlet.http.HttpServlet {
128:
129: private static final int BUFFER_SIZE = 256;
130: private String dbType;
131: private String dbPath;
132: private String errorStr;
133: private RowOutputBinary rowOut;
134: private RowInputBinary rowIn;
135: private int iQueries;
136:
137: /**
138: * Method declaration
139: *
140: *
141: * @param config
142: */
143: public void init(ServletConfig config) {
144:
145: try {
146: super .init(config);
147:
148: rowOut = new RowOutputBinary(BUFFER_SIZE);
149: rowIn = new RowInputBinary(rowOut);
150: } catch (ServletException e) {
151: log(e.toString());
152: }
153:
154: String dbStr = getInitParameter("hsqldb.server.database");
155:
156: if (dbStr == null) {
157: dbStr = ".";
158: }
159:
160: // begin WEB-INF patch */
161: String useWebInfStr = getInitParameter("hsqldb.server.use_web-inf_path");
162:
163: if (!dbStr.equals(".") && "true".equalsIgnoreCase(useWebInfStr)) {
164: dbStr = getServletContext().getRealPath("/") + "WEB-INF"
165: + dbStr;
166: }
167:
168: // end WEB-INF patch
169: HsqlProperties dbURL = DatabaseURL.parseURL(dbStr, false);
170:
171: log("Database filename = " + dbStr);
172:
173: if (dbURL == null) {
174: errorStr = "Bad Database name";
175: } else {
176: dbPath = dbURL.getProperty("database");
177: dbType = dbURL.getProperty("connection_type");
178:
179: try {
180:
181: // loosecannon1@users 1.7.2 patch properties on the JDBC URL
182: DatabaseManager.getDatabase(dbType, dbPath, dbURL);
183: } catch (HsqlException e) {
184: errorStr = e.getMessage();
185: }
186: }
187:
188: log(errorStr);
189: log("Initialization completed.");
190: }
191:
192: private static long lModified = 0;
193:
194: /**
195: * Method declaration
196: *
197: *
198: * @param req
199: *
200: * @return
201: */
202: protected long getLastModified(HttpServletRequest req) {
203:
204: // this is made so that the cache of the http server is not used
205: // maybe there is some other way
206: return lModified++;
207: }
208:
209: /**
210: * Method declaration
211: *
212: *
213: * @param request
214: * @param response
215: *
216: * @throws IOException
217: * @throws ServletException
218: */
219: public void doGet(HttpServletRequest request,
220: HttpServletResponse response) throws IOException,
221: ServletException {
222:
223: String query = request.getQueryString();
224:
225: if ((query == null) || (query.length() == 0)) {
226: response.setContentType("text/html");
227:
228: // fredt@users 20020130 - patch 1.7.0 by fredt
229: // to avoid caching on the browser
230: response.setHeader("Pragma", "no-cache");
231:
232: PrintWriter out = response.getWriter();
233:
234: out
235: .println("<html><head><title>HSQL Database Engine Servlet</title>");
236: out
237: .println("</head><body><h1>HSQL Database Engine Servlet</h1>");
238: out.println("The servlet is running.<p>");
239:
240: if (errorStr == null) {
241: out.println("The database is also running.<p>");
242: out
243: .println("Database name: " + dbType + dbPath
244: + "<p>");
245: out.println("Queries processed: " + iQueries + "<p>");
246: } else {
247: out.println("<h2>The database is not running!</h2>");
248: out.println("The error message is:<p>");
249: out.println(errorStr);
250: }
251:
252: out.println("</body></html>");
253: }
254: }
255:
256: /**
257: * Method declaration
258: *
259: *
260: * @param request
261: * @param response
262: *
263: * @throws IOException
264: * @throws ServletException
265: */
266: public void doPost(HttpServletRequest request,
267: HttpServletResponse response) throws IOException,
268: ServletException {
269:
270: synchronized (this ) {
271: DataInputStream inStream = null;
272: ServletOutputStream outStream = null;
273:
274: try {
275:
276: // fredt@users - the servlet container, Resin does not return all
277: // the bytes with one call to input.read(b,0,len) when len > 8192
278: // bytes, the loop in the Result.read() method handles this
279: inStream = new DataInputStream(request.getInputStream());
280:
281: Result resultIn = Result.read(rowIn, inStream);
282: Result resultOut;
283:
284: if (resultIn.mode == ResultConstants.SQLCONNECT) {
285: try {
286: Session session = DatabaseManager.newSession(
287: dbType, dbPath, resultIn
288: .getMainString(), resultIn
289: .getSubString(), null);
290:
291: resultOut = new Result(
292: ResultConstants.UPDATECOUNT);
293: resultOut.sessionID = session.getId();
294: } catch (HsqlException e) {
295: resultOut = new Result(e, null);
296: }
297: } else {
298: int dbId = resultIn.databaseID;
299: int sessionId = resultIn.sessionID;
300: Session session = DatabaseManager.getSession(dbId,
301: sessionId);
302:
303: resultOut = session.execute(resultIn);
304: }
305:
306: rowOut.reset();
307: resultOut.write(rowOut);
308:
309: //
310: response.setContentType("application/octet-stream");
311: response.setContentLength(rowOut.size());
312:
313: //
314: outStream = response.getOutputStream();
315:
316: outStream.write(rowOut.getOutputStream().getBuffer(),
317: 0, rowOut.getOutputStream().size());
318:
319: iQueries++;
320: } catch (HsqlException e) {
321: } finally {
322: if (outStream != null) {
323: outStream.close();
324: }
325:
326: if (inStream != null) {
327: inStream.close();
328: }
329: }
330: }
331:
332: // Trace.printSystemOut("Queries processed: "+iQueries+" \n");
333: }
334: }
|