KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > loadbalancer > AbstractLoadBalancer


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;
26
27 import java.sql.CallableStatement JavaDoc;
28 import java.sql.Connection JavaDoc;
29 import java.sql.PreparedStatement JavaDoc;
30 import java.sql.SQLException JavaDoc;
31 import java.sql.Statement JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.LinkedList JavaDoc;
34
35 import javax.management.NotCompliantMBeanException JavaDoc;
36
37 import org.objectweb.cjdbc.common.exceptions.BadConnectionException;
38 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
39 import org.objectweb.cjdbc.common.i18n.Translate;
40 import org.objectweb.cjdbc.common.jmx.mbeans.AbstractLoadBalancerMBean;
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.SelectRequest;
45 import org.objectweb.cjdbc.common.sql.StoredProcedure;
46 import org.objectweb.cjdbc.common.sql.filters.MacrosHandler;
47 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
48 import org.objectweb.cjdbc.common.xml.XmlComponent;
49 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
50 import org.objectweb.cjdbc.controller.backend.DriverCompliance;
51 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
52 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager;
53 import org.objectweb.cjdbc.controller.jmx.AbstractStandardMBean;
54 import org.objectweb.cjdbc.controller.requestmanager.TransactionMarkerMetaData;
55 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
56 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
57
58 /**
59  * The Request Load Balancer should implement the load balancing of the requests
60  * among the backend nodes.
61  * <p>
62  * The requests comes from the Request Controller and are sent to the Connection
63  * Managers.
64  *
65  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
66  * @author <a HREF="mailto:vadim@kase.kz">Vadim Kassin </a>
67  * @author <a HREF="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
68  * @author <a HREF="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
69  * </a>
70  * @version 1.0
71  */

