blob: e26635ac506911db99bf1deb9ff8ca26bbea5ff2 [file] [log] [blame]
/*
* For work developed by the HSQL Development Group:
*
* Copyright (c) 2001-2010, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*
* For work originally developed by the Hypersonic SQL Group:
*
* Copyright (c) 1995-2000, The Hypersonic SQL Group.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the Hypersonic SQL Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Hypersonic SQL Group.
*/
package org.hsqldb.server;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hsqldb.DatabaseManager;
import org.hsqldb.DatabaseURL;
import org.hsqldb.HsqlException;
import org.hsqldb.Session;
import org.hsqldb.lib.DataOutputStream;
import org.hsqldb.persist.HsqlProperties;
import org.hsqldb.result.Result;
import org.hsqldb.result.ResultConstants;
import org.hsqldb.rowio.RowInputBinary;
import org.hsqldb.rowio.RowOutputBinary;
// fredt@users 20020130 - patch 475586 by wreissen@users
// fredt@users 20020328 - patch 1.7.0 by fredt - error trapping
// fredt@users 20030630 - patch 1.7.2 - new protocol, persistent sessions
// fredt@users 20041112 - patch by Willian Crick - use web_inf directory
/**
* Servlet can act as an interface between the client and the database for the
* the client / server mode of HSQL Database Engine. It uses the HTTP protocol
* for communication. This class is not required if the included HSQLDB
* Weberver is used on the server host. But if the host is running a J2EE
* application server or a servlet container such as Tomcat, the Servlet class
* can be hosted on this server / container to serve external requests from
* external hosts.<p>
* The remote applet / application should
* use the normal JDBC interfaces to connect to the URL of this servlet. An
* example URL is:
* <pre>
* jdbc:hsqldb:http://myhost.com:8080/servlet/org.hsqldb.server.Servlet
* </pre>
* The database path/name is taken from the servlet engine property:
* <pre>
* hsqldb.server.database
* </pre>
* <p>
* If the database is deployed in the WEB-INF directory of the servlet container,
* the property:
* <pre>
* hsqldb.server.use_web-inf_path
* </pre>
* should be set "true" in the web.xml file of the servlet container.
* In this case, the database path should begin with a "/".
*
* JDBC connections via the HTTP protocol are persistent
* in the JDBC sense. The JDBC Connection that is established can support
* transactions spanning several Statement calls and real PreparedStatement
* calls are supported. This class has been rewritten to support the new
* features.<p>
* (fredt@users)<p>
*
* Extensively rewritten for HSQLDB.
*
* @author Thomas Mueller (Hypersonic SQL Group)
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 1.9.0
* @since Hypersonic SQL
*/
public class Servlet extends javax.servlet.http.HttpServlet {
private static final int BUFFER_SIZE = 256;
private String dbType;
private String dbPath;
private String errorStr;
private RowOutputBinary rowOut;
private RowInputBinary rowIn;
private int iQueries;
public void init(ServletConfig config) {
try {
super.init(config);
rowOut = new RowOutputBinary(BUFFER_SIZE, 1);
rowIn = new RowInputBinary(rowOut);
} catch (ServletException e) {
log(e.toString());
}
String dbStr = getInitParameter("hsqldb.server.database");
if (dbStr == null) {
dbStr = ".";
}
// begin WEB-INF patch */
String useWebInfStr =
getInitParameter("hsqldb.server.use_web-inf_path");
if (!dbStr.equals(".") && "true".equalsIgnoreCase(useWebInfStr)) {
dbStr = getServletContext().getRealPath("/") + "WEB-INF/" + dbStr;
}
// end WEB-INF patch
HsqlProperties dbURL = DatabaseURL.parseURL(dbStr, false, false);
log("Database filename = " + dbStr);
if (dbURL == null) {
errorStr = "Bad Database name";
} else {
dbPath = dbURL.getProperty("database");
dbType = dbURL.getProperty("connection_type");
try {
// loosecannon1@users 1.7.2 patch properties on the JDBC URL
DatabaseManager.getDatabase(dbType, dbPath, dbURL);
} catch (HsqlException e) {
errorStr = e.getMessage();
}
}
log(errorStr);
log("Initialization completed.");
}
private static long lModified = 0;
protected long getLastModified(HttpServletRequest req) {
// this is made so that the cache of the http server is not used
// maybe there is some other way
return lModified++;
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
String query = request.getQueryString();
if ((query == null) || (query.length() == 0)) {
response.setContentType("text/html");
// fredt@users 20020130 - patch 1.7.0 by fredt
// to avoid caching on the browser
response.setHeader("Pragma", "no-cache");
PrintWriter out = response.getWriter();
out.println(
"<html><head><title>HSQL Database Engine Servlet</title>");
out.println("</head><body><h1>HSQL Database Engine Servlet</h1>");
out.println("The servlet is running.<p>");
if (errorStr == null) {
out.println("The database is also running.<p>");
out.println("Database name: " + dbType + dbPath + "<p>");
out.println("Queries processed: " + iQueries + "<p>");
} else {
out.println("<h2>The database is not running!</h2>");
out.println("The error message is:<p>");
out.println(errorStr);
}
out.println("</body></html>");
}
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
synchronized (this) {
DataInputStream inStream = null;
DataOutputStream dataOut = null;
try {
// fredt@users - the servlet container, Resin does not return all
// the bytes with one call to input.read(b,0,len) when len > 8192
// bytes, the loop in the Result.read() method handles this
inStream = new DataInputStream(request.getInputStream());
int databaseID = inStream.readInt();
long sessionID = inStream.readLong();
int mode = inStream.readByte();
Session session = DatabaseManager.getSession(databaseID,
sessionID);
Result resultIn = Result.newResult(session, mode, inStream,
rowIn);
resultIn.setDatabaseId(databaseID);
resultIn.setSessionId(sessionID);
Result resultOut;
if (resultIn.getType() == ResultConstants.CONNECT) {
try {
session = DatabaseManager.newSession(
dbType, dbPath, resultIn.getMainString(),
resultIn.getSubString(), new HsqlProperties(),
resultIn.getZoneString(),
resultIn.getUpdateCount());
resultIn.readAdditionalResults(null, inStream, rowIn);
resultOut = Result.newConnectionAcknowledgeResponse(
session.getDatabase(), session.getId(),
session.getDatabase().getDatabaseID());
} catch (HsqlException e) {
resultOut = Result.newErrorResult(e);
}
} else {
int dbId = resultIn.getDatabaseId();
long sessionId = resultIn.getSessionId();
session = DatabaseManager.getSession(dbId, sessionId);
resultIn.readAdditionalResults(session, inStream, rowIn);
resultOut = session.execute(resultIn);
}
//
response.setContentType("application/octet-stream");
response.setContentLength(rowOut.size());
//
dataOut = new DataOutputStream(response.getOutputStream());
resultOut.write(dataOut, rowOut);
iQueries++;
} catch (HsqlException e) {}
finally {
if (dataOut != null) {
dataOut.close();
}
if (inStream != null) {
inStream.close();
}
}
}
// Trace.printSystemOut("Queries processed: "+iQueries+" \n");
}
}