KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > engine > SessionRemote


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.engine;
6
7 import java.io.IOException JavaDoc;
8 import java.net.InetAddress JavaDoc;
9 import java.net.Socket JavaDoc;
10 import java.sql.SQLException JavaDoc;
11
12 import org.h2.command.CommandInterface;
13 import org.h2.command.CommandRemote;
14 import org.h2.command.dml.SetTypes;
15 import org.h2.jdbc.JdbcSQLException;
16 import org.h2.message.Message;
17 import org.h2.message.Trace;
18 import org.h2.message.TraceSystem;
19 import org.h2.store.DataHandler;
20 import org.h2.store.FileStore;
21 import org.h2.util.FileUtils;
22 import org.h2.util.MathUtils;
23 import org.h2.util.NetUtils;
24 import org.h2.util.ObjectArray;
25 import org.h2.util.RandomUtils;
26 import org.h2.util.StringUtils;
27 import org.h2.value.Transfer;
28 import org.h2.value.Value;
29
30 public class SessionRemote implements SessionInterface, DataHandler {
31
32     public static final int SESSION_PREPARE = 0;
33     public static final int SESSION_CLOSE = 1;
34     public static final int COMMAND_EXECUTE_QUERY = 2;
35     public static final int COMMAND_EXECUTE_UPDATE = 3;
36     public static final int COMMAND_CLOSE = 4;
37     public static final int RESULT_FETCH_ROW = 5;
38     public static final int RESULT_RESET = 6;
39     public static final int RESULT_CLOSE = 7;
40     public static final int COMMAND_COMMIT = 8;
41     public static final int CHANGE_ID = 9;
42     public static final int STATUS_ERROR = 0;
43     public static final int STATUS_OK = 1;
44     public static final int STATUS_CLOSED = 2;
45     private TraceSystem traceSystem;
46     private Trace trace;
47     private ObjectArray transferList;
48     private int nextId;
49     private boolean autoCommit = true;
50     private CommandInterface switchOffAutoCommit;
51     private ConnectionInfo connectionInfo;
52     private int objectId;
53     private String JavaDoc databaseName;
54     private String JavaDoc cipher;
55     private byte[] fileEncryptionKey;
56
57     private Transfer initTransfer(ConnectionInfo ci, String JavaDoc db, String JavaDoc server) throws IOException JavaDoc, SQLException JavaDoc {
58         int port = Constants.DEFAULT_SERVER_PORT;
59         // IPv6: RFC 2732 format is '[a:b:c:d:e:f:g:h]' or '[a:b:c:d:e:f:g:h]:port'
60
// RFC 2396 format is 'a.b.c.d' or 'a.b.c.d:port' or 'hostname' or 'hostname:port'
61
int startIndex = server.startsWith("[") ? server.indexOf(']') : 0;
62         int idx = server.indexOf(':', startIndex);
63         if (idx >= 0) {
64             port = MathUtils.decodeInt(server.substring(idx + 1));
65             server = server.substring(0, idx);
66         }
67         InetAddress JavaDoc address = InetAddress.getByName(server);
68         Socket JavaDoc socket = NetUtils.createSocket(address, port, ci.isSSL());
69         Transfer trans = new Transfer(this);
70         trans.setSocket(socket);
71         trans.init();
72         trans.writeInt(Constants.TCP_DRIVER_VERSION);
73         trans.writeString(db);
74         trans.writeString(ci.getOriginalURL());
75         trans.writeString(ci.getUserName());
76         trans.writeBytes(ci.getUserPasswordHash());
77         trans.writeBytes(ci.getFilePasswordHash());
78         String JavaDoc[] keys = ci.getKeys();
79         trans.writeInt(keys.length);
80         for(int i=0; i<keys.length; i++) {
81             String JavaDoc key = keys[i];
82             trans.writeString(key).writeString(ci.getProperty(key));
83         }
84         try {
85             done(trans);
86         } catch(SQLException JavaDoc e) {
87             trans.close();
88             throw e;
89         }
90         autoCommit = true;
91         return trans;
92     }
93
94     private void switchOffAutocommitIfCluster() throws SQLException JavaDoc {
95         if(autoCommit && transferList.size() > 1) {
96             if(switchOffAutoCommit == null) {
97                 switchOffAutoCommit = prepareCommand("SET AUTOCOMMIT FALSE");
98             }
99             // this will call setAutocommit(false)
100
switchOffAutoCommit.executeUpdate();
101             // so we need to switch it on
102
autoCommit = true;
103         }
104     }
105
106     public void setAutoCommit(boolean autoCommit) {
107         this.autoCommit = autoCommit;
108     }
109
110     public void autoCommitIfCluster() throws SQLException JavaDoc {
111         if(autoCommit && transferList!= null && transferList.size() > 1) {
112             // server side autocommit is off because of race conditions
113
// (update set id=1 where id=0, but update set id=2 where id=0 is faster)
114
for(int i=0; i<transferList.size(); i++) {
115                 Transfer transfer = (Transfer) transferList.get(i);
116                 try {
117                     traceOperation("COMMAND_COMMIT", 0);
118                     transfer.writeInt(SessionRemote.COMMAND_COMMIT);
119                     done(transfer);
120                 } catch(IOException JavaDoc e) {
121                     removeServer(i);
122                 }
123             }
124         }
125     }
126
127     private String JavaDoc getTraceFilePrefix(String JavaDoc dbName) throws SQLException JavaDoc {
128         String JavaDoc dir = Constants.CLIENT_TRACE_DIRECTORY;
129         StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
130         buff.append(dir);
131         for(int i=0; i<dbName.length(); i++) {
132             char ch = dbName.charAt(i);
133             if(Character.isLetterOrDigit(ch)) {
134                 buff.append(ch);
135             } else {
136                 buff.append('_');
137             }
138         }
139         return buff.toString();
140     }
141
142     public SessionRemote() {
143     }
144
145     public int getPowerOffCount() {
146         return 0;
147     }
148
149     public void setPowerOffCount(int count) throws SQLException JavaDoc {
150         throw Message.getUnsupportedException();
151     }
152
153     public SessionInterface createSession(ConnectionInfo ci) throws SQLException JavaDoc {
154         return new SessionRemote(ci);
155     }
156
157     private SessionRemote(ConnectionInfo ci) throws SQLException JavaDoc {
158         this.connectionInfo = ci;
159         connect();
160     }
161
162     private void connect() throws SQLException JavaDoc {
163         ConnectionInfo ci = connectionInfo;
164         String JavaDoc name = ci.getName();
165         if(name.startsWith("//")) {
166             name = name.substring("//".length());
167         }
168         int idx = name.indexOf('/');
169         if(idx<0) {
170             throw ci.getFormatException();
171         }
172         databaseName = name.substring(idx + 1);
173         String JavaDoc server = name.substring(0, idx);
174         traceSystem = new TraceSystem(null);
175         try {
176             String JavaDoc traceLevelFile = ci.getProperty(SetTypes.TRACE_LEVEL_FILE, null);
177             if(traceLevelFile != null) {
178                 int level = Integer.parseInt(traceLevelFile);
179                 String JavaDoc prefix = getTraceFilePrefix(databaseName);
180                 String JavaDoc file = FileUtils.createTempFile(prefix, Constants.SUFFIX_TRACE_FILE, false);
181                 traceSystem.setFileName(file);
182                 traceSystem.setLevelFile(level);
183             }
184             String JavaDoc traceLevelSystemOut = ci.getProperty(SetTypes.TRACE_LEVEL_SYSTEM_OUT, null);
185             if(traceLevelSystemOut != null) {
186                 int level = Integer.parseInt(traceLevelSystemOut);
187                 traceSystem.setLevelSystemOut(level);
188             }
189         } catch(Exception JavaDoc e) {
190             throw Message.convert(e);
191         }
192         trace = traceSystem.getTrace(Trace.JDBC);
193         transferList = new ObjectArray();
194         String JavaDoc serverlist = null;
195         if(server.indexOf(',') >= 0) {
196             serverlist = StringUtils.quoteStringSQL(server);
197             ci.setProperty("CLUSTER", serverlist);
198         }
199         cipher = ci.getProperty("CIPHER");
200         if(cipher != null) {
201             fileEncryptionKey = RandomUtils.getSecureBytes(32);
202         }
203         String JavaDoc[] servers = StringUtils.arraySplit(server, ',', true);
204         int len = servers.length;
205         transferList = new ObjectArray();
206         // TODO cluster: support at most 2 connections
207
boolean switchOffCluster = false;
208         for(int i=0; i<len; i++) {
209             try {
210                 Transfer trans = initTransfer(ci, databaseName, servers[i]);
211                 transferList.add(trans);
212             } catch(IOException JavaDoc e) {
213                 switchOffCluster = true;
214             }
215         }
216         checkClosed();
217         if(switchOffCluster) {
218             switchOffCluster();
219         }
220         switchOffAutocommitIfCluster();
221     }
222
223     private void switchOffCluster() throws SQLException JavaDoc {
224         CommandInterface ci = prepareCommand("SET CLUSTER ''");
225         ci.executeUpdate();
226     }
227
228     public void removeServer(int i) throws SQLException JavaDoc {
229         transferList.remove(i);
230         checkClosed();
231         switchOffCluster();
232     }
233
234     public CommandInterface prepareCommand(String JavaDoc sql) throws SQLException JavaDoc {
235         synchronized(this) {
236             checkClosed();
237             return new CommandRemote(this, transferList, sql);
238         }
239     }
240
241     public void checkClosed() throws SQLException JavaDoc {
242         if(isClosed()) {
243             // TODO broken connection: try to reconnect automatically
244
throw Message.getSQLException(Message.CONNECTION_BROKEN);
245         }
246     }
247
248     public void close() {
249         if(transferList != null) {
250             synchronized(this) {
251                 for(int i=0; i<transferList.size(); i++) {
252                     Transfer transfer = (Transfer) transferList.get(i);
253                     try {
254                         traceOperation("SESSION_CLOSE", 0);
255                         transfer.writeInt(SessionRemote.SESSION_CLOSE);
256                         done(transfer);
257                         transfer.close();
258                     } catch(Exception JavaDoc e) {
259                         trace.error("close", e);
260                     }
261                 }
262             }
263             transferList = null;
264         }
265         traceSystem.close();
266     }
267
268     public Trace getTrace() {
269         return traceSystem.getTrace(Trace.JDBC);
270     }
271
272     public int getNextId() {
273         return nextId++;
274     }
275
276     public int getCurrentId() {
277         return nextId;
278     }
279
280     public void done(Transfer transfer) throws SQLException JavaDoc, IOException JavaDoc {
281         transfer.flush();
282         int status = transfer.readInt();
283         if (status == STATUS_ERROR) {
284             String JavaDoc sqlstate = transfer.readString();
285             String JavaDoc message = transfer.readString();
286             int errorCode = transfer.readInt();
287             String JavaDoc trace = transfer.readString();
288             message = message + "\n" + trace;
289             throw new JdbcSQLException(message, sqlstate, errorCode, null);
290         } else if(status == STATUS_CLOSED) {
291             transferList = null;
292         }
293     }
294
295     public boolean isClustered() {
296         return transferList.size() > 1;
297     }
298
299     public boolean isClosed() {
300         return transferList == null || transferList.size() == 0;
301     }
302
303     public void traceOperation(String JavaDoc operation, int id) {
304         if(trace.debug()) {
305             trace.debug(operation + " " + id);
306         }
307     }
308
309     public int allocateObjectId(boolean needFresh, boolean dataFile) {
310         return objectId++;
311     }
312
313     public void checkPowerOff() throws SQLException JavaDoc {
314     }
315
316     public void checkWritingAllowed() throws SQLException JavaDoc {
317     }
318
319     public int compareTypeSave(Value a, Value b) throws SQLException JavaDoc {
320         throw Message.getInternalError();
321     }
322
323     public String JavaDoc createTempFile() throws SQLException JavaDoc {
324         try {
325             return FileUtils.createTempFile(databaseName, Constants.SUFFIX_TEMP_FILE, true);
326         } catch (IOException JavaDoc e) {
327             throw Message.convert(e);
328         }
329     }
330
331     public void freeUpDiskSpace() throws SQLException JavaDoc {
332     }
333
334     public int getChecksum(byte[] data, int start, int end) {
335         return 0;
336     }
337
338     public String JavaDoc getDatabasePath() {
339         return "";
340     }
341
342     public String JavaDoc getLobCompressionAlgorithm(int type) {
343         return null;
344     }
345
346     public int getMaxLengthInplaceLob() {
347         return Constants.DEFAULT_MAX_LENGTH_CLIENTSIDE_LOB;
348     }
349
350     public boolean getTextStorage() {
351         return false;
352     }
353
354     public void handleInvalidChecksum() throws SQLException JavaDoc {
355         throw Message.getSQLException(Message.FILE_CORRUPTED_1, "wrong checksum");
356     }
357
358     public FileStore openFile(String JavaDoc name, boolean mustExist) throws SQLException JavaDoc {
359         if(mustExist && !FileUtils.exists(name)) {
360             throw Message.getSQLException(Message.FILE_CORRUPTED_1, name);
361         }
362         FileStore store;
363         byte[] magic = Constants.MAGIC_FILE_HEADER.getBytes();
364         if(cipher == null) {
365             store = FileStore.open(this, name, magic);
366         } else {
367             store = FileStore.open(this, name, magic, cipher, fileEncryptionKey, 0);
368         }
369         try {
370             store.init();
371         } catch(SQLException JavaDoc e) {
372             store.closeSilently();
373             throw e;
374         }
375         return store;
376     }
377
378     public DataHandler getDataHandler() {
379         return this;
380     }
381
382 }
383
Popular Tags