KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > loadbalancer > singledb > SingleDB


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): Vadim Kassin, Jaco Swart, Jean-Bernard van Zuylen.
23  */

24
25 package org.objectweb.cjdbc.controller.loadbalancer.singledb;
26
27 import java.sql.Connection JavaDoc;
28 import java.sql.SQLException JavaDoc;
29 import java.sql.Savepoint JavaDoc;
30
31 import org.objectweb.cjdbc.common.exceptions.BadConnectionException;
32 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
33 import org.objectweb.cjdbc.common.i18n.Translate;
34 import org.objectweb.cjdbc.common.log.Trace;
35 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
36 import org.objectweb.cjdbc.common.sql.ParsingGranularities;
37 import org.objectweb.cjdbc.common.sql.SelectRequest;
38 import org.objectweb.cjdbc.common.sql.StoredProcedure;
39 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
40 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
41 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
42 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager;
43 import org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer;
44 import org.objectweb.cjdbc.controller.loadbalancer.AllBackendsFailedException;
45 import org.objectweb.cjdbc.controller.requestmanager.RAIDbLevels;
46 import org.objectweb.cjdbc.controller.requestmanager.TransactionMarkerMetaData;
47 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
48 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
49
50 /**
51  * Single Database request load balancer.
52  * <p>
53  * The requests coming from the request controller are directly forwarded to the
54  * single backend. This load balancer does not support multiple backends.
55  *
56  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
57  * @author <a HREF="mailto:vadim@kase.kz">Vadim Kassin </a>
58  * @author <a HREF="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
59  * @author <a HREF="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
60  * </a>
61  * @version 1.0
62  */

