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

AbstractLoadBalancer.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;
00026 
00027 import java.sql.CallableStatement;
00028 import java.sql.Connection;
00029 import java.sql.PreparedStatement;
00030 import java.sql.SQLException;
00031 import java.sql.Statement;
00032 import java.util.ArrayList;
00033 
00034 import javax.management.NotCompliantMBeanException;
00035 
00036 import org.objectweb.cjdbc.common.exceptions.BadConnectionException;
00037 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
00038 import org.objectweb.cjdbc.common.i18n.Translate;
00039 import org.objectweb.cjdbc.common.jmx.mbeans.AbstractLoadBalancerMBean;
00040 import org.objectweb.cjdbc.common.log.Trace;
00041 import org.objectweb.cjdbc.common.sql.AbstractRequest;
00042 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
00043 import org.objectweb.cjdbc.common.sql.SelectRequest;
00044 import org.objectweb.cjdbc.common.sql.StoredProcedure;
00045 import org.objectweb.cjdbc.common.sql.filters.MacrosHandler;
00046 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00047 import org.objectweb.cjdbc.common.xml.XmlComponent;
00048 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00049 import org.objectweb.cjdbc.controller.backend.DriverCompliance;
00050 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
00051 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager;
00052 import org.objectweb.cjdbc.controller.jmx.AbstractStandardMBean;
00053 import org.objectweb.cjdbc.controller.requestmanager.TransactionMarkerMetaData;
00054 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
00055 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
00056 
00057 /**
00058  * The Request Load Balancer should implement the load balancing of the requests
00059  * among the backend nodes.
00060  * <p>
00061  * The requests comes from the Request Controller and are sent to the Connection
00062  * Managers.
00063  * 
00064  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00065  * @author <a href="mailto:vadim@kase.kz">Vadim Kassin </a>
00066  * @author <a href="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
00067  * @version 1.0
00068  */
00069 public abstract class AbstractLoadBalancer extends AbstractStandardMBean
00070     implements
00071       XmlComponent,
00072       AbstractLoadBalancerMBean
00073 {
00074 
00075   //
00076   // How the code is organized ?
00077   //
00078   // 1. Member variables/Constructor
00079   // 2. Getter/Setter (possibly in alphabetical order)
00080   // 3. Request handling
00081   // 4. Transaction management
00082   // 5. Backend management
00083   // 6. Debug/Monitoring
00084   //
00085 
00086   // Virtual Database this load balancer is attached to.
00087   protected VirtualDatabase vdb;
00088   protected int             raidbLevel;
00089   protected int             parsingGranularity;
00090 
00091   protected static Trace    logger = Trace
00092                                        .getLogger("org.objectweb.cjdbc.controller.loadbalancer");
00093 
00094   protected MacrosHandler   macroHandler;
00095 
00096   /**
00097    * Generic constructor that sets some member variables and checks that
00098    * backends are in the disabled state
00099    * 
00100    * @param vdb The virtual database this load balancer belongs to
00101    * @param raidbLevel The RAIDb level of this load balancer
00102    * @param parsingGranularity The parsing granularity needed by this load
00103    *          balancer
00104    */
00105   protected AbstractLoadBalancer(VirtualDatabase vdb, int raidbLevel,
00106       int parsingGranularity) throws SQLException, NotCompliantMBeanException
00107   {
00108     super(AbstractLoadBalancerMBean.class);
00109     this.raidbLevel = raidbLevel;
00110     this.parsingGranularity = parsingGranularity;
00111     this.vdb = vdb;
00112     try
00113     {
00114       vdb.acquireReadLockBackendLists();
00115     }
00116     catch (InterruptedException e)
00117     {
00118       String msg = Translate.get(
00119           "loadbalancer.backendlist.acquire.readlock.failed", e);
00120       logger.error(msg);
00121       throw new SQLException(msg);
00122     }
00123     int size = vdb.getBackends().size();
00124     ArrayList backends = vdb.getBackends();
00125     for (int i = 0; i < size; i++)
00126     {
00127       DatabaseBackend backend = (DatabaseBackend) backends.get(i);
00128       if (backend.isReadEnabled() || backend.isWriteEnabled())
00129       {
00130         if (logger.isWarnEnabled())
00131           logger.warn(Translate.get(
00132               "loadbalancer.constructor.backends.not.disabled", backend
00133                   .getName()));
00134         try
00135         {
00136           disableBackend(backend);
00137         }
00138         catch (Exception e)
00139         { // Set the disabled state anyway
00140           backend.disable();
00141         }
00142       }
00143     }
00144     vdb.releaseReadLockBackendLists();
00145   }
00146 
00147   //
00148   // Getter/Setter methods
00149   //
00150 
00151   /**
00152    * Returns the RAIDbLevel.
00153    * 
00154    * @return int the RAIDb level
00155    */
00156   public int getRAIDbLevel()
00157   {
00158     return raidbLevel;
00159   }
00160 
00161   /**
00162    * Sets the RAIDbLevel.
00163    * 
00164    * @param raidbLevel The RAIDb level to set
00165    */
00166   public void setRAIDbLevel(int raidbLevel)
00167   {
00168     this.raidbLevel = raidbLevel;
00169   }
00170 
00171   /**
00172    * Get the needed query parsing granularity.
00173    * 
00174    * @return needed query parsing granularity
00175    */
00176   public int getParsingGranularity()
00177   {
00178     return parsingGranularity;
00179   }
00180 
00181   /**
00182    * Set the needed query parsing granularity.
00183    * 
00184    * @param parsingGranularity the granularity to set
00185    */
00186   public void setParsingGranularity(int parsingGranularity)
00187   {
00188     this.parsingGranularity = parsingGranularity;
00189   }
00190 
00191   //
00192   // Request Handling
00193   //
00194 
00195   /**
00196    * Perform a read request. It is up to the implementation to choose to which
00197    * backend node(s) this request should be sent.
00198    * 
00199    * @param request an <code>SelectRequest</code>
00200    * @param metadataCache MetadataCache (null if none)
00201    * @return the corresponding <code>ControllerResultSet</code>
00202    * @exception SQLException if an error occurs
00203    */
00204   public abstract ControllerResultSet execReadRequest(SelectRequest request,
00205       MetadataCache metadataCache) throws SQLException;
00206 
00207   /**
00208    * Perform a write request. This request should usually be broadcasted to all
00209    * nodes.
00210    * 
00211    * @param request an <code>AbstractWriteRequest</code>
00212    * @return number of rows affected by the request
00213    * @throws AllBackendsFailedException if all backends failed to execute the
00214    *           request
00215    * @exception SQLException if an error occurs
00216    */
00217   public abstract int execWriteRequest(AbstractWriteRequest request)
00218       throws AllBackendsFailedException, SQLException;
00219 
00220   /**
00221    * Perform a write request and return a ResultSet containing the auto
00222    * generated keys.
00223    * 
00224    * @param request an <code>AbstractWriteRequest</code>
00225    * @param metadataCache MetadataCache (null if none)
00226    * @return auto generated keys
00227    * @throws AllBackendsFailedException if all backends failed to execute the
00228    *           request
00229    * @exception SQLException if an error occurs
00230    */
00231   public abstract ControllerResultSet execWriteRequestWithKeys(
00232       AbstractWriteRequest request, MetadataCache metadataCache)
00233       throws AllBackendsFailedException, SQLException;
00234 
00235   /**
00236    * Call a read-only stored procedure that returns a ResultSet. The stored
00237    * procedure will be executed by one node only.
00238    * 
00239    * @param proc the stored procedure call
00240    * @param metadataCache MetadataCache (null if none)
00241    * @return a <code>ControllerResultSet</code> value
00242    * @exception SQLException if an error occurs
00243    */
00244   public abstract ControllerResultSet execReadOnlyReadStoredProcedure(
00245       StoredProcedure proc, MetadataCache metadataCache) throws SQLException;
00246 
00247   /**
00248    * Call a stored procedure that returns a ResultSet. This stored procedure can
00249    * possibly perform writes and will therefore be executed by all nodes.
00250    * 
00251    * @param proc the stored procedure call
00252    * @param metadataCache MetadataCache (null if none)
00253    * @return a <code>ControllerResultSet</code> value
00254    * @exception SQLException if an error occurs
00255    */
00256   public abstract ControllerResultSet execReadStoredProcedure(
00257       StoredProcedure proc, MetadataCache metadataCache) throws SQLException;
00258 
00259   /**
00260    * Call a stored procedure that performs an update.
00261    * 
00262    * @param proc the stored procedure call
00263    * @return number of rows affected
00264    * @exception SQLException if an error occurs
00265    */
00266   public abstract int execWriteStoredProcedure(StoredProcedure proc)
00267       throws SQLException;
00268 
00269   /**
00270    * Execute a statement on a backend. If the execution fails, the connection is
00271    * checked for validity. If the connection was not valid, the query is
00272    * automatically retried on a new connection.
00273    * 
00274    * @param request the request to execute
00275    * @param backend the backend on which the request is executed
00276    * @param c connection used to create the statement
00277    * @param metadataCache MetadataCache (null if none)
00278    * @return the ControllerResultSet
00279    * @throws SQLException if an error occurs
00280    * @throws BadConnectionException if the connection was bad
00281    */
00282   public static final ControllerResultSet executeSelectRequestOnBackend(
00283       SelectRequest request, DatabaseBackend backend, Connection c,
00284       MetadataCache metadataCache) throws SQLException, BadConnectionException
00285   {
00286     ControllerResultSet rs = null;
00287     try
00288     {
00289       backend.addPendingReadRequest(request);
00290       String sql = request.getSQL();
00291       // Rewrite the query if needed
00292       sql = backend.rewriteQuery(sql);
00293 
00294       Statement s; // Can also be used as a PreparedStatement
00295       if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00296         s = c.createStatement();
00297       else
00298       {
00299         s = c.prepareStatement(request.getSqlSkeleton());
00300         org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(sql,
00301             (PreparedStatement) s);
00302       }
00303 
00304       // Execute the query
00305       DriverCompliance driverCompliance = backend.getDriverCompliance();
00306       if (driverCompliance.supportSetQueryTimeout())
00307         s.setQueryTimeout(request.getTimeout());
00308       if ((request.getCursorName() != null)
00309           && (driverCompliance.supportSetCursorName()))
00310         s.setCursorName(request.getCursorName());
00311       if ((request.getFetchSize() != 0)
00312           && driverCompliance.supportSetFetchSize())
00313         s.setFetchSize(request.getFetchSize());
00314       if ((request.getMaxRows() > 0) && driverCompliance.supportSetMaxRows())
00315         s.setMaxRows(request.getMaxRows());
00316       if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00317         rs = new ControllerResultSet(request, s.executeQuery(sql),
00318             metadataCache, s);
00319       else
00320         rs = new ControllerResultSet(request, ((PreparedStatement) s)
00321             .executeQuery(), metadataCache, s);
00322     }
00323     catch (SQLException e)
00324     { // Something bad happened
00325       if (backend.isValidConnection(c))
00326         throw e; // Connection is valid, throw the exception
00327       else
00328         throw new BadConnectionException(e);
00329     }
00330     finally
00331     {
00332       backend.removePendingRequest(request);
00333     }
00334     return rs;
00335   }
00336 
00337   /**
00338    * Execute an update prepared statement on a backend. If the execution fails,
00339    * the connection is checked for validity. If the connection was not valid,
00340    * the query is automatically retried on a new connection.
00341    * 
00342    * @param request the request to execute
00343    * @param backend the backend on which the request is executed
00344    * @param c connection used to create the statement
00345    * @return int Number of rows effected
00346    * @throws SQLException if an error occurs
00347    * @throws BadConnectionException if the connection was bad
00348    */
00349   public static final int executeUpdateRequestOnBackend(
00350       AbstractWriteRequest request, DatabaseBackend backend, Connection c)
00351       throws SQLException, BadConnectionException
00352   {
00353     try
00354     {
00355       backend.addPendingWriteRequest(request);
00356       String sql = request.getSQL();
00357       // Rewrite the query if needed
00358       sql = backend.rewriteQuery(sql);
00359 
00360       Statement s; // Can also be used as a PreparedStatement
00361       if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00362         s = c.createStatement();
00363       else
00364       {
00365         s = c.prepareStatement(request.getSqlSkeleton());
00366         org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(sql,
00367             (PreparedStatement) s);
00368       }
00369 
00370       // Execute the query
00371       DriverCompliance driverCompliance = backend.getDriverCompliance();
00372       if (driverCompliance.supportSetQueryTimeout())
00373         s.setQueryTimeout(request.getTimeout());
00374 
00375       int rows = 0;
00376       if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00377         rows = s.executeUpdate(sql);
00378       else
00379         rows = ((PreparedStatement) s).executeUpdate();
00380 
00381       s.close();
00382       return rows;
00383     }
00384     catch (SQLException e)
00385     { // Something bad happened
00386       if (backend.isValidConnection(c))
00387         throw e; // Connection is valid, throw the exception
00388       else
00389         throw new BadConnectionException(e);
00390     }
00391     finally
00392     {
00393       backend.removePendingRequest(request);
00394     }
00395   }
00396 
00397   /**
00398    * Execute an update prepared statement on a backend. If the execution fails,
00399    * the connection is checked for validity. If the connection was not valid,
00400    * the query is automatically retried on a new connection.
00401    * 
00402    * @param request the request to execute
00403    * @param backend the backend on which the request is executed
00404    * @param c connection used to create the statement
00405    * @param metadataCache MetadataCache (null if none)
00406    * @return ControllerResultSet containing the auto-generated keys
00407    * @throws SQLException if an error occurs
00408    * @throws BadConnectionException if the connection was bad
00409    */
00410   public static final ControllerResultSet executeUpdateRequestOnBackendWithKeys(
00411       AbstractWriteRequest request, DatabaseBackend backend, Connection c,
00412       MetadataCache metadataCache) throws SQLException, BadConnectionException
00413   {
00414     try
00415     {
00416       backend.addPendingWriteRequest(request);
00417       String sql = request.getSQL();
00418       // Rewrite the query if needed
00419       sql = backend.rewriteQuery(sql);
00420 
00421       Statement s = c.createStatement();
00422 
00423       // Execute the query
00424       DriverCompliance driverCompliance = backend.getDriverCompliance();
00425       if (driverCompliance.supportSetQueryTimeout())
00426         s.setQueryTimeout(request.getTimeout());
00427 
00428       s.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
00429       ControllerResultSet rs = new ControllerResultSet(request, s
00430           .getGeneratedKeys(), metadataCache, s);
00431       return rs;
00432     }
00433     catch (SQLException e)
00434     { // Something bad happened
00435       if (backend.isValidConnection(c))
00436         throw e; // Connection is valid, throw the exception
00437       else
00438         throw new BadConnectionException(e);
00439     }
00440     finally
00441     {
00442       backend.removePendingRequest(request);
00443     }
00444   }
00445 
00446   /**
00447    * Execute a read stored procedure on the given backend. The callable
00448    * statement is setXXX if the driver has not processed the statement.
00449    * 
00450    * @param proc the stored procedure to execute
00451    * @param backend the backend on which to execute the stored procedure
00452    * @param c the connection on which to execute the stored procedure
00453    * @param metadataCache the matedatacache to build the ControllerResultSet
00454    * @return the controllerResultSet
00455    * @throws SQLException if an error occurs
00456    * @throws BadConnectionException if the connection was bad
00457    */
00458   public static final ControllerResultSet executeReadStoredProcedureOnBackend(
00459       StoredProcedure proc, DatabaseBackend backend, Connection c,
00460       MetadataCache metadataCache) throws SQLException, BadConnectionException
00461   {
00462     try
00463     {
00464       backend.addPendingReadRequest(proc);
00465 
00466       // We suppose here that the request does not modify the schema since
00467       // it is a read-only query.
00468       CallableStatement cs;
00469       if (proc.isDriverProcessed())
00470         cs = c.prepareCall(proc.getSQL());
00471       else
00472       {
00473         cs = c.prepareCall(proc.getSqlSkeleton());
00474         org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(proc
00475             .getSQL(), cs);
00476       }
00477       if (backend.getDriverCompliance().supportSetQueryTimeout())
00478         cs.setQueryTimeout(proc.getTimeout());
00479       if ((proc.getMaxRows() > 0)
00480           && backend.getDriverCompliance().supportSetMaxRows())
00481         cs.setMaxRows(proc.getMaxRows());
00482       ControllerResultSet rs = new ControllerResultSet(proc, cs.executeQuery(),
00483           metadataCache, cs);
00484       return rs;
00485     }
00486     catch (SQLException e)
00487     { // Something bad happened
00488       if (backend.isValidConnection(c))
00489         throw e; // Connection is valid, throw the exception
00490       else
00491         throw new BadConnectionException(e);
00492     }
00493     finally
00494     {
00495       backend.removePendingRequest(proc);
00496     }
00497   }
00498 
00499   /**
00500    * Execute a write stored procedure on the given backend. The callable
00501    * statement is setXXX if the driver has not processed the statement.
00502    * 
00503    * @param proc the stored procedure to execute
00504    * @param backend the backend on which to execute the stored procedure
00505    * @param c the connection on which to execute the stored procedure
00506    * @return the number of updated rows
00507    * @throws SQLException if an error occurs
00508    * @throws BadConnectionException if the connection was bad
00509    */
00510   public static final int executeWriteStoredProcedureOnBackend(
00511       StoredProcedure proc, DatabaseBackend backend, Connection c)
00512       throws SQLException, BadConnectionException
00513   {
00514     try
00515     {
00516       backend.addPendingWriteRequest(proc);
00517 
00518       // We suppose here that the request does not modify the schema since
00519       // it is a read-only query.
00520       CallableStatement cs;
00521       if (proc.isDriverProcessed())
00522         cs = c.prepareCall(proc.getSQL());
00523       else
00524       {
00525         cs = c.prepareCall(proc.getSqlSkeleton());
00526         org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(proc
00527             .getSQL(), cs);
00528       }
00529       if (backend.getDriverCompliance().supportSetQueryTimeout())
00530         cs.setQueryTimeout(proc.getTimeout());
00531       if ((proc.getMaxRows() > 0)
00532           && backend.getDriverCompliance().supportSetMaxRows())
00533         cs.setMaxRows(proc.getMaxRows());
00534       int rows = cs.executeUpdate();
00535       cs.close();
00536       return rows;
00537     }
00538     catch (SQLException e)
00539     { // Something bad happened
00540       if (backend.isValidConnection(c))
00541         throw e; // Connection is valid, throw the exception
00542       else
00543         throw new BadConnectionException(e);
00544     }
00545     finally
00546     {
00547       backend.removePendingRequest(proc);
00548     }
00549   }
00550 
00551   //
00552   // Transaction management
00553   //
00554 
00555   /**
00556    * Begin a new transaction.
00557    * 
00558    * @param tm The transaction marker metadata
00559    * @throws SQLException if an error occurs
00560    */
00561   public abstract void begin(TransactionMarkerMetaData tm) throws SQLException;
00562 
00563   /**
00564    * Commit a transaction.
00565    * 
00566    * @param tm The transaction marker metadata
00567    * @throws AllBackendsFailedException if all backends failed to execute the
00568    *           request
00569    * @exception SQLException if an error occurs
00570    */
00571   public abstract void commit(TransactionMarkerMetaData tm)
00572       throws AllBackendsFailedException, SQLException;
00573 
00574   /**
00575    * Rollback a transaction.
00576    * 
00577    * @param tm The transaction marker metadata
00578    * @throws AllBackendsFailedException if all backends failed to execute the
00579    *           request
00580    * @exception SQLException if an error occurs
00581    */
00582   public abstract void rollback(TransactionMarkerMetaData tm)
00583       throws AllBackendsFailedException, SQLException;
00584 
00585   //
00586   // Backends management
00587   //
00588 
00589   /**
00590    * Enable a backend without further check. The backend is at least read
00591    * enabled but could also be enabled for writes. Ask the corresponding
00592    * connection manager to initialize the connections if needed.
00593    * 
00594    * @param db The database backend to enable
00595    * @param writeEnabled True if the backend must be enabled for writes
00596    * @throws SQLException if an error occurs
00597    */
00598   public abstract void enableBackend(DatabaseBackend db, boolean writeEnabled)
00599       throws SQLException;
00600 
00601   /**
00602    * Disable a backend without further check. Ask the corresponding connection
00603    * manager to finalize the connections if needed. This method should not be
00604    * called directly but instead should access the
00605    * <code>RequestManager.disableBackeknd(...)</code> method.
00606    * 
00607    * @param db The database backend to disable
00608    * @throws SQLException if an error occurs
00609    */
00610   public abstract void disableBackend(DatabaseBackend db) throws SQLException;
00611 
00612   /**
00613    * Associate a weight to a backend identified by its logical name.
00614    * 
00615    * @param name the backend name
00616    * @param w the weight
00617    * @throws SQLException if an error occurs
00618    */
00619   public void setWeight(String name, int w) throws SQLException
00620   {
00621     throw new SQLException("Weight is not supported by this load balancer");
00622   }
00623 
00624   //
00625   // Debug/Monitoring
00626   //
00627 
00628   /**
00629    * Get information about the Request Load Balancer
00630    * 
00631    * @return <code>String</code> containing information
00632    */
00633   public abstract String getInformation();
00634 
00635   /**
00636    * Get information about the Request Load Balancer in xml
00637    * 
00638    * @return <code>String</code> containing information, xml formatted
00639    */
00640   public abstract String getXmlImpl();
00641 
00642   /**
00643    * This sets the macro handler for this load balancer. Handling macros
00644    * prevents different backends to generate different values when interpreting
00645    * the macros which could result in data inconsitencies.
00646    * 
00647    * @param handler <code>MacrosHandler</code> instance
00648    */
00649   public void setMacroHandler(MacrosHandler handler)
00650   {
00651     this.macroHandler = handler;
00652   }
00653 
00654   /**
00655    * Interprets the macros in the request (depending on the
00656    * <code>MacroHandler</code> set for this class) and modify either the
00657    * skeleton or the query itself. Note that the given object is directly
00658    * modified.
00659    * 
00660    * @param request the request to process
00661    */
00662   public void handleMacros(AbstractRequest request)
00663   {
00664     if (macroHandler == null)
00665       return;
00666 
00667     if (request.isWriteRequest())
00668     {
00669       AbstractWriteRequest writeReq = (AbstractWriteRequest) request;
00670       if (writeReq.isCreate() || writeReq.isAlter() || writeReq.isDrop())
00671         return;
00672     }
00673 
00674     if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00675       request.setSQL(macroHandler.processMacros(request.getSQL()));
00676     else
00677       request.setSqlSkeleton(macroHandler.processMacros(request
00678           .getSqlSkeleton()));
00679   }
00680 
00681   /**
00682    * @see org.objectweb.cjdbc.common.xml.XmlComponent#getXml()
00683    */
00684   public String getXml()
00685   {
00686     StringBuffer info = new StringBuffer();
00687     info.append("<" + DatabasesXmlTags.ELT_LoadBalancer + ">");
00688     info.append(getXmlImpl());
00689     info.append("</" + DatabasesXmlTags.ELT_LoadBalancer + ">");
00690     return info.toString();
00691   }
00692 
00693   /**
00694    * Factorized code to start a transaction on a backend and to retrieve a
00695    * connection on this backend
00696    * 
00697    * @param backend the backend needed to check valid connection against this
00698    *          backend test statement
00699    * @param cm the connection manager to use to retrieve connections
00700    * @param tid the id of the transaction to start
00701    * @return a valid connection with a started transaction
00702    * @throws SQLException if the backend is valid but set autocommit cannot be
00703    *           set to false
00704    * @throws UnreachableBackendException if the backend is not reachable, ie not
00705    *           valid connection can be retrieved
00706    */
00707   public static final Connection getConnectionAndBeginTransaction(
00708       DatabaseBackend backend, AbstractConnectionManager cm, long tid)
00709       throws SQLException, UnreachableBackendException
00710   {
00711     Connection c = null;
00712     boolean isConnectionValid = false;
00713     do
00714     {
00715       c = cm.getConnection(tid);
00716 
00717       // Sanity check
00718       if (c == null)
00719         throw new UnreachableBackendException(Translate.get(
00720             "loadbalancer.unable.get.connection", new String[]{
00721                 String.valueOf(tid), backend.getName()}));
00722       try
00723       {
00724         c.setAutoCommit(false);
00725         isConnectionValid = true;
00726       }
00727       catch (SQLException e)
00728       {
00729         if (backend.isValidConnection(c))
00730           throw e; // Connection is valid, throw the exception
00731         else
00732         {
00733           cm.deleteConnection(tid);
00734         }
00735       }
00736     }
00737     while (!isConnectionValid);
00738     return c;
00739   }
00740 
00741   /**
00742    * @see org.objectweb.cjdbc.controller.jmx.AbstractStandardMBean#getAssociatedString()
00743    */
00744   public String getAssociatedString()
00745   {
00746     return "loadbalancer";
00747   }
00748 }

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