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.BufferedOutputStream;
069: import java.io.DataInputStream;
070: import java.io.IOException;
071: import java.net.Socket;
072:
073: import org.hsqldb.lib.ArrayUtil;
074: import org.hsqldb.rowio.RowInputBinary;
075: import org.hsqldb.rowio.RowOutputBinary;
076:
077: // fredt@users 20020215 - patch 461556 by paul-h@users - server factory
078: // fredt@users 20020424 - patch 1.7.0 by fredt - shutdown without exit
079: // fredt@users 20021002 - patch 1.7.1 by fredt - changed notification method
080: // fredt@users 20030618 - patch 1.7.2 by fredt - changed read/write methods
081:
082: /**
083: * All ServerConnection objects are listed in a Set in server
084: * and removed by this class when closed.<p>
085: *
086: * When the database or server is shutdown, the signalClose() method is called
087: * for all current ServerConnection instances. This will call the private
088: * close() method unless the ServerConnection thread itself has caused the
089: * shutdown. In this case, the keepAlive flag is set to false, allowing the
090: * thread to terminate once it has returned the result of the operation to
091: * the client.
092: * (fredt@users)<p>
093: *
094: * Rewritten in version HSQLDB 1.7.2, based on original Hypersonic code.
095: *
096: * @author Thomas Mueller (Hypersonic SQL Group)
097: * @author fredt@users
098: * @version 1.8.0
099: * @since Hypersonic SQL
100: */
101: class ServerConnection implements Runnable {
102:
103: boolean keepAlive;
104: private String user;
105: private String password;
106: int dbID;
107: private volatile Session session;
108: private Socket socket;
109: private Server server;
110: private DataInputStream dataInput;
111: private BufferedOutputStream dataOutput;
112: private static int mCurrentThread = 0;
113: private int mThread;
114: static final int BUFFER_SIZE = 0x1000;
115: final byte[] mainBuffer = new byte[BUFFER_SIZE];
116: RowOutputBinary rowOut = new RowOutputBinary(BUFFER_SIZE);
117: RowInputBinary rowIn = new RowInputBinary(rowOut);
118: Thread runnerThread;
119:
120: /**
121: * Creates a new ServerConnection to the specified Server on the
122: * specified socket.
123: *
124: * @param socket the network socket on which Server communication
125: * takes place
126: * @param server the Server instance to which the object
127: * represents a connection
128: */
129: ServerConnection(Socket socket, Server server) {
130:
131: this .socket = socket;
132: this .server = server;
133:
134: synchronized (ServerConnection.class) {
135: mThread = mCurrentThread++;
136: }
137:
138: synchronized (server.serverConnSet) {
139: server.serverConnSet.add(this );
140: }
141: }
142:
143: /**
144: * Signals this object to close, including exiting the thread running
145: * the request handling loop
146: */
147: void signalClose() {
148:
149: keepAlive = false;
150:
151: if (!Thread.currentThread().equals(runnerThread)) {
152: close();
153: }
154: }
155:
156: /**
157: * Closes this connection.
158: */
159: private void close() {
160:
161: if (session != null) {
162: session.close();
163:
164: session = null;
165: }
166:
167: // fredt@user - closing the socket is to stop this thread
168: try {
169: socket.close();
170: } catch (IOException e) {
171: }
172:
173: socket = null;
174:
175: synchronized (server.serverConnSet) {
176: server.serverConnSet.remove(this );
177: }
178: }
179:
180: /**
181: * Initializes this connection.
182: */
183: private void init() {
184:
185: runnerThread = Thread.currentThread();
186: keepAlive = true;
187:
188: try {
189: socket.setTcpNoDelay(true);
190:
191: dataInput = new DataInputStream(socket.getInputStream());
192: dataOutput = new BufferedOutputStream(socket
193: .getOutputStream());
194:
195: Result resultIn = Result.read(rowIn, dataInput);
196: Result resultOut;
197:
198: try {
199: dbID = server.getDBID(resultIn.subSubString);
200: user = resultIn.getMainString();
201: password = resultIn.getSubString();
202:
203: if (!server.isSilent()) {
204: server.printWithThread(mThread
205: + ":trying to connect user " + user);
206: }
207:
208: session = DatabaseManager.newSession(dbID, resultIn
209: .getMainString(), resultIn.getSubString());
210: resultOut = new Result(ResultConstants.UPDATECOUNT);
211: resultOut.databaseID = session.getDatabase().databaseID;
212: resultOut.sessionID = session.getId();
213: } catch (HsqlException e) {
214: session = null;
215: resultOut = new Result(e, null);
216: } catch (RuntimeException e) {
217: session = null;
218: resultOut = new Result(e, null);
219: }
220:
221: Result.write(resultOut, rowOut, dataOutput);
222:
223: return;
224: } catch (Exception e) {
225: server.printWithThread(mThread + ":couldn't connect "
226: + user);
227: }
228:
229: close();
230: }
231:
232: /**
233: * Initializes this connection and runs the request handling
234: * loop until closed.
235: */
236: public void run() {
237:
238: init();
239:
240: if (session != null) {
241: try {
242: while (keepAlive) {
243: Result resultIn = Result.read(rowIn, dataInput);
244:
245: server.printRequest(mThread, resultIn);
246:
247: Result resultOut;
248:
249: if (resultIn.mode == ResultConstants.HSQLRESETSESSION) {
250: resultOut = resetSession();
251: } else {
252: resultOut = session.execute(resultIn);
253: }
254:
255: Result.write(resultOut, rowOut, dataOutput);
256: rowOut.setBuffer(mainBuffer);
257: rowIn.resetRow(mainBuffer.length);
258: }
259: } catch (IOException e) {
260:
261: // fredt - is thrown when connection drops
262: server.printWithThread(mThread + ":disconnected "
263: + user);
264: } catch (HsqlException e) {
265:
266: // fredt - is thrown while constructing the result
267: server.printStackTrace(e);
268: }
269: }
270:
271: close();
272: }
273:
274: /**
275: * Used by pooled connections to close the existing SQL session and open
276: * a new one.
277: */
278: private Result resetSession() {
279:
280: Result resultOut;
281:
282: if (!server.isSilent()) {
283: server.printWithThread(mThread + ":trying to connect user "
284: + user);
285: }
286:
287: try {
288: session.close();
289:
290: session = DatabaseManager.newSession(dbID, user, password);
291: resultOut = new Result(ResultConstants.UPDATECOUNT);
292: resultOut.databaseID = session.getDatabase().databaseID;
293: resultOut.sessionID = session.getId();
294: } catch (HsqlException e) {
295: session = null;
296: resultOut = new Result(e, null);
297: }
298:
299: return resultOut;
300: }
301:
302: /**
303: * Retrieves the thread name to be used when
304: * this object is the Runnable object of a Thread.
305: *
306: * @return the thread name to be used when this object is the Runnable
307: * object of a Thread.
308: */
309: String getConnectionThreadName() {
310: return "HSQLDB Connection @" + Integer.toString(hashCode(), 16);
311: }
312: }
|