63 public class SingleDB extends AbstractLoadBalancer
64 {
65   //
66
// How the code is organized?
67
// 1. Member variables
68
// 2. Constructor(s)
69
// 3. Request handling
70
// 4. Transaction handling
71
// 5. Backend management
72
// 6. Debug/Monitoring
73
//
74

75   private DatabaseBackend backend;
76
77   private static Trace logger = Trace
78                                      .getLogger("org.objectweb.cjdbc.controller.loadbalancer.SingleDB");
79
80   /*
81    * Constructors
82    */

83
84   /**
85    * Creates a new <code>SingleDB</code> instance.
86    *
87    * @param vdb the <code>VirtualDatabase</code> this load balancer belongs to
88    * @throws Exception if there is not exactly one backend attached to the
89    * <code>VirtualDatabase</code>
90    */

91   public SingleDB(VirtualDatabase vdb) throws Exception JavaDoc
92   {
93     // We don't need to parse the requests, just send them to the backend
94
super(vdb, RAIDbLevels.SingleDB, ParsingGranularities.NO_PARSING);
95   }
96
97   /*
98    * Request Handling
99    */

100
101   /**
102    * Performs a read request. It is up to the implementation to choose to which
103    * backend node(s) this request should be sent.
104    *
105    * @param request an <code>SelectRequest</code>
106    * @param metadataCache MetadataCache (null if none)
107    * @return the corresponding <code>java.sql.ResultSet</code>
108    * @exception SQLException if an error occurs
109    */

110   public ControllerResultSet execReadRequest(SelectRequest request,
111       MetadataCache metadataCache) throws SQLException JavaDoc
112   {
113     if (backend == null)
114       throw new SQLException JavaDoc(Translate.get(
115           "loadbalancer.execute.no.backend.available", request.getId()));
116
117     try
118     {
119       AbstractConnectionManager cm = backend.getConnectionManager(request
120           .getLogin());
121       if (request.isAutoCommit())
122       {
123         ControllerResultSet rs = null;
124         boolean badConnection;
125         do
126         {
127           badConnection = false;
128           // Use a connection just for this request
129
Connection JavaDoc c = null;
130           try
131           {
132             c = cm.getConnection();
133           }
134           catch (UnreachableBackendException e1)
135           {
136             String JavaDoc backendName = backend.getName();
137             logger.error(Translate.get(
138                 "loadbalancer.backend.disabling.unreachable", backendName));
139             disableBackend(backend);
140             backend = null;
141             throw new SQLException JavaDoc(Translate.get(
142                 "loadbalancer.backend.unreacheable", backendName));
143           }
144
145           // Sanity check
146
if (c == null)
147             throw new SQLException JavaDoc(Translate.get(
148                 "loadbalancer.backend.no.connection", backend.getName()));
149
150           // Execute Query
151
try
152           {
153             rs = executeSelectRequestOnBackend(request, backend, c,
154                 metadataCache);
155             cm.releaseConnection(c);
156           }
157           catch (SQLException JavaDoc e)
158           {
159             cm.releaseConnection(c);
160             throw new SQLException JavaDoc(Translate.get(
161                 "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
162                     request.getSQLShortForm(vdb.getSQLShortFormLength()),
163                     backend.getName(), e.getMessage()}));
164           }
165           catch (BadConnectionException e)
166           { // Get rid of the bad connection
167
cm.deleteConnection(c);
168             badConnection = true;
169           }
170         }
171         while (badConnection);
172         return rs;
173       }
174       else
175       {
176         long tid = request.getTransactionId();
177         // Re-use the connection used by this transaction
178
Connection JavaDoc c = cm.retrieveConnection(tid);
179
180         // Sanity check
181
if (c == null)
182           throw new SQLException JavaDoc(Translate.get(
183               "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
184                   String.valueOf(tid), backend.getName()}));
185
186         // Execute Query
187
ControllerResultSet rs = null;
188         try
189         {
190           rs = executeSelectRequestOnBackend(request, backend, c, metadataCache);
191         }
192         catch (SQLException JavaDoc e)
193         {
194           throw new SQLException JavaDoc(Translate.get(
195               "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
196                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
197                   backend.getName(), e.getMessage()}));
198         }
199         catch (BadConnectionException e)
200         { // Get rid of the bad connection
201
cm.deleteConnection(tid);
202           throw new SQLException JavaDoc(Translate.get(
203               "loadbalancer.connection.failed", new String JavaDoc[]{
204                   String.valueOf(tid), backend.getName(), e.getMessage()}));
205         }
206         return rs;
207       }
208     }
209     catch (RuntimeException JavaDoc e)
210     {
211       String JavaDoc msg = "Request '"
212           + request.getSQLShortForm(vdb.getSQLShortFormLength())
213           + "' failed on backend " + backend.getURL() + " (" + e + ")";
214       logger.fatal(msg, e);
215       throw new SQLException JavaDoc(msg);
216     }
217   }
218
219   /**
220    * Performs a write request on the backend.
221    *
222    * @param request an <code>AbstractWriteRequest</code>
223    * @return number of rows affected by the request
224    * @exception SQLException if an error occurs
225    */

