Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

SingleDB.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet.
00022  * Contributor(s): Vadim Kassin, Jaco Swart.
00023  */
00024 
00025 package org.objectweb.cjdbc.controller.loadbalancer.singledb;
00026 
00027 import java.sql.Connection;
00028 import java.sql.SQLException;
00029 
00030 import org.objectweb.cjdbc.common.exceptions.BadConnectionException;
00031 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
00032 import org.objectweb.cjdbc.common.i18n.Translate;
00033 import org.objectweb.cjdbc.common.log.Trace;
00034 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
00035 import org.objectweb.cjdbc.common.sql.ParsingGranularities;
00036 import org.objectweb.cjdbc.common.sql.SelectRequest;
00037 import org.objectweb.cjdbc.common.sql.StoredProcedure;
00038 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00039 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00040 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
00041 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager;
00042 import org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer;
00043 import org.objectweb.cjdbc.controller.requestmanager.RAIDbLevels;
00044 import org.objectweb.cjdbc.controller.requestmanager.TransactionMarkerMetaData;
00045 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
00046 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
00047 
00048 /**
00049  * Single Database request load balancer.
00050  * <p>
00051  * The requests coming from the request controller are directly forwarded to the
00052  * single backend. This load balancer does not support multiple backends.
00053  * 
00054  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00055  * @author <a href="mailto:vadim@kase.kz">Vadim Kassin </a>
00056  * @author <a href="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
00057  * @version 1.0
00058  */
00059 public class SingleDB extends AbstractLoadBalancer
00060 {
00061   /*
00062    * How the code is organized ? 1. Member variables 2. Constructor(s) 3.
00063    * Request handling 4. Transaction handling 5. Backend management 6.
00064    * Debug/Monitoring
00065    */
00066 
00067   private DatabaseBackend backend;
00068 
00069   private static Trace    logger = Trace
00070                                      .getLogger("org.objectweb.cjdbc.controller.loadbalancer.SingleDB");
00071 
00072   /*
00073    * Constructors
00074    */
00075 
00076   /**
00077    * Creates a new <code>SingleDB</code> instance.
00078    * 
00079    * @param vdb the <code>VirtualDatabase</code> this load balancer belongs to
00080    * @throws Exception if there is not exactly one backend attached to the
00081    *           <code>VirtualDatabase</code>
00082    */
00083   public SingleDB(VirtualDatabase vdb) throws Exception
00084   {
00085     // We don't need to parse the requests, just send them to the backend
00086     super(vdb, RAIDbLevels.SingleDB, ParsingGranularities.NO_PARSING);
00087   }
00088 
00089   /*
00090    * Request Handling
00091    */
00092 
00093   /**
00094    * Performs a read request. It is up to the implementation to choose to which
00095    * backend node(s) this request should be sent.
00096    * 
00097    * @param request an <code>SelectRequest</code>
00098    * @param metadataCache MetadataCache (null if none)
00099    * @return the corresponding <code>java.sql.ResultSet</code>
00100    * @exception SQLException if an error occurs
00101    */
00102   public ControllerResultSet execReadRequest(SelectRequest request,
00103       MetadataCache metadataCache) throws SQLException
00104   {
00105     if (backend == null)
00106       throw new SQLException(Translate.get(
00107           "loadbalancer.execute.no.backend.available", request.getId()));
00108 
00109     try
00110     {
00111       AbstractConnectionManager cm = backend.getConnectionManager(request
00112           .getLogin());
00113       if (request.isAutoCommit())
00114       {
00115         ControllerResultSet rs = null;
00116         boolean badConnection;
00117         do
00118         {
00119           badConnection = false;
00120           // Use a connection just for this request
00121           Connection c = null;
00122           try
00123           {
00124             c = cm.getConnection();
00125           }
00126           catch (UnreachableBackendException e1)
00127           {
00128             String backendName = backend.getName();
00129             logger.error(Translate.get(
00130                 "loadbalancer.backend.disabling.unreachable", backendName));
00131             disableBackend(backend);
00132             backend = null;
00133             throw new SQLException(Translate.get(
00134                 "loadbalancer.backend.unreacheable", backendName));
00135           }
00136 
00137           // Sanity check
00138           if (c == null)
00139             throw new SQLException(Translate.get(
00140                 "loadbalancer.backend.no.connection", backend.getName()));
00141 
00142           // Execute Query
00143           try
00144           {
00145             rs = executeSelectRequestOnBackend(request, backend, c,
00146                 metadataCache);
00147             cm.releaseConnection(c);
00148           }
00149           catch (SQLException e)
00150           {
00151             cm.releaseConnection(c);
00152             throw new SQLException(Translate.get(
00153                 "loadbalancer.request.failed.on.backend", new String[]{
00154                     request.getSQLShortForm(vdb.getSQLShortFormLength()),
00155                     backend.getName(), e.getMessage()}));
00156           }
00157           catch (BadConnectionException e)
00158           { // Get rid of the bad connection
00159             cm.deleteConnection(c);
00160             badConnection = true;
00161           }
00162         }
00163         while (badConnection);
00164         return rs;
00165       }
00166       else
00167       {
00168         long tid = request.getTransactionId();
00169         // Re-use the connection used by this transaction
00170         Connection c = cm.retrieveConnection(tid);
00171 
00172         // Sanity check
00173         if (c == null)
00174           throw new SQLException(Translate.get(
00175               "loadbalancer.unable.retrieve.connection", new String[]{
00176                   String.valueOf(tid), backend.getName()}));
00177 
00178         // Execute Query
00179         ControllerResultSet rs = null;
00180         try
00181         {
00182           rs = executeSelectRequestOnBackend(request, backend, c, metadataCache);
00183         }
00184         catch (SQLException e)
00185         {
00186           throw new SQLException(Translate.get(
00187               "loadbalancer.request.failed.on.backend", new String[]{
00188                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
00189                   backend.getName(), e.getMessage()}));
00190         }
00191         catch (BadConnectionException e)
00192         { // Get rid of the bad connection
00193           cm.deleteConnection(tid);
00194           throw new SQLException(Translate.get(
00195               "loadbalancer.connection.failed", new String[]{
00196                   String.valueOf(tid), backend.getName(), e.getMessage()}));
00197         }
00198         return rs;
00199       }
00200     }
00201     catch (RuntimeException e)
00202     {
00203       String msg = "Request '"
00204           + request.getSQLShortForm(vdb.getSQLShortFormLength())
00205           + "' failed on backend " + backend.getURL() + " (" + e + ")";
00206       logger.fatal(msg, e);
00207       throw new SQLException(msg);
00208     }
00209   }
00210 
00211   /**
00212    * Performs a write request on the backend.
00213    * 
00214    * @param request an <code>AbstractWriteRequest</code>
00215    * @return number of rows affected by the request
00216    * @exception SQLException if an error occurs
00217    */
00218   public int execWriteRequest(AbstractWriteRequest request) throws SQLException
00219   {
00220     if (backend == null)
00221       throw new SQLException(Translate.get(
00222           "loadbalancer.execute.no.backend.available", request.getId()));
00223 
00224     try
00225     {
00226       AbstractConnectionManager cm = backend.getConnectionManager(request
00227           .getLogin());
00228       if (request.isAutoCommit())
00229       {
00230         // We do not execute request outside the already open transactions if we
00231         // are disabling the backend.
00232         if (backend.isDisabling())
00233           throw new SQLException(Translate.get(
00234               "loadbalancer.backend.is.disabling", new String[]{
00235                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
00236                   backend.getName()}));
00237 
00238         // Use a connection just for this request
00239         Connection c = null;
00240         try
00241         {
00242           c = cm.getConnection();
00243         }
00244         catch (UnreachableBackendException e1)
00245         {
00246           String backendName = backend.getName();
00247           logger.error(Translate.get(
00248               "loadbalancer.backend.disabling.unreachable", backendName));
00249           disableBackend(backend);
00250           backend = null;
00251           throw new SQLException(Translate.get(
00252               "loadbalancer.backend.unreacheable", backendName));
00253         }
00254 
00255         // Sanity check
00256         if (c == null)
00257           throw new SQLException(Translate.get(
00258               "loadbalancer.backend.no.connection", backend.getName()));
00259 
00260         // Execute Query
00261         int result;
00262         try
00263         {
00264           result = executeUpdateRequestOnBackend(request, backend, c);
00265         }
00266         catch (Exception e)
00267         {
00268           throw new SQLException(Translate.get(
00269               "loadbalancer.request.failed.on.backend", new String[]{
00270                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
00271                   backend.getName(), e.getMessage()}));
00272         }
00273         finally
00274         {
00275           cm.releaseConnection(c);
00276         }
00277         return result;
00278       }
00279       else
00280       { // Re-use the connection used by this transaction
00281         Connection c = cm.retrieveConnection(request.getTransactionId());
00282 
00283         // Sanity check
00284         if (c == null)
00285           throw new SQLException(Translate.get(
00286               "loadbalancer.unable.retrieve.connection",
00287               new String[]{String.valueOf(request.getTransactionId()),
00288                   backend.getName()}));
00289 
00290         // Execute Query
00291         try
00292         {
00293           return executeUpdateRequestOnBackend(request, backend, c);
00294         }
00295         catch (Exception e)
00296         {
00297           throw new SQLException(Translate.get(
00298               "loadbalancer.request.failed.on.backend", new String[]{
00299                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
00300                   backend.getName(), e.getMessage()}));
00301         }
00302       }
00303     }
00304     catch (RuntimeException e)
00305     {
00306       String msg = Translate.get("loadbalancer.request.failed.on.backend",
00307           new String[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
00308               backend.getName(), e.getMessage()});
00309       logger.fatal(msg, e);
00310       throw new SQLException(msg);
00311     }
00312   }
00313 
00314   /**
00315    * @see AbstractLoadBalancer#execWriteRequestWithKeys(AbstractWriteRequest,
00316    *      MetadataCache)
00317    */
00318   public ControllerResultSet execWriteRequestWithKeys(
00319       AbstractWriteRequest request, MetadataCache metadataCache)
00320       throws SQLException
00321   {
00322     if (backend == null)
00323       throw new SQLException(Translate.get(
00324           "loadbalancer.execute.no.backend.available", request.getId()));
00325 
00326     if (!backend.getDriverCompliance().supportGetGeneratedKeys())
00327       throw new SQLException(Translate.get(
00328           "loadbalancer.backend.autogeneratedkeys.unsupported", backend
00329               .getName()));
00330 
00331     try
00332     {
00333       AbstractConnectionManager cm = backend.getConnectionManager(request
00334           .getLogin());
00335       if (request.isAutoCommit())
00336       {
00337         // We do not execute request outside the already open transactions if we
00338         // are disabling the backend.
00339         if (backend.isDisabling())
00340           throw new SQLException(Translate.get(
00341               "loadbalancer.backend.is.disabling", new String[]{
00342                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
00343                   backend.getName()}));
00344 
00345         // Use a connection just for this request
00346         Connection c = null;
00347         try
00348         {
00349           c = cm.getConnection();
00350         }
00351         catch (UnreachableBackendException e1)
00352         {
00353           String backendName = backend.getName();
00354           logger.error(Translate.get(
00355               "loadbalancer.backend.disabling.unreachable", backendName));
00356           disableBackend(backend);
00357           backend = null;
00358           throw new SQLException(Translate.get(
00359               "loadbalancer.backend.unreacheable", backendName));
00360         }
00361 
00362         // Sanity check
00363         if (c == null)
00364           throw new SQLException(Translate.get(
00365               "loadbalancer.backend.no.connection", backend.getName()));
00366 
00367         // Execute Query
00368         ControllerResultSet result;
00369         try
00370         {
00371           result = executeUpdateRequestOnBackendWithKeys(request, backend, c,
00372               metadataCache);
00373         }
00374         catch (Exception e)
00375         {
00376           throw new SQLException(Translate.get(
00377               "loadbalancer.request.failed.on.backend", new String[]{
00378                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
00379                   backend.getName(), e.getMessage()}));
00380         }
00381         finally
00382         {
00383           cm.releaseConnection(c);
00384         }
00385         return result;
00386       }
00387       else
00388       {
00389         // Re-use the connection used by this transaction
00390         Connection c = cm.retrieveConnection(request.getTransactionId());
00391 
00392         // Sanity check
00393         if (c == null)
00394           throw new SQLException(Translate.get(
00395               "loadbalancer.unable.retrieve.connection",
00396               new String[]{String.valueOf(request.getTransactionId()),
00397                   backend.getName()}));
00398 
00399         // Execute Query
00400         try
00401         {
00402           return executeUpdateRequestOnBackendWithKeys(request, backend, c,
00403               metadataCache);
00404         }
00405         catch (Exception e)
00406         {
00407           throw new SQLException(Translate.get(
00408               "loadbalancer.request.failed.on.backend", new String[]{
00409                   request.getSQLShortForm(vdb.getSQLShortFormLength()),
00410                   backend.getName(), e.getMessage()}));
00411         }
00412         finally
00413         {
00414           backend.removePendingRequest(request);
00415         }
00416       }
00417     }
00418     catch (RuntimeException e)
00419     {
00420       String msg = Translate.get("loadbalancer.request.failed.on.backend",
00421           new String[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
00422               backend.getName(), e.getMessage()});
00423       logger.fatal(msg, e);
00424       throw new SQLException(msg);
00425     }
00426   }
00427 
00428   /**
00429    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#execReadOnlyReadStoredProcedure(StoredProcedure,
00430    *      MetadataCache)
00431    */
00432   public ControllerResultSet execReadOnlyReadStoredProcedure(
00433       StoredProcedure proc, MetadataCache metadataCache) throws SQLException
00434   {
00435     return execReadStoredProcedure(proc, metadataCache);
00436   }
00437 
00438   /**
00439    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#execReadStoredProcedure(StoredProcedure,
00440    *      MetadataCache)
00441    */
00442   public ControllerResultSet execReadStoredProcedure(StoredProcedure proc,
00443       MetadataCache metadataCache) throws SQLException
00444   {
00445     if (backend == null)
00446       throw new SQLException(
00447           "No available backend to execute stored procedure " + proc.getId());
00448 
00449     try
00450     {
00451       AbstractConnectionManager cm = backend.getConnectionManager(proc
00452           .getLogin());
00453       if (proc.isAutoCommit())
00454       { // Use a connection just for this request
00455         Connection c = null;
00456         try
00457         {
00458           c = cm.getConnection();
00459         }
00460         catch (UnreachableBackendException e1)
00461         {
00462           String backendName = backend.getName();
00463           logger.error(Translate.get(
00464               "loadbalancer.backend.disabling.unreachable", backendName));
00465           disableBackend(backend);
00466           backend = null;
00467           throw new SQLException(Translate.get(
00468               "loadbalancer.backend.unreacheable", backendName));
00469         }
00470 
00471         // Sanity check
00472         if (c == null)
00473           throw new SQLException(Translate.get(
00474               "loadbalancer.backend.no.connection", backend.getName()));
00475 
00476         // Execute Query
00477         ControllerResultSet rs = null;
00478         try
00479         {
00480           rs = AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
00481               backend, c, metadataCache);
00482         }
00483         catch (Exception e)
00484         {
00485           throw new SQLException(Translate.get(
00486               "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00487                   proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00488                   backend.getName(), e.getMessage()}));
00489         }
00490         finally
00491         {
00492           cm.releaseConnection(c);
00493         }
00494         return rs;
00495       }
00496       else
00497       { // Re-use the connection used by this transaction
00498         Connection c = cm.retrieveConnection(proc.getTransactionId());
00499 
00500         // Sanity check
00501         if (c == null)
00502           throw new SQLException(Translate.get(
00503               "loadbalancer.unable.retrieve.connection", new String[]{
00504                   String.valueOf(proc.getTransactionId()), backend.getName()}));
00505 
00506         // Execute Query
00507         try
00508         {
00509           return AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
00510               backend, c, metadataCache);
00511         }
00512         catch (Exception e)
00513         {
00514           throw new SQLException(Translate.get(
00515               "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00516                   proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00517                   backend.getName(), e.getMessage()}));
00518         }
00519       }
00520     }
00521     catch (RuntimeException e)
00522     {
00523       String msg = Translate.get(
00524           "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00525               proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00526               backend.getName(), e.getMessage()});
00527       logger.fatal(msg, e);
00528       throw new SQLException(msg);
00529     }
00530   }
00531 
00532   /**
00533    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#execWriteStoredProcedure(org.objectweb.cjdbc.common.sql.StoredProcedure)
00534    */
00535   public int execWriteStoredProcedure(StoredProcedure proc) throws SQLException
00536   {
00537     if (backend == null)
00538       throw new SQLException(
00539           "No available backend to execute stored procedure " + proc.getId());
00540 
00541     try
00542     {
00543       AbstractConnectionManager cm = backend.getConnectionManager(proc
00544           .getLogin());
00545       if (proc.isAutoCommit())
00546       { // Use a connection just for this request
00547         Connection c = null;
00548         try
00549         {
00550           c = cm.getConnection();
00551         }
00552         catch (UnreachableBackendException e1)
00553         {
00554           String backendName = backend.getName();
00555           logger.error(Translate.get(
00556               "loadbalancer.backend.disabling.unreachable", backendName));
00557           disableBackend(backend);
00558           backend = null;
00559           throw new SQLException(Translate.get(
00560               "loadbalancer.backend.unreacheable", backendName));
00561         }
00562 
00563         // Sanity check
00564         if (c == null)
00565           throw new SQLException(Translate.get(
00566               "loadbalancer.backend.no.connection", backend.getName()));
00567 
00568         // Execute Query
00569         int result;
00570         try
00571         {
00572           result = AbstractLoadBalancer.executeWriteStoredProcedureOnBackend(
00573               proc, backend, c);
00574         }
00575         catch (Exception e)
00576         {
00577           throw new SQLException(Translate.get(
00578               "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00579                   proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00580                   backend.getName(), e.getMessage()}));
00581         }
00582         finally
00583         {
00584           cm.releaseConnection(c);
00585         }
00586         return result;
00587       }
00588       else
00589       { // Re-use the connection used by this transaction
00590         Connection c = cm.retrieveConnection(proc.getTransactionId());
00591 
00592         // Sanity check
00593         if (c == null)
00594           throw new SQLException(Translate.get(
00595               "loadbalancer.unable.retrieve.connection", new String[]{
00596                   String.valueOf(proc.getTransactionId()), backend.getName()}));
00597 
00598         // Execute Query
00599         try
00600         {
00601           return AbstractLoadBalancer.executeWriteStoredProcedureOnBackend(
00602               proc, backend, c);
00603         }
00604         catch (Exception e)
00605         {
00606           throw new SQLException(Translate.get(
00607               "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00608                   proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00609                   backend.getName(), e.getMessage()}));
00610         }
00611       }
00612     }
00613     catch (RuntimeException e)
00614     {
00615       String msg = Translate.get(
00616           "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00617               proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00618               backend.getName(), e.getMessage()});
00619       logger.fatal(msg, e);
00620       throw new SQLException(msg);
00621     }
00622   }
00623 
00624   /*
00625    * Transaction management
00626    */
00627 
00628   /**
00629    * Begins a new transaction.
00630    * 
00631    * @param tm the transaction marker metadata
00632    * @exception SQLException if an error occurs
00633    */
00634   public void begin(TransactionMarkerMetaData tm) throws SQLException
00635   {
00636     if (backend == null)
00637       throw new SQLException("No available backend to begin transaction "
00638           + tm.getTransactionId());
00639 
00640     // We do not accept new transactions if we are disabling the backend
00641     if (backend.isDisabling())
00642       throw new SQLException(Translate.get("loadbalancer.backend.is.disabling",
00643           new String[]{"begin transaction " + tm.getTransactionId(),
00644               backend.getName()}));
00645 
00646     try
00647     {
00648       Connection c = backend.getConnectionManager(tm.getLogin()).getConnection(
00649           tm.getTransactionId());
00650 
00651       if (c == null)
00652         throw new SQLException(Translate.get(
00653             "loadbalancer.backend.no.connection", backend.getName()));
00654 
00655       c.setAutoCommit(false);
00656     }
00657     catch (Exception e)
00658     {
00659       throw new SQLException("Begin of transaction " + tm.getTransactionId()
00660           + " failed on backend " + backend.getURL() + " (" + e + ")");
00661     }
00662   }
00663 
00664   /**
00665    * Commits a transaction.
00666    * 
00667    * @param tm the transaction marker metadata
00668    * @exception SQLException if an error occurs
00669    */
00670   public void commit(TransactionMarkerMetaData tm) throws SQLException
00671   {
00672     if (backend == null)
00673       throw new SQLException("No available backend to commit transaction "
00674           + tm.getTransactionId());
00675 
00676     try
00677     {
00678       AbstractConnectionManager cm = backend
00679           .getConnectionManager(tm.getLogin());
00680       Connection c = cm.retrieveConnection(tm.getTransactionId());
00681 
00682       if (c == null)
00683         throw new SQLException("No connection found for transaction "
00684             + tm.getTransactionId());
00685 
00686       try
00687       {
00688         c.commit();
00689         c.setAutoCommit(true);
00690       }
00691       catch (SQLException e)
00692       {
00693         throw new SQLException(Translate.get("loadbalancer.commit.failed",
00694             new String[]{String.valueOf(tm.getTransactionId()),
00695                 backend.getName(), e.getMessage()}));
00696       }
00697       finally
00698       {
00699         cm.releaseConnection(tm.getTransactionId());
00700       }
00701     }
00702     catch (RuntimeException e)
00703     {
00704       String msg = Translate.get("loadbalancer.commit.failed", new String[]{
00705           String.valueOf(tm.getTransactionId()), backend.getName(),
00706           e.getMessage()});
00707       logger.fatal(msg, e);
00708       throw new SQLException(msg);
00709     }
00710   }
00711 
00712   /**
00713    * Rollbacks a transaction.
00714    * 
00715    * @param tm the transaction marker metadata
00716    * @exception SQLException if an error occurs
00717    */
00718   public void rollback(TransactionMarkerMetaData tm) throws SQLException
00719   {
00720     if (backend == null)
00721       throw new SQLException("No available backend to rollback transaction "
00722           + tm.getTransactionId());
00723 
00724     try
00725     {
00726       AbstractConnectionManager cm = backend
00727           .getConnectionManager(tm.getLogin());
00728       Connection c = cm.retrieveConnection(tm.getTransactionId());
00729 
00730       if (c == null)
00731         throw new SQLException("No connection found for transaction "
00732             + tm.getTransactionId());
00733 
00734       try
00735       {
00736         c.rollback();
00737         c.setAutoCommit(true);
00738       }
00739       catch (SQLException e)
00740       {
00741         throw new SQLException(Translate.get("loadbalancer.rollback.failed",
00742             new String[]{String.valueOf(tm.getTransactionId()),
00743                 backend.getName(), e.getMessage()}));
00744       }
00745       finally
00746       {
00747         cm.releaseConnection(tm.getTransactionId());
00748       }
00749     }
00750     catch (RuntimeException e)
00751     {
00752       String msg = Translate.get("loadbalancer.rollback.failed", new String[]{
00753           String.valueOf(tm.getTransactionId()), backend.getName(),
00754           e.getMessage()});
00755       logger.fatal(msg, e);
00756       throw new SQLException(msg);
00757     }
00758   }
00759 
00760   /*
00761    * Backends management
00762    */
00763 
00764   /**
00765    * Enables a backend that was previously disabled. Asks the corresponding
00766    * connection manager to initialize the connections if needed.
00767    * 
00768    * @param db the database backend to enable
00769    * @param writeEnabled True if the backend must be enabled for writes
00770    * @throws SQLException if an error occurs
00771    */
00772   public void enableBackend(DatabaseBackend db, boolean writeEnabled)
00773       throws SQLException
00774   {
00775     if (backend != null)
00776     {
00777       if (backend.isReadEnabled())
00778         throw new SQLException(
00779             "SingleDB load balancer accepts only one backend and "
00780                 + backend.getName() + " is already enabled. Skipping "
00781                 + db.getName() + " initialization.");
00782     }
00783     backend = db;
00784     logger.info(Translate.get("loadbalancer.backend.enabling", db.getName()));
00785     if (!backend.isInitialized())
00786       backend.initializeConnections();
00787     backend.enableRead();
00788     if (writeEnabled)
00789       backend.enableWrite();
00790   }
00791 
00792   /**
00793    * Disables a backend that was previously enabled. Asks the corresponding
00794    * connection manager to finalize the connections if needed.
00795    * 
00796    * @param db the database backend to disable
00797    * @throws SQLException if an error occurs
00798    */
00799   public void disableBackend(DatabaseBackend db) throws SQLException
00800   {
00801     if (backend.equals(db))
00802     {
00803       logger
00804           .info(Translate.get("loadbalancer.backend.disabling", db.getName()));
00805       backend.disable();
00806       if (backend.isInitialized())
00807         backend.finalizeConnections();
00808       backend = null;
00809     }
00810     else
00811     {
00812       String msg = "Trying to disable a non-existing backend " + db.getName();
00813       logger.warn(msg);
00814       throw new SQLException(msg);
00815     }
00816   }
00817 
00818   /**
00819    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#setWeight(String,
00820    *      int)
00821    */
00822   public void setWeight(String name, int w) throws SQLException
00823   {
00824     throw new SQLException("Weight is not supported with this load balancer");
00825   }
00826 
00827   /*
00828    * Debug/Monitoring
00829    */
00830 
00831   /**
00832    * Gets information about the request load balancer
00833    * 
00834    * @return <code>String</code> containing information
00835    */
00836   public String getInformation()
00837   {
00838     if (backend == null)
00839       return "SingleDB Request load balancer: !!!Warning!!! No enabled backend node found\n";
00840     else
00841       return "SingleDB Request load balancer using " + backend.getURL() + "\n";
00842   }
00843 
00844   /**
00845    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#getXmlImpl()
00846    */
00847   public String getXmlImpl()
00848   {
00849     return "<" + DatabasesXmlTags.ELT_SingleDB + "/>";
00850   }
00851 
00852 }

Generated on Mon Apr 11 22:01:34 2005 for C-JDBC by  doxygen 1.3.9.1