72 public abstract class AbstractLoadBalancer extends AbstractStandardMBean
73     implements
74       XmlComponent,
75       AbstractLoadBalancerMBean
76 {
77
78   //
79
// How the code is organized ?
80
//
81
// 1. Member variables/Constructor
82
// 2. Getter/Setter (possibly in alphabetical order)
83
// 3. Request handling
84
// 4. Transaction management
85
// 5. Backend management
86
// 6. Debug/Monitoring
87
//
88

89   // Virtual Database this load balancer is attached to.
90
protected VirtualDatabase vdb;
91   protected int raidbLevel;
92   protected int parsingGranularity;
93   /** Reference to distributed virtual database total order queue */
94   protected LinkedList JavaDoc totalOrderQueue;
95
96   protected static Trace logger = Trace
97                                        .getLogger("org.objectweb.cjdbc.controller.loadbalancer");
98
99   protected MacrosHandler macroHandler;
100
101   /**
102    * Generic constructor that sets some member variables and checks that
103    * backends are in the disabled state
104    *
105    * @param vdb The virtual database this load balancer belongs to
106    * @param raidbLevel The RAIDb level of this load balancer
107    * @param parsingGranularity The parsing granularity needed by this load
108    * balancer
109    */

110   protected AbstractLoadBalancer(VirtualDatabase vdb, int raidbLevel,
111       int parsingGranularity) throws SQLException JavaDoc, NotCompliantMBeanException JavaDoc
112   {
113     super(AbstractLoadBalancerMBean.class);
114     this.raidbLevel = raidbLevel;
115     this.parsingGranularity = parsingGranularity;
116     this.vdb = vdb;
117     this.totalOrderQueue = vdb.getTotalOrderQueue();
118     try
119     {
120       vdb.acquireReadLockBackendLists();
121     }
122     catch (InterruptedException JavaDoc e)
123     {
124       String JavaDoc msg = Translate.get(
125           "loadbalancer.backendlist.acquire.readlock.failed", e);
126       logger.error(msg);
127       throw new SQLException JavaDoc(msg);
128     }
129     int size = vdb.getBackends().size();
130     ArrayList JavaDoc backends = vdb.getBackends();
131     for (int i = 0; i < size; i++)
132     {
133       DatabaseBackend backend = (DatabaseBackend) backends.get(i);
134       if (backend.isReadEnabled() || backend.isWriteEnabled())
135       {
136         if (logger.isWarnEnabled())
137           logger.warn(Translate.get(
138               "loadbalancer.constructor.backends.not.disabled", backend
139                   .getName()));
140         try
141         {
142           disableBackend(backend);
143         }
144         catch (Exception JavaDoc e)
145         { // Set the disabled state anyway
146
backend.disable();
147         }
148       }
149     }
150     vdb.releaseReadLockBackendLists();
151   }
152
153   //
154
// Getter/Setter methods
155
//
156

157   /**
158    * Returns the RAIDbLevel.
159    *
160    * @return int the RAIDb level
161    */

162   public int getRAIDbLevel()
163   {
164     return raidbLevel;
165   }
166
167   /**
168    * Sets the RAIDbLevel.
169    *
170    * @param raidbLevel The RAIDb level to set
171    */

172   public void setRAIDbLevel(int raidbLevel)
173   {
174     this.raidbLevel = raidbLevel;
175   }
176
177   /**
178    * Get the needed query parsing granularity.
179    *
180    * @return needed query parsing granularity
181    */

182   public int getParsingGranularity()
183   {
184     return parsingGranularity;
185   }
186
187   /**
188    * Set the needed query parsing granularity.
189    *
190    * @param parsingGranularity the granularity to set
191    */

192   public void setParsingGranularity(int parsingGranularity)
193   {
194     this.parsingGranularity = parsingGranularity;
195   }
196
197   //
198
// Request Handling
199
//
200

201   /**
202    * Interprets the macros in the request (depending on the
203    * <code>MacroHandler</code> set for this class) and modify either the
204    * skeleton or the query itself. Note that the given object is directly
205    * modified.
206    *
207    * @param request the request to process
208    */

209   public void handleMacros(AbstractRequest request)
210   {
211     if (macroHandler == null)
212       return;
213
214     // Do not handle macros for requests of type: create, alter, drop and
215
// select.
216
if (!request.needsMacroProcessing())
217       return;
218
219     if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
220       request.setSQL(macroHandler.processMacros(request.getSQL()));
221     else
222       request.setSqlSkeleton(macroHandler.processMacros(request
223           .getSqlSkeleton()));
224   }
225
226   /**
227    * If we are executing in a distributed virtual database, we have to make sure
228    * that we post the query in the queue following the total order. This method
229    * does not remove the request from the total order queue. You have to call
230    * removeHeadFromAndNotifyTotalOrderQueue() to do so.
231    *
232    * @param request the request to wait for (can be any object but usually a
233    * DistributedRequest, Commit or Rollback)
234    * @param errorIfNotFound true if an error message should be logged if the
235    * request is not found in the total order queue
236    * @return true if the element was found and wait has succeeded, false
237    * otherwise
238    * @see #removeHeadFromAndNotifyTotalOrderQueue()
239    */

240   public boolean waitForTotalOrder(Object JavaDoc request, boolean errorIfNotFound)
241   {
242     if (totalOrderQueue != null)
243     {
244       synchronized (totalOrderQueue)
245       {
246         int index = totalOrderQueue.indexOf(request);
247         while (index > 0)
248         {
249           if (logger.isDebugEnabled())
250             logger.debug("Waiting for " + index
251                 + " queries to execute (current is " + totalOrderQueue.get(0)
252                 + ")");
253           try
254           {
255             totalOrderQueue.wait();
256           }
257           catch (InterruptedException JavaDoc ignore)
258           {
259           }
260           index = totalOrderQueue.indexOf(request);
261         }
262         if (index == -1)
263         {
264           if (errorIfNotFound)
265             logger
266                 .error("Request was not found in total order queue, posting out of order ("
267                     + request + ")");
268           return false;
269         }
270         else
271           return true;
272       }
273     }
274     return false;
275   }
276
277   /**
278    * Remove the first entry of the total order queue and notify the queue so
279    * that the next queries can be scheduled.
280    */

281   public void removeHeadFromAndNotifyTotalOrderQueue()
282   {
283     if (totalOrderQueue != null)
284     {
285       synchronized (totalOrderQueue)
286       {
287         totalOrderQueue.removeFirst();
288         totalOrderQueue.notifyAll();
289       }
290     }
291   }
292
293   /**
294    * Perform a read request. It is up to the implementation to choose to which
295    * backend node(s) this request should be sent.
296    *
297    * @param request an <code>SelectRequest</code>
298    * @param metadataCache MetadataCache (null if none)
299    * @return the corresponding <code>ControllerResultSet</code>
300    * @exception SQLException if an error occurs
301    */

302   public abstract ControllerResultSet execReadRequest(SelectRequest request,
303       MetadataCache metadataCache) throws SQLException JavaDoc;
304
305   /**
306    * Perform a write request. This request should usually be broadcasted to all
307    * nodes.
308    *
309    * @param request an <code>AbstractWriteRequest</code>
310    * @return number of rows affected by the request
311    * @throws AllBackendsFailedException if all backends failed to execute the
312    * request
313    * @exception SQLException if an error occurs
314    */

315   public abstract int execWriteRequest(AbstractWriteRequest request)
316       throws AllBackendsFailedException, SQLException JavaDoc;
317
318   /**
319    * Perform a write request and return a ResultSet containing the auto
320    * generated keys.
321    *
322    * @param request an <code>AbstractWriteRequest</code>
323    * @param metadataCache MetadataCache (null if none)
324    * @return auto generated keys
325    * @throws AllBackendsFailedException if all backends failed to execute the
326    * request
327    * @exception SQLException if an error occurs
328    */

329   public abstract ControllerResultSet execWriteRequestWithKeys(
330       AbstractWriteRequest request, MetadataCache metadataCache)
331       throws AllBackendsFailedException, SQLException JavaDoc;
332
333   /**
334    * Call a read-only stored procedure that returns a ResultSet. The stored
335    * procedure will be executed by one node only.
336    *
337    * @param proc the stored procedure call
338    * @param metadataCache MetadataCache (null if none)
339    * @return a <code>ControllerResultSet</code> value
340    * @exception SQLException if an error occurs
341    */

342   public abstract ControllerResultSet execReadOnlyReadStoredProcedure(
343       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc;
344
345   /**
346    * Call a stored procedure that returns a ResultSet. This stored procedure can
347    * possibly perform writes and will therefore be executed by all nodes.
348    *
349    * @param proc the stored procedure call
350    * @param metadataCache MetadataCache (null if none)
351    * @return a <code>ControllerResultSet</code> value
352    * @throws AllBackendsFailedException if all backends failed to execute the
353    * request
354    * @exception SQLException if an error occurs
355    */

356   public abstract ControllerResultSet execReadStoredProcedure(
357       StoredProcedure proc, MetadataCache metadataCache)
358       throws AllBackendsFailedException, SQLException JavaDoc;
359
360   /**
361    * Call a stored procedure that performs an update.
362    *
363    * @param proc the stored procedure call
364    * @return number of rows affected
365    * @throws AllBackendsFailedException if all backends failed to execute the
366    * request
367    * @throws SQLException if an error occurs
368    */

369   public abstract int execWriteStoredProcedure(StoredProcedure proc)
370       throws AllBackendsFailedException, SQLException JavaDoc;
371
372   /**
373    * Execute a statement on a backend. If the execution fails, the connection is
374    * checked for validity. If the connection was not valid, the query is
375    * automatically retried on a new connection.
376    *
377    * @param request the request to execute
378    * @param backend the backend on which the request is executed
379    * @param c connection used to create the statement
380    * @param metadataCache MetadataCache (null if none)
381    * @return the ControllerResultSet
382    * @throws SQLException if an error occurs
383    * @throws BadConnectionException if the connection was bad
384    */

385   public static final ControllerResultSet executeSelectRequestOnBackend(
386       SelectRequest request, DatabaseBackend backend, Connection JavaDoc c,
387       MetadataCache metadataCache) throws SQLException JavaDoc, BadConnectionException
388   {
389     ControllerResultSet rs = null;
390     try
391     {
392       backend.addPendingReadRequest(request);
393       String JavaDoc sql = request.getSQL();
394       // Rewrite the query if needed
395
sql = backend.rewriteQuery(sql);
396
397       Statement JavaDoc s; // Can also be used as a PreparedStatement
398
if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
399         s = c.createStatement();
400       else
401       {
402         s = c.prepareStatement(request.getSqlSkeleton());
403         org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(sql,
404             (PreparedStatement JavaDoc) s);
405       }
406
407       // Execute the query
408
DriverCompliance driverCompliance = backend.getDriverCompliance();
409       if (driverCompliance.supportSetQueryTimeout())
410         s.setQueryTimeout(request.getTimeout());
411       if ((request.getCursorName() != null)
412           && (driverCompliance.supportSetCursorName()))
413         s.setCursorName(request.getCursorName());
414       if ((request.getFetchSize() != 0)
415           && driverCompliance.supportSetFetchSize())
416         s.setFetchSize(request.getFetchSize());
417       if ((request.getMaxRows() > 0) && driverCompliance.supportSetMaxRows())
418         s.setMaxRows(request.getMaxRows());
419       if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
420         rs = new ControllerResultSet(request, s.executeQuery(sql),
421             metadataCache, s);
422       else
423         rs = new ControllerResultSet(request, ((PreparedStatement JavaDoc) s)
424             .executeQuery(), metadataCache, s);
425     }
426     catch (SQLException JavaDoc e)
427     { // Something bad happened
428
if (backend.isValidConnection(c))
429         throw e; // Connection is valid, throw the exception
430
else
431         throw new BadConnectionException(e);
432     }
433     finally
434     {
435       backend.removePendingRequest(request);
436     }
437     return rs;
438   }
439
440   /**
441    * Execute an update prepared statement on a backend. If the execution fails,
442    * the connection is checked for validity. If the connection was not valid,
443    * the query is automatically retried on a new connection.
444    *
445    * @param request the request to execute
446    * @param backend the backend on which the request is executed
447    * @param c connection used to create the statement
448    * @return int Number of rows effected
449    * @throws SQLException if an error occurs
450    * @throws BadConnectionException if the connection was bad
451    */

452   public static final int executeUpdateRequestOnBackend(
453       AbstractWriteRequest request, DatabaseBackend backend, Connection JavaDoc c)
454       throws SQLException JavaDoc, BadConnectionException
455   {
456     try
457     {
458       backend.addPendingWriteRequest(request);
459       String JavaDoc sql = request.getSQL();
460       // Rewrite the query if needed
461
sql = backend.rewriteQuery(sql);
462
463       Statement JavaDoc s; // Can also be used as a PreparedStatement
464
if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
465         s = c.createStatement();
466       else
467       {
468         s = c.prepareStatement(request.getSqlSkeleton());
469         org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(sql,
470             (PreparedStatement JavaDoc) s);
471       }
472
473       // Execute the query
474
DriverCompliance driverCompliance = backend.getDriverCompliance();
475       if (driverCompliance.supportSetQueryTimeout())
476         s.setQueryTimeout(request.getTimeout());
477
478       int rows = 0;
479       if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
480         rows = s.executeUpdate(sql);
481       else
482         rows = ((PreparedStatement JavaDoc) s).executeUpdate();
483
484       s.close();
485       return rows;
486     }
487     catch (SQLException JavaDoc e)
488     { // Something bad happened
489
if (backend.isValidConnection(c))
490         throw e; // Connection is valid, throw the exception
491
else
492         throw new BadConnectionException(e);
493     }
494     finally
495     {
496       backend.removePendingRequest(request);
497     }
498   }
499
500   /**
501    * Execute an update prepared statement on a backend. If the execution fails,
502    * the connection is checked for validity. If the connection was not valid,
503    * the query is automatically retried on a new connection.
504    *
505    * @param request the request to execute
506    * @param backend the backend on which the request is executed
507    * @param c connection used to create the statement
508    * @param metadataCache MetadataCache (null if none)
509    * @return ControllerResultSet containing the auto-generated keys
510    * @throws SQLException if an error occurs
511    * @throws BadConnectionException if the connection was bad
512    */

513   public static final ControllerResultSet executeUpdateRequestOnBackendWithKeys(
514       AbstractWriteRequest request, DatabaseBackend backend, Connection JavaDoc c,
515       MetadataCache metadataCache) throws SQLException JavaDoc, BadConnectionException
516   {
517     try
518     {
519       backend.addPendingWriteRequest(request);
520       String JavaDoc sql = request.getSQL();
521       // Rewrite the query if needed
522
sql = backend.rewriteQuery(sql);
523
524       Statement JavaDoc s = c.createStatement();
525
526       // Execute the query
527
DriverCompliance driverCompliance = backend.getDriverCompliance();
528       if (driverCompliance.supportSetQueryTimeout())
529         s.setQueryTimeout(request.getTimeout());
530       if (!driverCompliance.supportGetGeneratedKeys())
531         throw new SQLException JavaDoc("Backend " + backend.getName()
532             + " does not support RETURN_GENERATED_KEYS");
533
534       s.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
535       ControllerResultSet rs = new ControllerResultSet(request, s
536           .getGeneratedKeys(), metadataCache, s);
537       return rs;
538     }
539     catch (SQLException JavaDoc e)
540     { // Something bad happened
541
if (backend.isValidConnection(c))
542         throw e; // Connection is valid, throw the exception
543
else
544         throw new BadConnectionException(e);
545     }
546     finally
547     {
548       backend.removePendingRequest(request);
549     }
550   }
551
552   /**
553    * Execute a read stored procedure on the given backend. The callable
554    * statement is setXXX if the driver has not processed the statement.
555    *
556    * @param proc the stored procedure to execute
557    * @param backend the backend on which to execute the stored procedure
558    * @param c the connection on which to execute the stored procedure
559    * @param metadataCache the matedatacache to build the ControllerResultSet
560    * @return the controllerResultSet
561    * @throws SQLException if an error occurs
562    * @throws BadConnectionException if the connection was bad
563    */

564   public static final ControllerResultSet executeReadStoredProcedureOnBackend(
565       StoredProcedure proc, DatabaseBackend backend, Connection JavaDoc c,
566       MetadataCache metadataCache) throws SQLException JavaDoc, BadConnectionException
567   {
568     try
569     {
570       backend.addPendingReadRequest(proc);
571
572       // We suppose here that the request does not modify the schema since
573
// it is a read-only query.
574
CallableStatement JavaDoc cs;
575       if (proc.isDriverProcessed())
576         cs = c.prepareCall(proc.getSQL());
577       else
578       {
579         cs = c.prepareCall(proc.getSqlSkeleton());
580         org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(proc
581             .getSQL(), cs);
582       }
583       if (backend.getDriverCompliance().supportSetQueryTimeout())
584         cs.setQueryTimeout(proc.getTimeout());
585       if ((proc.getMaxRows() > 0)
586           && backend.getDriverCompliance().supportSetMaxRows())
587         cs.setMaxRows(proc.getMaxRows());
588       ControllerResultSet rs = new ControllerResultSet(proc, cs.executeQuery(),
589           metadataCache, cs);
590       return rs;
591     }
592     catch (SQLException JavaDoc e)
593     { // Something bad happened
594
if (backend.isValidConnection(c))
595         throw e; // Connection is valid, throw the exception
596
else
597         throw new BadConnectionException(e);
598     }
599     finally
600     {
601       backend.removePendingRequest(proc);
602     }
603   }
604
605   /**
606    * Execute a write stored procedure on the given backend. The callable
607    * statement is setXXX if the driver has not processed the statement.
608    *
609    * @param proc the stored procedure to execute
610    * @param backend the backend on which to execute the stored procedure
611    * @param c the connection on which to execute the stored procedure
612    * @return the number of updated rows
613    * @throws SQLException if an error occurs
614    * @throws BadConnectionException if the connection was bad
615    */

616   public static final int executeWriteStoredProcedureOnBackend(
617       StoredProcedure proc, DatabaseBackend backend, Connection JavaDoc c)
618       throws SQLException JavaDoc, BadConnectionException
619   {
620     try
621     {
622       backend.addPendingWriteRequest(proc);
623
624       // We suppose here that the request does not modify the schema since
625
// it is a read-only query.
626
CallableStatement JavaDoc cs;
627       if (proc.isDriverProcessed())
628         cs = c.prepareCall(proc.getSQL());
629       else
630       {
631         cs = c.prepareCall(proc.getSqlSkeleton());
632         org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(proc
633             .getSQL(), cs);
634       }
635       if (backend.getDriverCompliance().supportSetQueryTimeout())
636         cs.setQueryTimeout(proc.getTimeout());
637       if ((proc.getMaxRows() > 0)
638           && backend.getDriverCompliance().supportSetMaxRows())
639         cs.setMaxRows(proc.getMaxRows());
640       int rows = cs.executeUpdate();
641       cs.close();
642       return rows;
643     }
644     catch (SQLException JavaDoc e)
645     { // Something bad happened
646
if (backend.isValidConnection(c))
647         throw e; // Connection is valid, throw the exception
648
else
649         throw new BadConnectionException(e);
650     }
651     finally
652     {
653       backend.removePendingRequest(proc);
654     }
655   }
656
657   //
658
// Transaction management
659
//
660

661   /**
662    * Begin a new transaction.
663    *
664    * @param tm The transaction marker metadata
665    * @throws SQLException if an error occurs
666    */

667   public abstract void begin(TransactionMarkerMetaData tm) throws SQLException JavaDoc;
668
669   /**
670    * Commit a transaction.
671    *
672    * @param tm The transaction marker metadata
673    * @throws AllBackendsFailedException if all backends failed to execute the
674    * request
675    * @throws SQLException if an error occurs
676    */

677   public abstract void commit(TransactionMarkerMetaData tm)
678       throws AllBackendsFailedException, SQLException JavaDoc;
679
680   /**
681    * Rollback a transaction.
682    *
683    * @param tm The transaction marker metadata
684    * @throws AllBackendsFailedException if all backends failed to execute the
685    * request
686    * @throws SQLException if an error occurs
687    */

688   public abstract void rollback(TransactionMarkerMetaData tm)
689       throws AllBackendsFailedException, SQLException JavaDoc;
690
691   /**
692    * Rollback a transaction to a savepoint
693    *
694    * @param tm The transaction marker metadata
695    * @param savepointName The name of the savepoint
696    * @throws AllBackendsFailedException if all backends failed to execute the
697    * request
698    * @throws SQLException if an error occurs
699    */

700   public abstract void rollback(TransactionMarkerMetaData tm,
701       String JavaDoc savepointName) throws AllBackendsFailedException, SQLException JavaDoc;
702
703   /**
704    * Set a savepoint to a transaction.
705    *
706    * @param tm The transaction marker metadata
707    * @param name The name of the new savepoint
708    * @throws AllBackendsFailedException if all backends failed to execute the
709    * request
710    * @throws SQLException if an error occurs
711    */

712   public abstract void setSavepoint(TransactionMarkerMetaData tm, String JavaDoc name)
713       throws AllBackendsFailedException, SQLException JavaDoc;
714
715   /**
716    * Release a savepoint from a transaction
717    *
718    * @param tm The transaction marker metadata
719    * @param name The name of the savepoint ro release
720    * @throws AllBackendsFailedException if all backends failed to execute the
721    * request
722    * @throws SQLException if an error occurs
723    */

724   public abstract void releaseSavepoint(TransactionMarkerMetaData tm,
725       String JavaDoc name) throws AllBackendsFailedException, SQLException JavaDoc;
726
727   /**
728    * Factorized code to start a transaction on a backend and to retrieve a
729    * connection on this backend
730    *
731    * @param backend the backend needed to check valid connection against this
732    * backend test statement
733    * @param cm the connection manager to use to retrieve connections
734    * @param tid the id of the transaction to start
735    * @param transactionIsolationLevel transaction isolation level to use for a
736    * new transaction (does nothing if equals to
737    * Connection.DEFAULT_TRANSACTION_ISOLATION_LEVEL)
738    * @return a valid connection with a started transaction
739    * @throws SQLException if the backend is valid but set autocommit cannot be
740    * set to false
741    * @throws UnreachableBackendException if the backend is not reachable, ie not
742    * valid connection can be retrieved
743    * @see org.objectweb.cjdbc.driver.Connection#DEFAULT_TRANSACTION_ISOLATION_LEVEL
744    */

745   public static final Connection JavaDoc getConnectionAndBeginTransaction(
746       DatabaseBackend backend, AbstractConnectionManager cm, long tid,
747       int transactionIsolationLevel) throws SQLException JavaDoc,
748       UnreachableBackendException
749   {
750     Connection JavaDoc c = null;
751     boolean isConnectionValid = false;
752     do
753     {
754       c = cm.getConnection(tid);
755
756       // Sanity check
757
if (c == null)
758         throw new UnreachableBackendException(Translate.get(
759             "loadbalancer.unable.get.connection", new String JavaDoc[]{
760                 String.valueOf(tid), backend.getName()}));
761       try
762       {
763         if (transactionIsolationLevel != org.objectweb.cjdbc.driver.Connection.DEFAULT_TRANSACTION_ISOLATION_LEVEL)
764           c.setTransactionIsolation(transactionIsolationLevel);
765         c.setAutoCommit(false);
766         isConnectionValid = true;
767       }
768       catch (SQLException JavaDoc e)
769       {
770         if (backend.isValidConnection(c))
771           throw e; // Connection is valid, throw the exception
772
else
773         {
774           cm.deleteConnection(tid);
775         }
776       }
777     }
778     while (!isConnectionValid);
779     return c;
780   }
781
782   //
783
// Backends management
784
//
785

786   /**
787    * Enable a backend without further check. The backend is at least read
788    * enabled but could also be enabled for writes. Ask the corresponding
789    * connection manager to initialize the connections if needed.
790    *
791    * @param db The database backend to enable
792    * @param writeEnabled True if the backend must be enabled for writes
793    * @throws SQLException if an error occurs
794    */

795   public abstract void enableBackend(DatabaseBackend db, boolean writeEnabled)
796       throws SQLException JavaDoc;
797
798   /**
799    * Disable a backend without further check. Ask the corresponding connection
800    * manager to finalize the connections if needed. This method should not be
801    * called directly but instead should access the
802    * <code>RequestManager.disableBackeknd(...)</code> method.
803    *
804    * @param db The database backend to disable
805    * @throws SQLException if an error occurs
806    */

807   public abstract void disableBackend(DatabaseBackend db) throws SQLException JavaDoc;
808
809   /**
810    * Get the number of currently enabled backends. 0 means that no backend is
811    * available.
812    *
813    * @return number of currently enabled backends
814    */

815   public abstract int getNumberOfEnabledBackends();
816
817   /**
818    * Associate a weight to a backend identified by its logical name.
819    *
820    * @param name the backend name
821    * @param w the weight
822    * @throws SQLException if an error occurs
823    */

824   public void setWeight(String JavaDoc name, int w) throws SQLException JavaDoc
825   {
826     throw new SQLException JavaDoc("Weight is not supported by this load balancer");
827   }
828
829   //
830
// Debug/Monitoring
831
//
832

833   /**
834    * Get information about the Request Load Balancer
835    *
836    * @return <code>String</code> containing information
837    */

838   public abstract String JavaDoc getInformation();
839
840   /**
841    * Get information about the Request Load Balancer in xml
842    *
843    * @return <code>String</code> containing information, xml formatted
844    */

845   public abstract String JavaDoc getXmlImpl();
846
847   /**
848    * This sets the macro handler for this load balancer. Handling macros
849    * prevents different backends to generate different values when interpreting
850    * the macros which could result in data inconsitencies.
851    *
852    * @param handler <code>MacrosHandler</code> instance
853    */

854   public void setMacroHandler(MacrosHandler handler)
855   {
856     this.macroHandler = handler;
857   }
858
859   /**
860    * @see org.objectweb.cjdbc.common.xml.XmlComponent#getXml()
861    */

862   public String JavaDoc getXml()
863   {
864     StringBuffer JavaDoc info = new StringBuffer JavaDoc();
865     info.append("<" + DatabasesXmlTags.ELT_LoadBalancer + ">");
866     info.append(getXmlImpl());
867     info.append("</" + DatabasesXmlTags.ELT_LoadBalancer + ">");
868     return info.toString();
869   }
870
871   /**
872    * @see org.objectweb.cjdbc.controller.jmx.AbstractStandardMBean#getAssociatedString()
873    */

874   public String JavaDoc getAssociatedString()
875   {
876     return "loadbalancer";
877   }
878 }
879
Popular Tags