226   public int execWriteRequest(AbstractWriteRequest request) throws SQLException JavaDoc
227   {
228     if (backend == null)
229       throw new SQLException JavaDoc(Translate.get(
230           "loadbalancer.execute.no.backend.available", request.getId()));
231
232     try
233     {
234       AbstractConnectionManager cm = backend.getConnectionManager(request
235           .getLogin());
236       if (request.isAutoCommit())
237       {
238         // We do not execute request outside the already open transactions if we
239
// are disabling the backend.
240
if (backend.isDisabling())
241           throw new SQLException JavaDoc(Translate.get(
242               "loadbalancer.backend.is.disabling", new String JavaDoc[]{
243                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
244                   backend.getName()}));
245
246         // Use a connection just for this request
247
Connection JavaDoc c = null;
248         try
249         {
250           c = cm.getConnection();
251         }
252         catch (UnreachableBackendException e1)
253         {
254           String JavaDoc backendName = backend.getName();
255           logger.error(Translate.get(
256               "loadbalancer.backend.disabling.unreachable", backendName));
257           disableBackend(backend);
258           backend = null;
259           throw new SQLException JavaDoc(Translate.get(
260               "loadbalancer.backend.unreacheable", backendName));
261         }
262
263         // Sanity check
264
if (c == null)
265           throw new SQLException JavaDoc(Translate.get(
266               "loadbalancer.backend.no.connection", backend.getName()));
267
268         // Execute Query
269
int result;
270         try
271         {
272           result = executeUpdateRequestOnBackend(request, backend, c);
273         }
274         catch (Exception JavaDoc e)
275         {
276           throw new SQLException JavaDoc(Translate.get(
277               "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
278                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
279                   backend.getName(), e.getMessage()}));
280         }
281         finally
282         {
283           cm.releaseConnection(c);
284         }
285         return result;
286       }
287       else
288       { // Re-use the connection used by this transaction
289
Connection JavaDoc c = cm.retrieveConnection(request.getTransactionId());
290
291         // Sanity check
292
if (c == null)
293           throw new SQLException JavaDoc(Translate.get(
294               "loadbalancer.unable.retrieve.connection",
295               new String JavaDoc[]{String.valueOf(request.getTransactionId()),
296                   backend.getName()}));
297
298         // Execute Query
299
try
300         {
301           return executeUpdateRequestOnBackend(request, backend, c);
302         }
303         catch (Exception JavaDoc e)
304         {
305           throw new SQLException JavaDoc(Translate.get(
306               "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
307                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
308                   backend.getName(), e.getMessage()}));
309         }
310       }
311     }
312     catch (RuntimeException JavaDoc e)
313     {
314       String JavaDoc msg = Translate.get("loadbalancer.request.failed.on.backend",
315           new String JavaDoc[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
316               backend.getName(), e.getMessage()});
317       logger.fatal(msg, e);
318       throw new SQLException JavaDoc(msg);
319     }
320   }
321
322   /**
323    * @see AbstractLoadBalancer#execWriteRequestWithKeys(AbstractWriteRequest,
324    * MetadataCache)
325    */

326   public ControllerResultSet execWriteRequestWithKeys(
327       AbstractWriteRequest request, MetadataCache metadataCache)
328       throws SQLException JavaDoc
329   {
330     if (backend == null)
331       throw new SQLException JavaDoc(Translate.get(
332           "loadbalancer.execute.no.backend.available", request.getId()));
333
334     if (!backend.getDriverCompliance().supportGetGeneratedKeys())
335       throw new SQLException JavaDoc(Translate.get(
336           "loadbalancer.backend.autogeneratedkeys.unsupported", backend
337               .getName()));
338
339     try
340     {
341       AbstractConnectionManager cm = backend.getConnectionManager(request
342           .getLogin());
343       if (request.isAutoCommit())
344       {
345         // We do not execute request outside the already open transactions if we
346
// are disabling the backend.
347
if (backend.isDisabling())
348           throw new SQLException JavaDoc(Translate.get(
349               "loadbalancer.backend.is.disabling", new String JavaDoc[]{
350                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
351                   backend.getName()}));
352
353         // Use a connection just for this request
354
Connection JavaDoc c = null;
355         try
356         {
357           c = cm.getConnection();
358         }
359         catch (UnreachableBackendException e1)
360         {
361           String JavaDoc backendName = backend.getName();
362           logger.error(Translate.get(
363               "loadbalancer.backend.disabling.unreachable", backendName));
364           disableBackend(backend);
365           backend = null;
366           throw new SQLException JavaDoc(Translate.get(
367               "loadbalancer.backend.unreacheable", backendName));
368         }
369
370         // Sanity check
371
if (c == null)
372           throw new SQLException JavaDoc(Translate.get(
373               "loadbalancer.backend.no.connection", backend.getName()));
374
375         // Execute Query
376
ControllerResultSet result;
377         try
378         {
379           result = executeUpdateRequestOnBackendWithKeys(request, backend, c,
380               metadataCache);
381         }
382         catch (Exception JavaDoc e)
383         {
384           throw new SQLException JavaDoc(Translate.get(
385               "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
386                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
387                   backend.getName(), e.getMessage()}));
388         }
389         finally
390         {
391           cm.releaseConnection(c);
392         }
393         return result;
394       }
395       else
396       {
397         // Re-use the connection used by this transaction
398
Connection JavaDoc c = cm.retrieveConnection(request.getTransactionId());
399
400         // Sanity check
401
if (c == null)
402           throw new SQLException JavaDoc(Translate.get(
403               "loadbalancer.unable.retrieve.connection",
404               new String JavaDoc[]{String.valueOf(request.getTransactionId()),
405                   backend.getName()}));
406
407         // Execute Query
408
try
409         {
410           return executeUpdateRequestOnBackendWithKeys(request, backend, c,
411               metadataCache);
412         }
413         catch (Exception JavaDoc e)
414         {
415           throw new SQLException JavaDoc(Translate.get(
416               "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
417                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
418                   backend.getName(), e.getMessage()}));
419         }
420         finally
421         {
422           backend.removePendingRequest(request);
423         }
424       }
425     }
426     catch (RuntimeException JavaDoc e)
427     {
428       String JavaDoc msg = Translate.get("loadbalancer.request.failed.on.backend",
429           new String JavaDoc[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
430               backend.getName(), e.getMessage()});
431       logger.fatal(msg, e);
432       throw new SQLException JavaDoc(msg);
433     }
434   }
435
436   /**
437    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#execReadOnlyReadStoredProcedure(StoredProcedure,
438    * MetadataCache)
439    */

