KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > virtualdatabase > VirtualDatabaseWorkerThread


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2005 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): Nicolas Modrzyk, Jean-Bernard van Zuylen.
23  * Refactored by Marc Herbert to remove the use of Java serialization.
24  */

25
26 package org.objectweb.cjdbc.controller.virtualdatabase;
27
28 import java.io.EOFException JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.net.SocketException JavaDoc;
31 import java.sql.SQLException JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.Iterator JavaDoc;
35
36 import org.objectweb.cjdbc.common.exceptions.NoMoreBackendException;
37 import org.objectweb.cjdbc.common.exceptions.NoMoreControllerException;
38 import org.objectweb.cjdbc.common.exceptions.NotImplementedException;
39 import org.objectweb.cjdbc.common.exceptions.driver.protocol.BackendDriverException;
40 import org.objectweb.cjdbc.common.exceptions.driver.protocol.ControllerCoreException;
41 import org.objectweb.cjdbc.common.log.Trace;
42 import org.objectweb.cjdbc.common.sql.AbstractRequest;
43 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
44 import org.objectweb.cjdbc.common.sql.AlterRequest;
45 import org.objectweb.cjdbc.common.sql.CreateRequest;
46 import org.objectweb.cjdbc.common.sql.DeleteRequest;
47 import org.objectweb.cjdbc.common.sql.DropRequest;
48 import org.objectweb.cjdbc.common.sql.InsertRequest;
49 import org.objectweb.cjdbc.common.sql.ParsingGranularities;
50 import org.objectweb.cjdbc.common.sql.RequestType;
51 import org.objectweb.cjdbc.common.sql.SelectRequest;
52 import org.objectweb.cjdbc.common.sql.StoredProcedure;
53 import org.objectweb.cjdbc.common.sql.UpdateRequest;
54 import org.objectweb.cjdbc.common.sql.metadata.MetadataContainer;
55 import org.objectweb.cjdbc.common.sql.metadata.MetadataDescription;
56 import org.objectweb.cjdbc.common.stream.CJDBCInputStream;
57 import org.objectweb.cjdbc.common.stream.CJDBCOutputStream;
58 import org.objectweb.cjdbc.common.users.VirtualDatabaseUser;
59 import org.objectweb.cjdbc.common.util.Constants;
60 import org.objectweb.cjdbc.controller.core.Controller;
61 import org.objectweb.cjdbc.driver.Connection;
62 import org.objectweb.cjdbc.driver.DriverResultSet;
63 import org.objectweb.cjdbc.driver.protocol.Commands;
64 import org.objectweb.cjdbc.driver.protocol.SQLDataSerialization;
65 import org.objectweb.cjdbc.driver.protocol.TypeTag;
66
67 /**
68  * This class handles a connection with a C-JDBC driver.
69  *
70  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
71  * @author <a HREF="mailto:Nicolas.Modrzyk@inria.fr">Nicolas Modrzyk </a>
72  * @author <a HREF="mailto:Marc.Herbert@emicnetworks.com">Marc Herbert </a>
73  * @author <a HREF="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
74  * </a>
75  * @version 2.0
76  */