440   public ControllerResultSet execReadOnlyReadStoredProcedure(
441       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc
442   {
443     return execReadStoredProcedure(proc, metadataCache);
444   }
445
446   /**
447    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#execReadStoredProcedure(StoredProcedure,
448    * MetadataCache)
449    */

450   public ControllerResultSet execReadStoredProcedure(StoredProcedure proc,
451       MetadataCache metadataCache) throws SQLException JavaDoc
452   {
453     if (backend == null)
454       throw new SQLException JavaDoc(
455           "No available backend to execute stored procedure " + proc.getId());
456
457     try
458     {
459       AbstractConnectionManager cm = backend.getConnectionManager(proc
460           .getLogin());
461       if (proc.isAutoCommit())
462       { // Use a connection just for this request
463
Connection JavaDoc c = null;
464         try
465         {
466           c = cm.getConnection();
467         }
468         catch (UnreachableBackendException e1)
469         {
470           String JavaDoc backendName = backend.getName();
471           logger.error(Translate.get(
472               "loadbalancer.backend.disabling.unreachable", backendName));
473           disableBackend(backend);
474           backend = null;
475           throw new SQLException JavaDoc(Translate.get(
476               "loadbalancer.backend.unreacheable", backendName));
477         }
478
479         // Sanity check
480
if (c == null)
481           throw new SQLException JavaDoc(Translate.get(
482               "loadbalancer.backend.no.connection", backend.getName()));
483
484         // Execute Query
485
ControllerResultSet rs = null;
486         try
487         {
488           rs = AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
489               backend, c, metadataCache);
490         }
491         catch (Exception JavaDoc e)
492         {
493           throw new SQLException JavaDoc(Translate.get(
494               "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
495                   proc.getSQLShortForm(vdb.getSQLShortFormLength()),
496                   backend.getName(), e.getMessage()}));
497         }
498         finally
499         {
500           cm.releaseConnection(c);
501         }
502         return rs;
503       }
504       else
505       { // Re-use the connection used by this transaction
506
Connection JavaDoc c = cm.retrieveConnection(proc.getTransactionId());
507
508         // Sanity check
509
if (c == null)
510           throw new SQLException JavaDoc(Translate.get(
511               "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
512                   String.valueOf(proc.getTransactionId()), backend.getName()}));
513
514         // Execute Query
515
try
516         {
517           return AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
518               backend, c, metadataCache);
519         }
520         catch (Exception JavaDoc e)
521         {
522           throw new SQLException JavaDoc(Translate.get(
523               "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
524                   proc.getSQLShortForm(vdb.getSQLShortFormLength()),
525                   backend.getName(), e.getMessage()}));
526         }
527       }
528     }
529     catch (RuntimeException JavaDoc e)
530     {
531       String JavaDoc msg = Translate.get(
532           "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
533               proc.getSQLShortForm(vdb.getSQLShortFormLength()),
534               backend.getName(), e.getMessage()});
535       logger.fatal(msg, e);
536       throw new SQLException JavaDoc(msg);
537     }
538   }
539
540   /**
541    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#execWriteStoredProcedure(org.objectweb.cjdbc.common.sql.StoredProcedure)
542    */

543   public int execWriteStoredProcedure(StoredProcedure proc) throws SQLException JavaDoc
544   {
545     if (backend == null)
546       throw new SQLException JavaDoc(
547           "No available backend to execute stored procedure " + proc.getId());
548
549     try
550     {
551       AbstractConnectionManager cm = backend.getConnectionManager(proc
552           .getLogin());
553       if (proc.isAutoCommit())
554       { // Use a connection just for this request
555
Connection JavaDoc c = null;
556         try
557         {
558           c = cm.getConnection();
559         }
560         catch (UnreachableBackendException e1)
561         {
562           String JavaDoc backendName = backend.getName();
563           logger.error(Translate.get(
564               "loadbalancer.backend.disabling.unreachable", backendName));
565           disableBackend(backend);
566           backend = null;
567           throw new SQLException JavaDoc(Translate.get(
568               "loadbalancer.backend.unreacheable", backendName));
569         }
570
571         // Sanity check
572
if (c == null)
573           throw new SQLException JavaDoc(Translate.get(
574               "loadbalancer.backend.no.connection", backend.getName()));
575
576         // Execute Query
577
int result;
578         try
579         {
580           result = AbstractLoadBalancer.executeWriteStoredProcedureOnBackend(
581               proc, backend, c);
582         }
583         catch (Exception JavaDoc e)
584         {
585           throw new SQLException JavaDoc(Translate.get(
586               "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
587                   proc.getSQLShortForm(vdb.getSQLShortFormLength()),
588                   backend.getName(), e.getMessage()}));
589         }
590         finally
591         {
592           cm.releaseConnection(c);
593         }
594         return result;
595       }
596       else
597       { // Re-use the connection used by this transaction
598
Connection JavaDoc c = cm.retrieveConnection(proc.getTransactionId());
599
600         // Sanity check
601
if (c == null)
602           throw new SQLException JavaDoc(Translate.get(
603               "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
604                   String.valueOf(proc.getTransactionId()), backend.getName()}));
605
606         // Execute Query
607
try
608         {
609           return AbstractLoadBalancer.executeWriteStoredProcedureOnBackend(
610               proc, backend, c);
611         }
612         catch (Exception JavaDoc e)
613         {
614           throw new SQLException JavaDoc(Translate.get(
615               "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
616                   proc.getSQLShortForm(vdb.getSQLShortFormLength()),
617                   backend.getName(), e.getMessage()}));
618         }
619       }
620     }
621     catch (RuntimeException JavaDoc e)
622     {
623       String JavaDoc msg = Translate.get(
624           "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
625               proc.getSQLShortForm(vdb.getSQLShortFormLength()),
626               backend.getName(), e.getMessage()});
627       logger.fatal(msg, e);
628       throw new SQLException JavaDoc(msg);
629     }
630   }
631
632   /*
633    * Transaction management
634    */

635
636   /**
637    * Begins a new transaction.
638    *
639    * @param tm the transaction marker metadata
640    * @exception SQLException if an error occurs
641    */

642   public void begin(TransactionMarkerMetaData tm) throws SQLException JavaDoc
643   {
644     if (backend == null)
645       throw new SQLException JavaDoc("No available backend to begin transaction "
646           + tm.getTransactionId());
647
648     // We do not accept new transactions if we are disabling the backend
649
if (backend.isDisabling())
650       throw new SQLException JavaDoc(Translate.get("loadbalancer.backend.is.disabling",
651           new String JavaDoc[]{"begin transaction " + tm.getTransactionId(),
652               backend.getName()}));
653
654     try
655     {
656       Connection JavaDoc c = backend.getConnectionManager(tm.getLogin()).getConnection(
657           tm.getTransactionId());
658
659       if (c == null)
660         throw new SQLException JavaDoc(Translate.get(
661             "loadbalancer.backend.no.connection", backend.getName()));
662
663       c.setAutoCommit(false);
664     }
665     catch (Exception JavaDoc e)
666     {
667       throw new SQLException JavaDoc("Begin of transaction " + tm.getTransactionId()
668           + " failed on backend " + backend.getURL() + " (" + e + ")");
669     }
670   }
671
672   /**
673    * Commits a transaction.
674    *
675    * @param tm the transaction marker metadata
676    * @exception SQLException if an error occurs
677    */