77 public class VirtualDatabaseWorkerThread extends Thread JavaDoc
78 {
79   //
80
// How the code is organized?
81
//
82
// 1. Member variables
83
// 2. Constructor(s)
84
// 3. Request management
85
// 4. Getter/Setters
86

87   /** <code>true</code> ifthis has been killed. */
88   private boolean isKilled = false;
89
90   /** Do we require the templates of PreparedStatements? Needed for parsing */
91   boolean needSkeleton = false;
92
93   /** Virtual database instantiating this thread. */
94   private VirtualDatabase vdb;
95
96   /** Logger instance. */
97   private Trace logger = null;
98
99   private CJDBCInputStream in = null;
100   private CJDBCOutputStream out = null;
101
102   private VirtualDatabaseUser user;
103
104   private Controller controller;
105
106   private boolean waitForCommand;
107
108   private HashMap JavaDoc streamedResultSet;
109
110   /**
111    * The following variables represent the state of the connection with the
112    * client
113    */

114   private long currentTid;
115   private boolean transactionStarted;
116   private boolean queryExecutedInThisTransaction;
117   private boolean writeQueryExecutedInThisTransaction;
118   private String JavaDoc login;
119   private boolean closed;
120   private int transactionIsolation = Connection.DEFAULT_TRANSACTION_ISOLATION_LEVEL;
121
122   /*
123    * Constructor
124    */

125
126   /**
127    * Creates a new <code>VirtualDatabaseWorkerThread</code> instance.
128    *
129    * @param controller the thread was originated from
130    * @param vdb the virtual database instantiating this thread.
131    */

132   public VirtualDatabaseWorkerThread(Controller controller, VirtualDatabase vdb)
133   {
134     super("VirtualDatabaseWorkerThread-" + vdb.getVirtualDatabaseName());
135     this.vdb = vdb;
136     this.controller = controller;
137     try
138     {
139       this.logger = Trace
140           .getLogger("org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabaseWorkerThread."
141               + vdb.getVirtualDatabaseName());
142     }
143     catch (Exception JavaDoc e)
144     {
145       this.logger = vdb.logger;
146     }
147   }
148
149   //
150
// Decoding commands from the stream
151
//
152

153   /**
154    * Read a write request send by the <code>Connection</code> object. Only the
155    * needed parameters are sent, so we can reconstruct the object on the
156    * controller side, without serializing everything.
157    *
158    * @return an instance of the <code>AbstractWriteRequest</code>
159    * @see AbstractRequest#AbstractRequest(CJDBCInputStream, int)
160    */

161   private AbstractWriteRequest decodeWriteRequestFromStream()
162       throws IOException JavaDoc
163   {
164     AbstractWriteRequest writeRequest;
165     int requestType = in.readInt();
166
167     switch (requestType)
168     {
169       case RequestType.CREATE :
170         writeRequest = new CreateRequest(in);
171         break;
172       case RequestType.ALTER :
173         writeRequest = new AlterRequest(in);
174         break;
175       case RequestType.DELETE :
176         writeRequest = new DeleteRequest(in);
177         break;
178       case RequestType.DROP :
179         writeRequest = new DropRequest(in);
180         break;
181       case RequestType.INSERT :
182         writeRequest = new InsertRequest(in);
183         break;
184       case RequestType.UPDATE :
185         writeRequest = new UpdateRequest(in);
186         break;
187       default :
188         // TODO should this really be an IOException ?
189
throw new IOException JavaDoc("Invalid Write Query Type");
190     }
191     return writeRequest;
192   }
193
194   /**
195    * Set the login and transaction id on the given request. If the request is
196    * autocommit and a transaction was started, the transaction is first commited
197    * to return in autocommit mode.
198    *
199    * @param request The request to set
200    * @param login user login to set
201    * @param tid the transaction id to set
202    * @return new value of transaction started
203    */

204   private boolean setRequestParameters(AbstractRequest request, String JavaDoc login,
205       long tid, boolean transactionStarted) throws SQLException JavaDoc
206   {
207     request.setLogin(login);
208     request.setTransactionIsolation(transactionIsolation);
209     if (request.isAutoCommit() && transactionStarted)
210     {
211       vdb.commit(tid, writeQueryExecutedInThisTransaction);
212       return false;
213     }
214     else
215       request.setTransactionId(tid);
216     return transactionStarted;
217   }
218
219   /**
220    * Keep a reference to both ResultSets, but garbage collect data already sent.
221    */

222   private void putStreamingReferences(ControllerResultSet crs,
223       DriverResultSet drs)
224   {
225     drs.setData(null);
226     crs.driverResultSet = drs;
227     streamedResultSet.put(crs.getCursorName(), crs);
228   }
229
230   /**
231    * Gets a connection from the connection queue and process it.
232    */

233   public void run()
234   {
235     ArrayList JavaDoc vdbActiveThreads = vdb.getActiveThreads();
236     ArrayList JavaDoc vdbPendingQueue = vdb.getPendingConnections();
237     // List of open ResultSets for streaming. This is not synchronized since the
238
// connection does only handle one request at a time
239
streamedResultSet = new HashMap JavaDoc();
240     boolean isActive = true;
241
242     if (vdbActiveThreads == null)
243     {
244       logger
245           .error("Got null active threads queue in VirtualDatabaseWorkerThread");
246       isKilled = true;
247     }
248     if (vdbPendingQueue == null)
249     {
250       logger.error("Got null connection queue in VirtualDatabaseWorkerThread");
251       isKilled = true;
252     }
253
254     // Main loop
255
while (!isKilled)
256     {
257       // Get a connection from the pending queue
258
synchronized (vdbPendingQueue)
259       {
260         while (vdbPendingQueue.isEmpty())
261         {
262           if (!vdb.poolConnectionThreads)
263           { // User does not want thread pooling, kill this thread!
264
isKilled = true;
265             break;
266           }
267           boolean timeout = false;
268           try
269           {
270             if (isActive)
271             {
272               isActive = false;
273               // Remove ourselves from the active thread list
274
synchronized (vdbActiveThreads)
275               {
276                 vdbActiveThreads.remove(this);
277                 vdb.addIdleThread();
278               }
279             }
280             long before = System.currentTimeMillis();
281             vdbPendingQueue.wait(vdb.getMaxThreadIdleTime());
282             long now = System.currentTimeMillis();
283             // Check if timeout has expired
284
timeout = now - before >= vdb.getMaxThreadIdleTime();
285           }
286           catch (InterruptedException JavaDoc e)
287           {
288             logger.warn("VirtualDatabaseWorkerThread wait() interrupted");
289           }
290           if (timeout && vdbPendingQueue.isEmpty())
291           {
292             if (vdb.currentNbOfThreads > vdb.minNbOfThreads)
293             { // We have enough threads, kill this one
294
isKilled = true;
295               break;
296             }
297           }
298         }
299
300         if (isKilled)
301         { // Cleaning up
302
synchronized (vdbActiveThreads)
303           { // Remove ourselves from the appropriate thread list
304
if (isActive)
305             {
306               vdbActiveThreads.remove(this);
307               vdb.removeCurrentNbOfThread();
308             }
309             else
310               vdb.removeIdleThread();
311           }
312           // Get out of the while loop
313
continue;
314         }
315
316         // Get a connection
317
try
318         {
319           in = (CJDBCInputStream) vdbPendingQueue.remove(0);
320           out = (CJDBCOutputStream) vdbPendingQueue.remove(0);
321         }
322         catch (Exception JavaDoc e)
323         {
324           logger.error("Error while getting streams from connection");
325           continue;
326         }
327
328         synchronized (vdbActiveThreads)
329         {
330           if (!isActive)
331           {
332             vdb.removeIdleThread();
333             isActive = true;
334             // Add this thread to the active thread list
335
vdbActiveThreads.add(this);
336           }
337         }
338       }
339
340       // Handle connection
341
// Read the user information and check authentication
342
/**
343        * @see org.objectweb.cjdbc.driver.Driver#connectToController(Properties,
344        * CjdbcUrl, ControllerInfo)
345        */

346       boolean success = false;
347       try
348       {
349         login = in.readUTF();
350         String JavaDoc password = in.readUTF();
351         user = new VirtualDatabaseUser(login, password);
352
353         if (vdb.getAuthenticationManager().isValidVirtualUser(user))
354         { // Authentication ok
355
out.writeBoolean(true); // success code
356

357           this.needSkeleton = vdb.getRequestManager()
358               .getRequiredParsingGranularity() != ParsingGranularities.NO_PARSING;
359           // tell the driver if we want the templates of PreparedStatements
360
out.writeBoolean(this.needSkeleton);
361           // tell the driver which blob encoding to use on this controller
362
out.writeUTF(vdb.getBlobFilter().getXml());
363           out.flush();
364           success = true;
365
366           if (logger.isDebugEnabled())
367             logger.debug("Login accepted for " + login);
368         }
369         else
370         { // Authentication failed, close the connection
371
String JavaDoc msg = "Authentication failed for user '" + login + "'";
372           out.writeBoolean(false); // authentication failed
373
out.writeUTF(msg); // error message
374
if (logger.isDebugEnabled())
375             logger.debug(msg);
376           continue;
377         }
378       }
379       catch (IOException JavaDoc e)
380       {
381         logger.error("I/O error during user authentication (" + e + ")");
382         continue;
383       }
384       finally
385       {
386         if (!success)
387         {
388           try
389           {
390             out.close();
391             in.close();
392           }
393           catch (IOException JavaDoc ignore)
394           {
395           }
396         }
397       }
398
399       currentTid = 0;
400       transactionStarted = false;
401       queryExecutedInThisTransaction = false;
402       writeQueryExecutedInThisTransaction = false;
403       closed = false;
404       int command;
405       while (!closed && !isKilled)
406       {
407         try
408         {
409           // Get the query
410
waitForCommand = true;
411           command = in.readInt();
412           waitForCommand = false;
413
414           // Process it
415
switch (command)
416           {
417             case Commands.ExecReadRequest :
418               execReadRequest();
419               break;
420             case Commands.ExecWriteRequest :
421               execWriteRequest();
422               break;
423             case Commands.ExecWriteRequestWithKeys :
424               execWriteRequestWithKeys();
425               break;
426             case Commands.ExecReadStoredProcedure :
427               execReadStoredProcedure();
428               break;
429             case Commands.ExecWriteStoredProcedure :
430               execWriteStoredProcedure();
431               break;
432             case Commands.Begin :
433               begin();
434               break;
435             case Commands.Commit :
436               commit();
437               break;
438             case Commands.SetAutoCommit :
439               setAutoCommit();
440               break;
441             case Commands.Rollback :
442               rollback();
443               break;
444             case Commands.SetNamedSavepoint :
445               setNamedSavepoint();
446               break;
447             case Commands.SetUnnamedSavepoint :
448               setUnnamedSavepoint();
449               break;
450             case Commands.ReleaseSavepoint :
451               releaseSavepoint();
452               break;
453             case Commands.RollbackToSavepoint :
454               rollbackToSavepoint();
455               break;
456             case Commands.SetTransactionIsolation :
457               connectionSetTransactionIsolation();
458               break;
459             case Commands.GetVirtualDatabaseName :
460               getVirtualDatabaseName();
461               break;
462             case Commands.DatabaseMetaDataGetDatabaseProductName :
463               databaseMetaDataGetDatabaseProductName();
464               break;
465             case Commands.GetControllerVersionNumber :
466               getControllerVersionNumber();
467               break;
468             case Commands.DatabaseMetaDataGetTables :
469               databaseMetaDataGetTables();
470               break;
471             case Commands.DatabaseMetaDataGetColumns :
472               databaseMetaDataGetColumns();
473               break;
474             case Commands.DatabaseMetaDataGetPrimaryKeys :
475               databaseMetaDataGetPrimaryKeys();
476               break;
477             case Commands.DatabaseMetaDataGetProcedures :
478               databaseMetaDataGetProcedures();
479               break;
480             case Commands.DatabaseMetaDataGetProcedureColumns :
481               databaseMetaDataGetProcedureColumns();
482               break;
483             case Commands.ConnectionGetCatalogs :
484               connectionGetCatalogs();
485               break;
486             case Commands.ConnectionGetCatalog :
487               connectionGetCatalog();
488               break;
489             case Commands.DatabaseMetaDataGetTableTypes :
490               databaseMetaDataGetTableTypes();
491               break;
492             case Commands.DatabaseMetaDataGetSchemas :
493               databaseMetaDataGetSchemas();
494               break;
495             case Commands.DatabaseMetaDataGetTablePrivileges :
496               databaseMetaDataGetTablePrivileges();
497               break;
498             case Commands.DatabaseMetaDataGetAttributes :
499               databaseMetaDataGetAttributes();
500               break;
501             case Commands.DatabaseMetaDataGetBestRowIdentifier :
502               databaseMetaDataGetBestRowIdentifier();
503               break;
504             case Commands.DatabaseMetaDataGetColumnPrivileges :
505               databaseMetaDataGetColumnPrivileges();
506               break;
507             case Commands.DatabaseMetaDataGetCrossReference :
508               databaseMetaDataGetCrossReference();
509               break;
510             case Commands.DatabaseMetaDataGetExportedKeys :
511               databaseMetaDataGetExportedKeys();
512               break;
513             case Commands.DatabaseMetaDataGetImportedKeys :
514               databaseMetaDataGetImportedKeys();
515               break;
516             case Commands.DatabaseMetaDataGetIndexInfo :
517               databaseMetaDataGetIndexInfo();
518               break;
519             case Commands.DatabaseMetaDataGetSuperTables :
520               databaseMetaDataGetSuperTables();
521               break;
522             case Commands.DatabaseMetaDataGetSuperTypes :
523               databaseMetaDataGetSuperTypes();
524               break;
525             case Commands.DatabaseMetaDataGetTypeInfo :
526               databaseMetaDataGetTypeInfo();
527               break;
528             case Commands.DatabaseMetaDataGetUDTs :
529               databaseMetaDataGetUDTs();
530               break;
531             case Commands.DatabaseMetaDataGetVersionColumns :
532               databaseMetaDataGetVersionColumns();
533               break;
534             case Commands.ConnectionSetCatalog :
535               connectionSetCatalog();
536               break;
537             case Commands.Close :
538               close();
539               break;
540             case Commands.Reset :
541               reset();
542               break;
543             case Commands.FetchNextResultSetRows :
544               fetchNextResultSetRows();
545               break;
546             case Commands.CloseRemoteResultSet :
547               closeRemoteResultSet();
548               break;
549             case Commands.DatabaseStaticMetadata :
550               databaseStaticMetadata();
551               break;
552             case Commands.RestoreConnectionState :
553               restoreConnectionState();
554               break;
555             default :
556               String JavaDoc errorMsg = "Unsupported protocol command: " + command;
557               logger.error(errorMsg);
558               sendToDriver(new RuntimeException JavaDoc(errorMsg));
559               out.flush();
560               break;
561           }
562         }
563         catch (EOFException JavaDoc e)
564         {
565           logger.warn("Client (login:" + login + ",host:"
566               + in.getSocket().getInetAddress().getHostName()
567               + " closed connection with server");
568           closed = true;
569         }
570         catch (SocketException JavaDoc e)
571         {
572           // shutting down
573
closed = true;
574         }
575         catch (IOException JavaDoc e)
576         {
577           closed = true;
578           logger.warn("Closing connection with client " + login
579               + " because of IOException.(" + e + ")");
580         }
581         catch (SQLException JavaDoc e)
582         {
583           logger
584               .warn("Error during command execution (" + e.getMessage() + ")");
585           try
586           {
587             sendToDriver(e);
588             out.flush();
589           }
590           catch (IOException JavaDoc ignore)
591           {
592           }
593         }
594         catch (RuntimeException JavaDoc e)
595         {
596           logger.warn("Runtime error during command execution ("
597               + e.getMessage() + ")", e);
598           try
599           {
600             sendToDriver(new SQLException JavaDoc(e.getMessage()));
601             out.flush();
602           }
603           catch (IOException JavaDoc ignore)
604           {
605           }
606         }
607       } // while (!closed && !isKilled) get and process command from driver
608

609       // Do the cleanup
610
if (transactionStarted)
611       {
612         if (logger.isDebugEnabled())
613           logger.debug("Forcing transaction " + currentTid + " rollback");
614         try
615         {
616           vdb.rollback(currentTid, writeQueryExecutedInThisTransaction);
617         }
618         catch (Exception JavaDoc e)
619         {
620           if (logger.isDebugEnabled())
621             logger.debug("Error during rollback of transaction " + currentTid
622                 + "(" + e + ")");
623         }
624       }
625       if (!streamedResultSet.isEmpty())
626       {
627         for (Iterator JavaDoc iter = streamedResultSet.values().iterator(); iter
628             .hasNext();)
629         {
630           ControllerResultSet crs = (ControllerResultSet) iter.next();
631           crs.closeResultSet();
632         }
633         streamedResultSet.clear();
634       }
635       try
636       {
637         in.close();
638       }
639       catch (IOException JavaDoc ignore)
640       {
641       }
642       try
643       {
644         out.close();
645       }
646       catch (IOException JavaDoc ignore)
647       {
648       }
649     }
650
651     if (logger.isDebugEnabled())
652       logger.debug("VirtualDatabaseWorkerThread associated to login: "
653           + this.getUser() + " terminating.");
654   }
655
656   //
657
// Connection management
658
//
659

660   private void close() throws IOException JavaDoc
661   {
662     if (logger.isDebugEnabled())
663       logger.debug("Close command");
664     sendToDriver(true);
665
666     closed = true;
667   }
668
669   private void closeRemoteResultSet() throws IOException JavaDoc
670   {
671     if (logger.isDebugEnabled())
672       logger.debug("CloseRemoteResultSet command");
673
674     String JavaDoc cursor = in.readUTF();
675     ControllerResultSet crsToClose = (ControllerResultSet) streamedResultSet
676         .remove(cursor);
677     if (crsToClose == null)
678     {
679       sendToDriver(new SQLException JavaDoc("No valid RemoteResultSet to close."));
680     }
681     else
682     {
683       crsToClose.closeResultSet();
684       sendToDriver(true);
685
686     }
687   }
688
689   private void reset()
690   {
691     // The client application has closed the connection but it is kept
692
// open in case the transparent connection pooling reuses it.
693
if (logger.isDebugEnabled())
694       logger.debug("Reset command");
695
696     // Do the cleanup
697
if (transactionStarted)
698     {
699       if (queryExecutedInThisTransaction)
700       { // Force rollback of this transaction
701
if (logger.isDebugEnabled())
702           logger.debug("Forcing transaction " + currentTid + " rollback");
703         try
704         {
705           vdb.rollback(currentTid, writeQueryExecutedInThisTransaction);
706         }
707         catch (Exception JavaDoc e)
708         {
709           if (logger.isDebugEnabled())
710             logger.debug("Error during rollback of transaction " + currentTid
711                 + "(" + e + ")");
712         }
713       }
714       else
715       { // We need to abort the begin to cleanup the metadata
716
// associated with the started transaction.
717
if (logger.isDebugEnabled())
718           logger.debug("Aborting transaction " + currentTid);
719         try
720         {
721           vdb.abort(currentTid, writeQueryExecutedInThisTransaction);
722         }
723         catch (Exception JavaDoc e)
724         {
725           if (logger.isDebugEnabled())
726             logger.debug("Error while aborting transaction " + currentTid + "("
727                 + e + ")", e);
728         }
729       }
730       currentTid = 0;
731       transactionStarted = false;
732     }
733   }
734
735   private void restoreConnectionState() throws IOException JavaDoc
736   {
737     if (logger.isDebugEnabled())
738       logger.debug("RestoreConnectionState command");
739     // We receive autocommit from driver
740
transactionStarted = !in.readBoolean();
741     if (transactionStarted)
742       currentTid = in.readLong();
743   }
744
745   //
746
// Catalog
747
//
748

749   private void connectionSetCatalog() throws IOException JavaDoc
750   {
751     // Warning! This could bypass the security checkings based on client IP
752
// address. If a user has access to a virtual database, through setCatalog()
753
// is will be able to access all other virtual databases where his
754
// login/password is valid regardless of the IP filtering settings.
755
if (logger.isDebugEnabled())
756       logger.debug("ConnectionSetCatalog command");
757     String JavaDoc catalog = in.readUTF();
758     boolean change = controller.hasVirtualDatabase(catalog);
759     if (change)
760     {
761       VirtualDatabase tempvdb = controller.getVirtualDatabase(catalog);
762       if (!tempvdb.getAuthenticationManager().isValidVirtualUser(user))
763         sendToDriver(new SQLException JavaDoc(
764             "User authentication has failed for asked catalog. No change"));
765       else
766       {
767         this.vdb = tempvdb;
768         sendToDriver(true);
769       }
770     }
771     else
772       sendToDriver(false);
773
774   }
775
776   private void connectionGetCatalog() throws IOException JavaDoc
777   {
778     if (logger.isDebugEnabled())
779       logger.debug("ConnectionGetCatalog command");
780
781     sendToDriver(vdb.getVirtualDatabaseName());
782   }
783
784   private void connectionGetCatalogs() throws IOException JavaDoc
785   {
786     if (logger.isDebugEnabled())
787       logger.debug("ConnectionGetCatalogs command");
788     ArrayList JavaDoc list = controller.getVirtualDatabaseNames();
789     sendToDriver(vdb.getDynamicMetaData().getCatalogs(list));
790   }
791
792   private void connectionSetTransactionIsolation() throws IOException JavaDoc
793   {
794     int level = in.readInt();
795     if (logger.isDebugEnabled())
796       logger.debug("SetTransactionIsolation command (level=" + level + ")");
797
798     // Check that we are not in a running transaction
799
if (transactionStarted && queryExecutedInThisTransaction)
800     {
801       sendToDriver(new SQLException JavaDoc(
802           "Cannot change the transaction isolation in a running transaction"));
803       out.flush();
804       return;
805     }
806
807     MetadataContainer metadataContainer = vdb.getStaticMetaData()
808         .getMetadataContainer();
809     if (metadataContainer != null)
810     {
811       Object JavaDoc value = metadataContainer.get(MetadataContainer.getContainerKey(
812           MetadataDescription.SUPPORTS_TRANSACTION_ISOLATION_LEVEL,
813           new Class JavaDoc[]{Integer.TYPE}, new Object JavaDoc[]{new Integer JavaDoc(level)}));
814
815       if (value != null)
816       {
817         if (!((Boolean JavaDoc) value).booleanValue())
818         {
819           sendToDriver(new SQLException JavaDoc("Transaction isolation level " + level
820               + " is not supported by the database"));
821           out.flush();
822           return;
823         }
824       }
825       else
826         logger.warn("Unable to check validity of transaction isolation level "
827             + level);
828     }
829     else
830       logger.warn("Unable to check validity of transaction isolation level "
831           + level);
832     transactionIsolation = level;
833     sendToDriver(true);
834   }
835
836   //
837
// Database MetaData
838
//
839

840   /**
841    * @see java.sql.DatabaseMetaData#getAttributes(java.lang.String,
842    * java.lang.String, java.lang.String, java.lang.String)
843    */

844   private void databaseMetaDataGetAttributes() throws IOException JavaDoc
845   {
846     if (logger.isDebugEnabled())
847       logger.debug("DatabaseMetaDataGetAttributes command");
848     String JavaDoc catalog = in.readUTF();
849     String JavaDoc schemaPattern = in.readUTF();
850     String JavaDoc typeNamePattern = in.readUTF();
851     String JavaDoc attributeNamePattern = in.readUTF();
852
853     try
854     {
855       sendToDriver(vdb.getDynamicMetaData().getAttributes(login, catalog,
856           schemaPattern, typeNamePattern, attributeNamePattern));
857     }
858     catch (SQLException JavaDoc e)
859     {
860       if (logger.isWarnEnabled())
861         logger.warn("Error while calling databaseMetaDataGetAttributes", e);
862       sendToDriver(e);
863     }
864   }
865
866   /**
867    * @see java.sql.DatabaseMetaData#getBestRowIdentifier(java.lang.String,
868    * java.lang.String, java.lang.String, int, boolean)
869    */

870   private void databaseMetaDataGetBestRowIdentifier() throws IOException JavaDoc
871   {
872     if (logger.isDebugEnabled())
873       logger.debug("DatabaseMetaDataGetBestRowIdentifier command");
874
875     String JavaDoc catalog = in.readUTF();
876     String JavaDoc schema = in.readUTF();
877     String JavaDoc table = in.readUTF();
878     int scope = in.readInt();
879     boolean nullable = in.readBoolean();
880
881     try
882     {
883       sendToDriver(vdb.getDynamicMetaData().getBestRowIdentifier(login,
884           catalog, schema, table, scope, nullable));
885     }
886     catch (SQLException JavaDoc e)
887     {
888       if (logger.isWarnEnabled())
889         logger.warn("Error while calling databaseMetaDataGetBestRowIdentifier",
890             e);
891       sendToDriver(e);
892     }
893   }
894
895   /**
896    * @see java.sql.DatabaseMetaData#getColumnPrivileges(java.lang.String,
897    * java.lang.String, java.lang.String, java.lang.String)
898    */

899   private void databaseMetaDataGetColumnPrivileges() throws IOException JavaDoc
900   {
901     if (logger.isDebugEnabled())
902       logger.debug("DatabaseMetaDataGetColumnPrivileges command");
903
904     String JavaDoc catalog = in.readUTF();
905     String JavaDoc schema = in.readUTF();
906     String JavaDoc table = in.readUTF();
907     String JavaDoc columnNamePattern = in.readUTF();
908
909     try
910     {
911       sendToDriver(vdb.getDynamicMetaData().getColumnPrivileges(login, catalog,
912           schema, table, columnNamePattern));
913     }
914     catch (SQLException JavaDoc e)
915     {
916       if (logger.isWarnEnabled())
917         logger.warn("Error while calling databaseMetaDataGetColumnPrivileges",
918             e);
919       sendToDriver(e);
920     }
921   }
922
923   /**
924    * @see java.sql.DatabaseMetaData#getColumns(java.lang.String,
925    * java.lang.String, java.lang.String, java.lang.String)
926    */

927   private void databaseMetaDataGetColumns() throws IOException JavaDoc
928   {
929     if (logger.isDebugEnabled())
930       logger.debug("DatabaseMetaDataGetColumns command");
931     String JavaDoc ccatalog = in.readUTF();
932     String JavaDoc cschemaPattern = in.readUTF();
933     String JavaDoc ctableNamePattern = in.readUTF();
934     String JavaDoc ccolumnNamePattern = in.readUTF();
935
936     try
937     {
938       sendToDriver(vdb.getDynamicMetaData().getColumns(login, ccatalog,
939           cschemaPattern, ctableNamePattern, ccolumnNamePattern));
940     }
941     catch (SQLException JavaDoc e)
942     {
943       if (logger.isWarnEnabled())
944         logger.warn("Error while calling databaseMetaDataGetColumns", e);
945       sendToDriver(e);
946     }
947   }
948
949   /**
950    * @see java.sql.DatabaseMetaData#getCrossReference(java.lang.String,
951    * java.lang.String, java.lang.String, java.lang.String,
952    * java.lang.String, java.lang.String)
953    */

954   private void databaseMetaDataGetCrossReference() throws IOException JavaDoc
955   {
956     if (logger.isDebugEnabled())
957       logger.debug("DatabaseMetaDataGetCrossReference command");
958
959     String JavaDoc primaryCatalog = in.readUTF();
960     String JavaDoc primarySchema = in.readUTF();
961     String JavaDoc primaryTable = in.readUTF();
962     String JavaDoc foreignCatalog = in.readUTF();
963     String JavaDoc foreignSchema = in.readUTF();
964     String JavaDoc foreignTable = in.readUTF();
965
966     try
967     {
968       sendToDriver(vdb.getDynamicMetaData().getCrossReference(login,
969           primaryCatalog, primarySchema, primaryTable, foreignCatalog,
970           foreignSchema, foreignTable));
971     }
972     catch (SQLException JavaDoc e)
973     {
974       if (logger.isWarnEnabled())
975         logger.warn("Error while calling databaseMetaDataGetCrossReference", e);
976       sendToDriver(e);
977     }
978   }
979
980   /**
981    * @see java.sql.DatabaseMetaData#getDatabaseProductName()
982    */

983   private void databaseMetaDataGetDatabaseProductName() throws IOException JavaDoc
984   {
985     if (logger.isDebugEnabled())
986       logger.debug("GetDatabaseProductName command");
987
988     sendToDriver(vdb.getDatabaseProductName());
989   }
990
991   /**
992    * @see java.sql.DatabaseMetaData#getExportedKeys(java.lang.String,
993    * java.lang.String, java.lang.String)
994    */

995   private void databaseMetaDataGetExportedKeys() throws IOException JavaDoc
996   {
997     if (logger.isDebugEnabled())
998       logger.debug("DatabaseMetaDataGetExportedKeys command");
999
1000    String JavaDoc catalog = in.readUTF();
1001    String JavaDoc schema = in.readUTF();
1002    String JavaDoc table = in.readUTF();
1003
1004    try
1005    {
1006      sendToDriver(vdb.getDynamicMetaData().getExportedKeys(login, catalog,
1007          schema, table));
1008    }
1009    catch (SQLException JavaDoc e)
1010    {
1011      if (logger.isWarnEnabled())
1012        logger.warn("Error while calling databaseMetaDataGetExportedKeys", e);
1013      sendToDriver(e);
1014    }
1015  }
1016
1017  /**
1018   * @see java.sql.DatabaseMetaData#getImportedKeys(java.lang.String,
1019   * java.lang.String, java.lang.String)
1020   */

1021  private void databaseMetaDataGetImportedKeys() throws IOException JavaDoc
1022  {
1023    if (logger.isDebugEnabled())
1024      logger.debug("DatabaseMetaDataGetImportedKeys command");
1025
1026    String JavaDoc catalog = in.readUTF();
1027    String JavaDoc schema = in.readUTF();
1028    String JavaDoc table = in.readUTF();
1029
1030    try
1031    {
1032      sendToDriver(vdb.getDynamicMetaData().getImportedKeys(login, catalog,
1033          schema, table));
1034    }
1035    catch (SQLException JavaDoc e)
1036    {
1037      if (logger.isWarnEnabled())
1038        logger.warn("Error while calling databaseMetaDataGetImportedKeys", e);
1039      sendToDriver(e);
1040    }
1041  }
1042
1043  /**
1044   * @see java.sql.DatabaseMetaData#getIndexInfo(java.lang.String,
1045   * java.lang.String, java.lang.String, boolean, boolean)
1046   */

1047  private void databaseMetaDataGetIndexInfo() throws IOException JavaDoc
1048  {
1049    if (logger.isDebugEnabled())
1050      logger.debug("databaseMetaDataGetIndexInfo command");
1051
1052    String JavaDoc catalog = in.readUTF();
1053    String JavaDoc schema = in.readUTF();
1054    String JavaDoc table = in.readUTF();
1055    boolean unique = in.readBoolean();
1056    boolean approximate = in.readBoolean();
1057
1058    try
1059    {
1060      sendToDriver(vdb.getDynamicMetaData().getIndexInfo(login, catalog,
1061          schema, table, unique, approximate));
1062    }
1063    catch (SQLException JavaDoc e)
1064    {
1065      if (logger.isWarnEnabled())
1066        logger.warn("Error while calling databaseMetaDataGetIndexInfo", e);
1067      sendToDriver(e);
1068    }
1069  }
1070
1071  /**
1072   * @see java.sql.DatabaseMetaData#getPrimaryKeys(java.lang.String,
1073   * java.lang.String, java.lang.String)
1074   */

1075  private void databaseMetaDataGetPrimaryKeys() throws IOException JavaDoc
1076  {
1077    if (logger.isDebugEnabled())
1078      logger.debug("DatabaseMetaDataGetPrimaryKeys command");
1079
1080    String JavaDoc pcatalog = in.readUTF();
1081    String JavaDoc pschemaPattern = in.readUTF();
1082    String JavaDoc ptableNamePattern = in.readUTF();
1083
1084    try
1085    {
1086      sendToDriver(vdb.getDynamicMetaData().getPrimaryKeys(login, pcatalog,
1087          pschemaPattern, ptableNamePattern));
1088    }
1089    catch (SQLException JavaDoc e)
1090    {
1091      if (logger.isWarnEnabled())
1092        logger.warn("Error while calling databaseMetaDataGetPrimaryKeys", e);
1093      sendToDriver(e);
1094    }
1095  }
1096
1097  /**
1098   * @see java.sql.DatabaseMetaData#getProcedureColumns(java.lang.String,
1099   * java.lang.String, java.lang.String, java.lang.String)
1100   */

1101  private void databaseMetaDataGetProcedureColumns() throws IOException JavaDoc
1102  {
1103    if (logger.isDebugEnabled())
1104      logger.debug("DatabaseMetaDataGetProcedureColumns command");
1105
1106    String JavaDoc pccatalog = in.readUTF();
1107    String JavaDoc pcschemaPattern = in.readUTF();
1108    String JavaDoc pcprocedureNamePattern = in.readUTF();
1109    String JavaDoc pccolumnNamePattern = in.readUTF();
1110
1111    try
1112    {
1113      sendToDriver(vdb.getDynamicMetaData().getProcedureColumns(login,
1114          pccatalog, pcschemaPattern, pcprocedureNamePattern,
1115          pccolumnNamePattern));
1116    }
1117    catch (SQLException JavaDoc e)
1118    {
1119      if (logger.isWarnEnabled())
1120        logger.warn("Error while calling databaseMetaDataGetProcedureColumns",
1121            e);
1122      sendToDriver(e);
1123    }
1124  }
1125
1126  /**
1127   * @see java.sql.DatabaseMetaData#getProcedures(java.lang.String,
1128   * java.lang.String, java.lang.String)
1129   */

1130  private void databaseMetaDataGetProcedures() throws IOException JavaDoc
1131  {
1132    if (logger.isDebugEnabled())
1133      logger.debug("DatabaseMetaDataGetProcedures command");
1134
1135    String JavaDoc rcatalog = in.readUTF();
1136    String JavaDoc rschemaPattern = in.readUTF();
1137    String JavaDoc procedureNamePattern = in.readUTF();
1138
1139    try
1140    {
1141      sendToDriver(vdb.getDynamicMetaData().getProcedures(login, rcatalog,
1142          rschemaPattern, procedureNamePattern));
1143    }
1144    catch (SQLException JavaDoc e)
1145    {
1146      if (logger.isWarnEnabled())
1147        logger.warn("Error while calling databaseMetaDataGetProcedures", e);
1148      sendToDriver(e);
1149    }
1150  }
1151
1152  /**
1153   * @see java.sql.DatabaseMetaData#getSchemas()
1154   */

1155  private void databaseMetaDataGetSchemas() throws IOException JavaDoc
1156  {
1157    if (logger.isDebugEnabled())
1158      logger.debug("DatabaseMetaDataGetSchemas Types command");
1159
1160    try
1161    {
1162      sendToDriver(vdb.getDynamicMetaData().getSchemas(login));
1163    }
1164    catch (SQLException JavaDoc e)
1165    {
1166      if (logger.isWarnEnabled())
1167        logger.warn("Error while calling databaseMetaDataGetSchemas", e);
1168      sendToDriver(e);
1169    }
1170  }
1171
1172  /**
1173   * @see java.sql.DatabaseMetaData#getSuperTables(java.lang.String,
1174   * java.lang.String, java.lang.String)
1175   */

1176  private void databaseMetaDataGetSuperTables() throws IOException JavaDoc
1177  {
1178    if (logger.isDebugEnabled())
1179      logger.debug("DatabaseMetaDataGetSuperTables command");
1180
1181    String JavaDoc catalog = in.readUTF();
1182    String JavaDoc schemaPattern = in.readUTF();
1183    String JavaDoc tableNamePattern = in.readUTF();
1184
1185    try
1186    {
1187      sendToDriver(vdb.getDynamicMetaData().getSuperTables(login, catalog,
1188          schemaPattern, tableNamePattern));
1189    }
1190    catch (SQLException JavaDoc e)
1191    {
1192      if (logger.isWarnEnabled())
1193        logger.warn("Error while calling databaseMetaDataGetSuperTables", e);
1194      sendToDriver(e);
1195    }
1196  }
1197
1198  /**
1199   * @see java.sql.DatabaseMetaData#getSuperTypes(java.lang.String,
1200   * java.lang.String, java.lang.String)
1201   */

1202  private void databaseMetaDataGetSuperTypes() throws IOException JavaDoc
1203  {
1204    if (logger.isDebugEnabled())
1205      logger.debug("DatabaseMetaDataGetSuperTables command");
1206
1207    String JavaDoc catalog = in.readUTF();
1208    String JavaDoc schemaPattern = in.readUTF();
1209    String JavaDoc tableNamePattern = in.readUTF();
1210
1211    try
1212    {
1213      sendToDriver(vdb.getDynamicMetaData().getSuperTypes(login, catalog,
1214          schemaPattern, tableNamePattern));
1215    }
1216    catch (SQLException JavaDoc e)
1217    {
1218      if (logger.isWarnEnabled())
1219        logger.warn("Error while calling databaseMetaDataGetSuperTypes", e);
1220      sendToDriver(e);
1221    }
1222  }
1223
1224  /**
1225   * @see java.sql.DatabaseMetaData#getTablePrivileges(java.lang.String,
1226   * java.lang.String, java.lang.String)
1227   */

1228  private void databaseMetaDataGetTablePrivileges() throws IOException JavaDoc
1229  {
1230    if (logger.isDebugEnabled())
1231      logger.debug("DatabaseMetaDataGetTablePrivileges command");
1232
1233    String JavaDoc tpcatalog = in.readUTF();
1234    String JavaDoc tpschemaPattern = in.readUTF();
1235    String JavaDoc tptablePattern = in.readUTF();
1236
1237    try
1238    {
1239      sendToDriver(vdb.getDynamicMetaData().getTablePrivileges(login,
1240          tpcatalog, tpschemaPattern, tptablePattern));
1241    }
1242    catch (SQLException JavaDoc e)
1243    {
1244      if (logger.isWarnEnabled())
1245        logger
1246            .warn("Error while calling databaseMetaDataGetTablePrivileges", e);
1247      sendToDriver(e);
1248    }
1249  }
1250
1251  /**
1252   * @see java.sql.DatabaseMetaData#getTables(java.lang.String,
1253   * java.lang.String, java.lang.String, java.lang.String[])
1254   */

1255  private void databaseMetaDataGetTables() throws IOException JavaDoc
1256  {
1257    if (logger.isDebugEnabled())
1258      logger.debug("DatabaseMetaDataGetTables command");
1259
1260    String JavaDoc tcatalog = in.readUTF();
1261    String JavaDoc tschemaPattern = in.readUTF();
1262    String JavaDoc ttableNamePattern = in.readUTF();
1263
1264    String JavaDoc[] ttypes = null;
1265    if (in.readBoolean())
1266    {
1267      int size = in.readInt();
1268      ttypes = new String JavaDoc[size];
1269      for (int i = 0; i < size; i++)
1270        ttypes[i] = in.readUTF();
1271    }
1272
1273    try
1274    {
1275      sendToDriver(vdb.getDynamicMetaData().getTables(login, tcatalog,
1276          tschemaPattern, ttableNamePattern, ttypes));
1277    }
1278    catch (SQLException JavaDoc e)
1279    {
1280      if (logger.isWarnEnabled())
1281        logger.warn("Error while calling databaseMetaDataGetTables", e);
1282      sendToDriver(e);
1283    }
1284  }
1285
1286  /**
1287   * @see java.sql.DatabaseMetaData#getTableTypes()
1288   */

1289  private void databaseMetaDataGetTableTypes() throws IOException JavaDoc
1290  {
1291    if (logger.isDebugEnabled())
1292      logger.debug("DatabaseMetaDataGetTableTypes command");
1293
1294    try
1295    {
1296      sendToDriver(vdb.getDynamicMetaData().getTableTypes(login));
1297    }
1298    catch (SQLException JavaDoc e)
1299    {
1300      if (logger.isWarnEnabled())
1301        logger.warn("Error while calling databaseMetaDataGetTableTypes", e);
1302      sendToDriver(e);
1303    }
1304  }
1305
1306  /**
1307   * @see java.sql.DatabaseMetaData#getTypeInfo()
1308   */

1309  private void databaseMetaDataGetTypeInfo() throws IOException JavaDoc
1310  {
1311    if (logger.isDebugEnabled())
1312      logger.debug("DatabaseMetaDataGetTypeInfo command");
1313
1314    try
1315    {
1316      sendToDriver(vdb.getDynamicMetaData().getTypeInfo(login));
1317    }
1318    catch (SQLException JavaDoc e)
1319    {
1320      if (logger.isWarnEnabled())
1321        logger.warn("Error while calling databaseMetaDataGetTypeInfo", e);
1322      sendToDriver(e);
1323    }
1324  }
1325
1326  /**
1327   * @see java.sql.DatabaseMetaData#getUDTs(java.lang.String, java.lang.String,
1328   * java.lang.String, int[])
1329   */

1330  private void databaseMetaDataGetUDTs() throws IOException JavaDoc
1331  {
1332    if (logger.isDebugEnabled())
1333      logger.debug("DatabaseMetaDataGetUDTs command");
1334
1335    String JavaDoc catalog = in.readUTF();
1336    String JavaDoc schemaPattern = in.readUTF();
1337    String JavaDoc tableNamePattern = in.readUTF();
1338
1339    int[] types = null;
1340    if (in.readBoolean())
1341    {
1342      int size = in.readInt();
1343      types = new int[size];
1344      for (int i = 0; i < size; i++)
1345        types[i] = in.readInt();
1346    }
1347
1348    try
1349    {
1350      sendToDriver(vdb.getDynamicMetaData().getUDTs(login, catalog,
1351          schemaPattern, tableNamePattern, types));
1352    }
1353    catch (SQLException JavaDoc e)
1354    {
1355      if (logger.isWarnEnabled())
1356        logger.warn("Error while calling databaseMetaDataGetUDTs", e);
1357      sendToDriver(e);
1358    }
1359  }
1360
1361  /**
1362   * @see java.sql.DatabaseMetaData#getVersionColumns(java.lang.String,
1363   * java.lang.String, java.lang.String)
1364   */

1365  private void databaseMetaDataGetVersionColumns() throws IOException JavaDoc
1366  {
1367    if (logger.isDebugEnabled())
1368      logger.debug("DatabaseMetaDataGetVersionColumns command");
1369
1370    String JavaDoc catalog = in.readUTF();
1371    String JavaDoc schema = in.readUTF();
1372    String JavaDoc table = in.readUTF();
1373
1374    try
1375    {
1376      sendToDriver(vdb.getDynamicMetaData().getVersionColumns(login, catalog,
1377          schema, table));
1378    }
1379    catch (SQLException JavaDoc e)
1380    {
1381      if (logger.isWarnEnabled())
1382        logger.warn("Error while calling databaseMetaDataGetVersionColumns", e);
1383      sendToDriver(e);
1384    }
1385  }
1386
1387  /**
1388   * Get the static metadata key from the socket and return the corresponding
1389   * metadata.
1390   *
1391   * @throws IOException if an IO error occurs
1392   * @throws NotImplementedException if the underlying metadata access method is
1393   * not implemented
1394   */

1395  private void databaseStaticMetadata() throws IOException JavaDoc,
1396      NotImplementedException
1397  {
1398    // the "getXXX(Y,Z,...)" hash key of the metadata
1399
// query called by the client using the driver.
1400
String JavaDoc key = in.readUTF();
1401    if (logger.isDebugEnabled())
1402      logger.debug("DatabaseStaticMetadata command for " + key);
1403    MetadataContainer container = vdb.getStaticMetaData()
1404        .getMetadataContainer();
1405    if (container == null) // no metadata has been gathered yet from backends
1406
{
1407      String JavaDoc msg = "No metadata is available probably because no backend is enabled on that controller.";
1408      logger.info(msg);
1409      sendToDriver(new SQLException JavaDoc(msg));
1410    }
1411    else
1412    {
1413      /**
1414       * To get an exhaustive list of all the types of java objects stored in
1415       * this hash table, search for all callers of
1416       * {@link org.objectweb.cjdbc.driver.DatabaseMetaData#getMetadata(String, Class[], Object[], boolean)}
1417       * and see also
1418       * {@link org.objectweb.cjdbc.controller.backend.DatabaseBackendMetaData#retrieveDatabaseMetadata()}
1419       * At this time it's limited to the following types: String, int and
1420       * boolean. boolean is the most frequent.
1421       */

1422      /*
1423       * Since we don't expect that any of these metadata methods will ever
1424       * return a non- java.sql.Types, we re-use here the serialization
1425       * implemented for SQL Data/ResultSets elements.
1426       */

1427
1428      SQLDataSerialization.Serializer serializer;
1429      Object JavaDoc result = container.get(key);
1430
1431      try
1432      {
1433        serializer = SQLDataSerialization.getSerializer(result);
1434      }
1435      catch (NotImplementedException innerEx)
1436      { // Should we just print a warning in case result == null ?
1437
// This should never happen with decent drivers.
1438
String JavaDoc msg;
1439        if (null == result)
1440          msg = " returned a null object.";
1441        else
1442          msg = " returned an object of an unsupported java type:"
1443              + result.getClass().getName() + ".";
1444
1445        NotImplementedException outerEx = new NotImplementedException(
1446            "Backend driver method " + key + msg);
1447        outerEx.initCause(innerEx);
1448        throw outerEx;
1449      }
1450
1451      TypeTag.NOT_EXCEPTION.sendToStream(out);
1452      serializer.getTypeTag().sendToStream(out);
1453      serializer.sendToStream(result, out);
1454    }
1455
1456    out.flush();
1457  }
1458
1459  private void getControllerVersionNumber() throws IOException JavaDoc
1460  {
1461    if (logger.isDebugEnabled())
1462      logger.debug("GetControllerVersionNumber command");
1463
1464    sendToDriver(Constants.VERSION);
1465  }
1466
1467  private void getVirtualDatabaseName() throws IOException JavaDoc
1468  {
1469    if (logger.isDebugEnabled())
1470      logger.debug("GetVirtualDatabaseName command");
1471
1472    sendToDriver(vdb.getDatabaseName());
1473  }
1474
1475  //
1476
// Transaction management
1477
//
1478

1479  private void begin() throws SQLException JavaDoc, IOException JavaDoc
1480  {
1481    if (logger.isDebugEnabled())
1482      logger.debug("Begin command");
1483
1484    currentTid = vdb.begin(login);
1485    sendToDriver(currentTid);
1486
1487    transactionStarted = true;
1488    queryExecutedInThisTransaction = false;
1489    writeQueryExecutedInThisTransaction = false;
1490  }
1491
1492  private void commit() throws SQLException JavaDoc, IOException JavaDoc
1493  {
1494    if (logger.isDebugEnabled())
1495      logger.debug("Commit command");
1496
1497    vdb.commit(currentTid, writeQueryExecutedInThisTransaction);
1498    currentTid = vdb.begin(login);
1499    sendToDriver(currentTid);
1500
1501    queryExecutedInThisTransaction = false;
1502    writeQueryExecutedInThisTransaction = false;
1503  }
1504
1505  private void rollback() throws SQLException JavaDoc, IOException JavaDoc
1506  {
1507    if (logger.isDebugEnabled())
1508      logger.debug("Rollback command");
1509
1510    vdb.rollback(currentTid, writeQueryExecutedInThisTransaction);
1511    currentTid = vdb.begin(login);
1512    sendToDriver(currentTid);
1513
1514    queryExecutedInThisTransaction = false;
1515    writeQueryExecutedInThisTransaction = false;
1516  }
1517
1518  private void setAutoCommit() throws SQLException JavaDoc, IOException JavaDoc
1519  {
1520    if (logger.isDebugEnabled())
1521      logger.debug("Set Auto commit command");
1522
1523    vdb.commit(currentTid, writeQueryExecutedInThisTransaction);
1524    currentTid = 0;
1525    transactionStarted = false;
1526    queryExecutedInThisTransaction = false;
1527    writeQueryExecutedInThisTransaction = false;
1528    sendToDriver(true);
1529  }
1530
1531  private void setNamedSavepoint() throws SQLException JavaDoc, IOException JavaDoc
1532  {
1533    if (logger.isDebugEnabled())
1534      logger.debug("Set named savepoint command");
1535
1536    String JavaDoc savepointName = in.readUTF();
1537    vdb.setSavepoint(currentTid, savepointName);
1538    sendToDriver(true);
1539  }
1540
1541  private void setUnnamedSavepoint() throws SQLException JavaDoc, IOException JavaDoc
1542  {
1543    if (logger.isDebugEnabled())
1544      logger.debug("Set unnamed savepoint command");
1545
1546    int savepointId = vdb.setSavepoint(currentTid);
1547    sendToDriver(savepointId);
1548  }
1549
1550  private void releaseSavepoint() throws SQLException JavaDoc, IOException JavaDoc
1551  {
1552    if (logger.isDebugEnabled())
1553      logger.debug("Release savepoint command");
1554
1555    String JavaDoc savepointName = in.readUTF();
1556    vdb.releaseSavepoint(currentTid, savepointName);
1557    sendToDriver(true);
1558  }
1559
1560  private void rollbackToSavepoint() throws SQLException JavaDoc, IOException JavaDoc
1561  {
1562    if (logger.isDebugEnabled())
1563      logger.debug("Rollback to savepoint command");
1564    String JavaDoc savepointName = in.readUTF();
1565    vdb.rollback(currentTid, savepointName);
1566    sendToDriver(true);
1567  }
1568
1569  //
1570
// Request execution
1571
//
1572

1573  private void execReadRequest() throws IOException JavaDoc, SQLException JavaDoc
1574  {
1575    if (logger.isDebugEnabled())
1576      logger.debug("ExecReadRequest command");
1577    SelectRequest select = new SelectRequest(in);
1578    transactionStarted = setRequestParameters(select, login, currentTid,
1579        transactionStarted);
1580    if (!transactionStarted)
1581      currentTid = 0;
1582    else
1583      queryExecutedInThisTransaction = true;
1584
1585    // send the resultset
1586
ControllerResultSet crs = vdb.execReadRequest(select);
1587    DriverResultSet drs = new DriverResultSet(crs.getFields(), crs.getData(),
1588        crs.hasMoreData(), crs.getCursorName());
1589    sendToDriver(drs);
1590
1591    // streaming
1592
if (crs.hasMoreData())
1593      putStreamingReferences(crs, drs);
1594
1595  }
1596
1597  // TODO : try to share code with execWriteStoredProcedure below
1598
private void execReadStoredProcedure() throws IOException JavaDoc, SQLException JavaDoc
1599  {
1600    if (logger.isDebugEnabled())
1601      logger.debug("ExecReadStoredProcedure command");
1602    StoredProcedure readProc = new StoredProcedure(in);
1603    transactionStarted = setRequestParameters(readProc, login, currentTid,
1604        transactionStarted);
1605    if (!transactionStarted)
1606      currentTid = 0;
1607    else
1608    { // Transaction not started, check if we should do a lazy start
1609
queryExecutedInThisTransaction = true;
1610      if (!(writeQueryExecutedInThisTransaction || readProc.isReadOnly()))
1611      {
1612        vdb.getRequestManager().logLazyTransactionBegin(currentTid);
1613        writeQueryExecutedInThisTransaction = true;
1614      }
1615    }
1616    ControllerResultSet sprs = vdb.execReadStoredProcedure(readProc);
1617    DriverResultSet drs = new DriverResultSet(sprs.getFields(), sprs.getData(),
1618        sprs.hasMoreData(), sprs.getCursorName());
1619
1620    sendToDriver(drs);
1621
1622    if (sprs.hasMoreData())
1623      putStreamingReferences(sprs, drs);
1624
1625  }
1626
1627  private void execWriteRequest() throws IOException JavaDoc, SQLException JavaDoc
1628  {
1629    if (logger.isDebugEnabled())
1630      logger.debug("ExecWriteRequest command");
1631    AbstractWriteRequest write = decodeWriteRequestFromStream();
1632    transactionStarted = setRequestParameters(write, login, currentTid,
1633        transactionStarted);
1634    if (!transactionStarted)
1635      currentTid = 0;
1636    else
1637    { // Transaction not started, check if we should do a lazy start
1638
queryExecutedInThisTransaction = true;
1639      if (!writeQueryExecutedInThisTransaction)
1640      {
1641        vdb.getRequestManager().logLazyTransactionBegin(currentTid);
1642        writeQueryExecutedInThisTransaction = true;
1643      }
1644    }
1645    sendToDriver(vdb.execWriteRequest(write));
1646  }
1647
1648  /**
1649   * execWriteRequestWithKeys() will probably have soon no difference with
1650   * execWriteRequest() anymore; then we can get rid of it.
1651   */

1652  private void execWriteRequestWithKeys() throws IOException JavaDoc, SQLException JavaDoc
1653  {
1654    if (logger.isDebugEnabled())
1655      logger.debug("ExecWriteRequestWithKeys command");
1656    AbstractWriteRequest writeWithKeys = decodeWriteRequestFromStream();
1657    transactionStarted = setRequestParameters(writeWithKeys, login, currentTid,
1658        transactionStarted);
1659    if (!transactionStarted)
1660      currentTid = 0;
1661    else
1662    { // Transaction not started, check if we should do a lazy start
1663
queryExecutedInThisTransaction = true;
1664      if (!writeQueryExecutedInThisTransaction)
1665      {
1666        vdb.getRequestManager().logLazyTransactionBegin(currentTid);
1667        writeQueryExecutedInThisTransaction = true;
1668      }
1669    }
1670    ControllerResultSet keys = vdb.execWriteRequestWithKeys(writeWithKeys);
1671    // currently UNTESTED (which backend does support auto-generated keys ?)
1672
DriverResultSet drs = new DriverResultSet(keys.getFields(), keys.getData(),
1673        keys.hasMoreData(), keys.getCursorName());
1674
1675    sendToDriver(drs);
1676
1677    if (keys.hasMoreData())
1678      putStreamingReferences(keys, drs);
1679
1680  }
1681
1682  private void execWriteStoredProcedure() throws IOException JavaDoc, SQLException JavaDoc
1683  {
1684    if (logger.isDebugEnabled())
1685      logger.debug("ExecWriteStoredProcedure command");
1686    StoredProcedure writeProc = new StoredProcedure(in);
1687    transactionStarted = setRequestParameters(writeProc, login, currentTid,
1688        transactionStarted);
1689    if (!transactionStarted)
1690      currentTid = 0;
1691    else
1692    {
1693      queryExecutedInThisTransaction = true;
1694      if (!writeQueryExecutedInThisTransaction)
1695      {
1696        vdb.getRequestManager().logLazyTransactionBegin(currentTid);
1697        writeQueryExecutedInThisTransaction = true;
1698      }
1699    }
1700    sendToDriver(vdb.execWriteStoredProcedure(writeProc));
1701  }
1702
1703  /**
1704   * Serialize a DriverResultSet answer, prefixed with the appropriate TypeTag
1705   *
1706   * @param drs the resultset to send
1707   * @throws IOException stream error
1708   */

1709  private void sendToDriver(DriverResultSet drs) throws IOException JavaDoc
1710  {
1711
1712    if (null == drs) // should not happen with well-behaved drivers
1713
{
1714      TypeTag.NULL_RESULTSET.sendToStream(out);
1715      out.flush();
1716    }
1717    else
1718    {
1719      TypeTag.RESULTSET.sendToStream(out);
1720      drs.sendToStream(out);
1721    }
1722  }
1723
1724  /**
1725   * Send a protocol String, prefixed with the appropriate TypeTag
1726   */

1727  private void sendToDriver(String JavaDoc str) throws IOException JavaDoc
1728  {
1729    TypeTag.NOT_EXCEPTION.sendToStream(out);
1730    out.writeUTF(str);
1731    out.flush();
1732  }
1733
1734  /**
1735   * Send a protocol boolean, prefixed with the appropriate TypeTag
1736   */

1737  private void sendToDriver(boolean b) throws IOException JavaDoc
1738  {
1739    TypeTag.NOT_EXCEPTION.sendToStream(out);
1740    out.writeBoolean(b);
1741    out.flush();
1742  }
1743
1744  /**
1745   * Send a protocol int, prefixed with the appropriate TypeTag
1746   */

1747  private void sendToDriver(int i) throws IOException JavaDoc
1748  {
1749    TypeTag.NOT_EXCEPTION.sendToStream(out);
1750    out.writeInt(i);
1751    out.flush();
1752  }
1753
1754  /**
1755   * Send a protocol long, prefixed with the appropriate TypeTag
1756   */

1757  private void sendToDriver(long l) throws IOException JavaDoc
1758  {
1759    TypeTag.NOT_EXCEPTION.sendToStream(out);
1760    out.writeLong(l);
1761    out.flush();
1762  }
1763
1764  private void sendToDriver(Exception JavaDoc e) throws IOException JavaDoc
1765  {
1766    TypeTag.EXCEPTION.sendToStream(out);
1767    // This is the place where we convert Exceptions to something
1768
// serializable and that the driver can understand
1769
// So this is the place where it's possible to trap all unknown exceptions
1770

1771    if (e instanceof SQLException JavaDoc)
1772    { // we assume that an SQLexception comes from the backend
1773

1774      // since this is currently false because some ControllerCoreExceptions
1775
// subclass SQLException, here are a few workarounds
1776
if (e instanceof NoMoreBackendException
1777          || e instanceof NoMoreControllerException
1778          || e instanceof NotImplementedException)
1779      {
1780        TypeTag.CORE_EXCEPTION.sendToStream(out);
1781        new ControllerCoreException(e).sendToStream(out);
1782        return;
1783      }
1784
1785      // non-workaround, regular SQLException from backend
1786
TypeTag.BACKEND_EXCEPTION.sendToStream(out);
1787      new BackendDriverException(e).sendToStream(out);
1788      return;
1789    }
1790
1791    // else we assume this is an exception from the core (currently...?)
1792
TypeTag.CORE_EXCEPTION.sendToStream(out);
1793    new ControllerCoreException(e).sendToStream(out);
1794    return;
1795
1796  }
1797
1798  /**
1799   * Implements streaming: send the next ResultSet chunk to driver, pulling it
1800   * from ControllerResultSet. The driver decides of the chunk size at each
1801   * call. Note that virtualdatabase streaming is independent from backend
1802   * streaming (which may not be supported). They even could be configured with
1803   * two different fetchSize -s (it's not currently the case).
1804   *
1805   * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#executeSelectRequestOnBackend(SelectRequest,
1806   * org.objectweb.cjdbc.controller.backend.DatabaseBackend, Connection,
1807   * org.objectweb.cjdbc.controller.cache.metadata.MetadataCache)
1808   * @see ControllerResultSet#fetchData(int)
1809   */

1810  private void fetchNextResultSetRows() throws IOException JavaDoc, SQLException JavaDoc
1811  {
1812    if (logger.isDebugEnabled())
1813      logger.debug("FetchNextResultSetRows command");
1814
1815    String JavaDoc cursorName = in.readUTF();
1816    int fetchSize = in.readInt();
1817    ControllerResultSet fetchCrs = (ControllerResultSet) streamedResultSet
1818        .get(cursorName);
1819    if (fetchCrs == null)
1820    {
1821      sendToDriver(new SQLException JavaDoc(
1822          "No valid ControllerResultSet to fetch data from"));
1823      out.flush();
1824    }
1825    else
1826    {
1827      // refresh driverResultSet with a new chunk of rows
1828
DriverResultSet drs = fetchCrs.driverResultSet;
1829      fetchCrs.fetchData(fetchSize);
1830      drs.setData(fetchCrs.getData());
1831      // at this point, we could probably do some kind of crs.setData(null)
1832
// as a memory optimization, but in doubt we leave it as is.
1833
drs.setHasMoreData(fetchCrs.hasMoreData());
1834
1835      // send it
1836
TypeTag.NOT_EXCEPTION.sendToStream(out);
1837      drs.sendRowsToStream(out);
1838
1839      // garbage collect sent data
1840
drs.setData(null);
1841
1842      if (!fetchCrs.hasMoreData())
1843        streamedResultSet.remove(cursorName);
1844    }
1845  }
1846
1847  //
1848
// Public API
1849
//
1850

1851  /**
1852   * Retrieve general information on this client
1853   *
1854   * @return an array of string
1855   */

1856  public String JavaDoc[] retrieveClientData()
1857  {
1858    String JavaDoc[] data = new String JavaDoc[4];
1859    data[0] = in.getSocket().getInetAddress().getHostName();
1860    data[1] = in.getSocket().getInetAddress().getHostAddress();
1861    data[2] = String
1862        .valueOf(((System.currentTimeMillis() - in.getDateCreated()) / 1000));
1863    return data;
1864  }
1865
1866  /**
1867   * Get time active
1868   *
1869   * @return time active since started
1870   */

1871  public long getTimeActive()
1872  {
1873    return ((System.currentTimeMillis() - in.getDateCreated()) / 1000);
1874  }
1875
1876  /**
1877   * @return Returns the login of the current user.
1878   */

1879  public String JavaDoc getUser()
1880  {
1881    return user.getLogin();
1882  }
1883
1884  /**
1885   * Shutdown this thread by setting <code>isKilled</code> value to true. This
1886   * gives time to check for needed rollback transactions
1887   */

1888  public void shutdown()
1889  {
1890    // Tell this thread to stop working gently.
1891
// This will cancel transaction if needed
1892
this.isKilled = true;
1893    try
1894    {
1895      if (waitForCommand)
1896      {
1897        // close only the streams if we're not in the middle of a request
1898
in.close();
1899        out.close();
1900      }
1901    }
1902    catch (IOException JavaDoc e)
1903    {
1904      // ignore, only the input stream should be close
1905
// for this thread to end
1906
}
1907  }
1908
1909}
Popular Tags