678   public void commit(TransactionMarkerMetaData tm) throws SQLException JavaDoc
679   {
680     if (backend == null)
681       throw new SQLException JavaDoc("No available backend to commit transaction "
682           + tm.getTransactionId());
683
684     try
685     {
686       AbstractConnectionManager cm = backend
687           .getConnectionManager(tm.getLogin());
688       Connection JavaDoc c = cm.retrieveConnection(tm.getTransactionId());
689
690       if (c == null)
691         throw new SQLException JavaDoc("No connection found for transaction "
692             + tm.getTransactionId());
693
694       try
695       {
696         c.commit();
697         c.setAutoCommit(true);
698       }
699       catch (SQLException JavaDoc e)
700       {
701         throw new SQLException JavaDoc(Translate.get("loadbalancer.commit.failed",
702             new String JavaDoc[]{String.valueOf(tm.getTransactionId()),
703                 backend.getName(), e.getMessage()}));
704       }
705       finally
706       {
707         cm.releaseConnection(tm.getTransactionId());
708       }
709     }
710     catch (RuntimeException JavaDoc e)
711     {
712       String JavaDoc msg = Translate.get("loadbalancer.commit.failed", new String JavaDoc[]{
713           String.valueOf(tm.getTransactionId()), backend.getName(),
714           e.getMessage()});
715       logger.fatal(msg, e);
716       throw new SQLException JavaDoc(msg);
717     }
718   }
719
720   /**
721    * Rollbacks a transaction.
722    *
723    * @param tm the transaction marker metadata
724    * @exception SQLException if an error occurs
725    */

726   public void rollback(TransactionMarkerMetaData tm) throws SQLException JavaDoc
727   {
728     if (backend == null)
729       throw new SQLException JavaDoc("No available backend to rollback transaction "
730           + tm.getTransactionId());
731
732     try
733     {
734       AbstractConnectionManager cm = backend
735           .getConnectionManager(tm.getLogin());
736       Connection JavaDoc c = cm.retrieveConnection(tm.getTransactionId());
737
738       if (c == null)
739         throw new SQLException JavaDoc("No connection found for transaction "
740             + tm.getTransactionId());
741
742       try
743       {
744         c.rollback();
745         c.setAutoCommit(true);
746       }
747       catch (SQLException JavaDoc e)
748       {
749         throw new SQLException JavaDoc(Translate.get("loadbalancer.rollback.failed",
750             new String JavaDoc[]{String.valueOf(tm.getTransactionId()),
751                 backend.getName(), e.getMessage()}));
752       }
753       finally
754       {
755         cm.releaseConnection(tm.getTransactionId());
756       }
757     }
758     catch (RuntimeException JavaDoc e)
759     {
760       String JavaDoc msg = Translate.get("loadbalancer.rollback.failed", new String JavaDoc[]{
761           String.valueOf(tm.getTransactionId()), backend.getName(),
762           e.getMessage()});
763       logger.fatal(msg, e);
764       throw new SQLException JavaDoc(msg);
765     }
766   }
767
768   /**
769    * Rollback a transaction to a savepoint
770    *
771    * @param tm The transaction marker metadata
772    * @param savepointName The name of the savepoint
773    * @throws SQLException if an error occurs
774    */

775   public void rollback(TransactionMarkerMetaData tm, String JavaDoc savepointName)
776       throws SQLException JavaDoc
777   {
778     if (backend == null)
779       throw new SQLException JavaDoc("No available backend to rollback transaction "
780           + tm.getTransactionId());
781
782     try
783     {
784       AbstractConnectionManager cm = backend
785           .getConnectionManager(tm.getLogin());
786       Connection JavaDoc c = cm.retrieveConnection(tm.getTransactionId());
787
788       if (c == null)
789         throw new SQLException JavaDoc("No connection found for transaction "
790             + tm.getTransactionId());
791
792       Savepoint JavaDoc savepoint = backend.getSavepoint(new Long JavaDoc(
793           tm.getTransactionId()), savepointName);
794       
795       if (savepoint == null)
796         throw new SQLException JavaDoc("No savepoint with name " + savepointName
797             + " has been found for transaction " + tm.getTransactionId());
798       
799       try
800       {
801         c.rollback(savepoint);
802       }
803       catch (SQLException JavaDoc e)
804       {
805         throw new SQLException JavaDoc(Translate.get(
806             "loadbalancer.rollbacksavepoint.failed", new String JavaDoc[]{
807                 savepointName, String.valueOf(tm.getTransactionId()),
808                 backend.getName(), e.getMessage()}));
809       }
810     }
811     catch (RuntimeException JavaDoc e)
812     {
813       String JavaDoc msg = Translate.get("loadbalancer.rollbacksavepoint.failed",
814           new String JavaDoc[]{savepointName, String.valueOf(tm.getTransactionId()),
815           backend.getName(), e.getMessage()});
816       logger.fatal(msg, e);
817       throw new SQLException JavaDoc(msg);
818     }
819   }
820   
821   /**
822    * Release a savepoint from a transaction
823    *
824    * @param tm The transaction marker metadata
825    * @param name The name of the savepoint ro release
826    * @throws SQLException if an error occurs
827    */

828   public void releaseSavepoint(TransactionMarkerMetaData tm, String JavaDoc name)
829       throws SQLException JavaDoc
830   {
831     if (backend == null)
832       throw new SQLException JavaDoc("No available backend to release savepoint from "
833           + " transaction " + tm.getTransactionId());
834
835     try
836     {
837       AbstractConnectionManager cm = backend.getConnectionManager(
838           tm.getLogin());
839       Connection JavaDoc c = cm.retrieveConnection(tm.getTransactionId());
840
841       if (c == null)
842         throw new SQLException JavaDoc("No connection found for transaction "
843             + tm.getTransactionId());
844
845       Savepoint JavaDoc savepoint = backend.getSavepoint(new Long JavaDoc(
846           tm.getTransactionId()), name);
847       
848       if (savepoint == null)
849         throw new SQLException JavaDoc("No savepoint with name " + name + " has been "
850             + "found for transaction " + tm.getTransactionId());
851
852       try
853       {
854         c.releaseSavepoint(savepoint);
855       }
856       catch (SQLException JavaDoc e)
857       {
858         throw new SQLException JavaDoc(Translate.get(
859             "loadbalancer.releasesavepoint.failed", new String JavaDoc[]{name,
860                 String.valueOf(tm.getTransactionId()), backend.getName(),
861                 e.getMessage()}));
862       }
863       finally
864       {
865         backend.removeSavepoint(new Long JavaDoc(tm.getTransactionId()), savepoint);
866       }
867     }
868     catch (RuntimeException JavaDoc e)
869     {
870       String JavaDoc msg = Translate.get("loadbalancer.releasesavepoint.failed",
871           new String JavaDoc[]{name, String.valueOf(tm.getTransactionId()),
872               backend.getName(), e.getMessage()});
873       logger.fatal(msg, e);
874       throw new SQLException JavaDoc(msg);
875     }
876   }
877
878   /**
879    * Set a savepoint to a transaction.
880    *
881    * @param tm The transaction marker metadata
882    * @param name The name of the new savepoint
883    * @throws AllBackendsFailedException if no backend succeeded in setting the
884    * savepoint.
885    * @throws SQLException if an error occurs
886    */

887   public void setSavepoint(TransactionMarkerMetaData tm, String JavaDoc name)
888       throws AllBackendsFailedException, SQLException JavaDoc
889   {
890     if (backend == null)
891       throw new SQLException JavaDoc("No available backend to set savepoint to "
892           + " transaction " + tm.getTransactionId());
893
894     try
895     {
896       AbstractConnectionManager cm = backend
897           .getConnectionManager(tm.getLogin());
898       Connection JavaDoc c = cm.retrieveConnection(tm.getTransactionId());
899
900       if (c == null)
901         throw new SQLException JavaDoc("No connection found for transaction "
902             + tm.getTransactionId());
903
904       Savepoint JavaDoc savepoint = null;
905       try
906       {
907         savepoint = c.setSavepoint(name);
908       }
909       catch (SQLException JavaDoc e)
910       {
911         throw new SQLException JavaDoc(Translate.get(
912             "loadbalancer.setsavepoint.failed", new String JavaDoc[]{
913                 name, String.valueOf(tm.getTransactionId()), backend.getName(),
914                 e.getMessage()}));
915       }
916       finally
917       {
918         if (savepoint != null)
919           backend.addSavepoint(new Long JavaDoc(tm.getTransactionId()), savepoint);
920       }
921     }
922     catch (RuntimeException JavaDoc e)
923     {
924       String JavaDoc msg = Translate.get("loadbalancer.setsavepoint.failed",
925           new String JavaDoc[]{name, String.valueOf(tm.getTransactionId()),
926               backend.getName(), e.getMessage()});
927       logger.fatal(msg, e);
928       throw new SQLException JavaDoc(msg);
929     }
930   }
931
932   /*
933    * Backends management
934    */

935
936   /**
937    * Enables a backend that was previously disabled. Asks the corresponding
938    * connection manager to initialize the connections if needed.
939    *
940    * @param db the database backend to enable
941    * @param writeEnabled True if the backend must be enabled for writes
942    * @throws SQLException if an error occurs
943    */

944   public void enableBackend(DatabaseBackend db, boolean writeEnabled)
945       throws SQLException JavaDoc
946   {
947     if (backend != null)
948     {
949       if (backend.isReadEnabled())
950         throw new SQLException JavaDoc(
951             "SingleDB load balancer accepts only one backend and "
952                 + backend.getName() + " is already enabled. Skipping "
953                 + db.getName() + " initialization.");
954     }
955     backend = db;
956     logger.info(Translate.get("loadbalancer.backend.enabling", db.getName()));
957     if (!backend.isInitialized())
958       backend.initializeConnections();
959     backend.enableRead();
960     if (writeEnabled)
961       backend.enableWrite();
962   }
963
964   /**
965    * Disables a backend that was previously enabled. Asks the corresponding
966    * connection manager to finalize the connections if needed.
967    *
968    * @param db the database backend to disable
969    * @throws SQLException if an error occurs
970    */

971   public void disableBackend(DatabaseBackend db) throws SQLException JavaDoc
972   {
973     if (backend.equals(db))
974     {
975       logger
976           .info(Translate.get("loadbalancer.backend.disabling", db.getName()));
977       backend.disable();
978       if (backend.isInitialized())
979         backend.finalizeConnections();
980       backend = null;
981     }
982     else
983     {
984       String JavaDoc msg = "Trying to disable a non-existing backend " + db.getName();
985       logger.warn(msg);
986       throw new SQLException JavaDoc(msg);
987     }
988   }
989
990   /**
991    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#setWeight(String,
992    * int)
993    */

994   public void setWeight(String JavaDoc name, int w) throws SQLException JavaDoc
995   {
996     throw new SQLException JavaDoc("Weight is not supported with this load balancer");
997   }
998
999   /**
1000   * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#getNumberOfEnabledBackends()
1001   */

1002  public int getNumberOfEnabledBackends()
1003  {
1004    if (backend == null)
1005      return 0;
1006    else
1007      return 1;
1008  }
1009
1010  /*
1011   * Debug/Monitoring
1012   */

1013
1014  /**
1015   * Gets information about the request load balancer
1016   *
1017   * @return <code>String</code> containing information
1018   */

1019  public String JavaDoc getInformation()
1020  {
1021    if (backend == null)
1022      return "SingleDB Request load balancer: !!!Warning!!! No enabled backend node found\n";
1023    else
1024      return "SingleDB Request load balancer using " + backend.getURL() + "\n";
1025  }
1026
1027  /**
1028   * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#getXmlImpl()
1029   */

1030  public String JavaDoc getXmlImpl()
1031  {
1032    return "<" + DatabasesXmlTags.ELT_SingleDB + "/>";
1033  }
1034
1035}
Popular Tags