00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 package org.objectweb.cjdbc.controller.virtualdatabase;
00026
00027 import java.io.File;
00028 import java.io.FilenameFilter;
00029 import java.io.Serializable;
00030 import java.sql.SQLException;
00031 import java.util.ArrayList;
00032 import java.util.Hashtable;
00033 import java.util.Map;
00034
00035 import javax.management.NotCompliantMBeanException;
00036 import javax.management.ObjectName;
00037
00038 import org.objectweb.cjdbc.common.exceptions.BackupException;
00039 import org.objectweb.cjdbc.common.exceptions.ExceptionTypes;
00040 import org.objectweb.cjdbc.common.exceptions.OctopusException;
00041 import org.objectweb.cjdbc.common.exceptions.VirtualDatabaseException;
00042 import org.objectweb.cjdbc.common.i18n.Translate;
00043 import org.objectweb.cjdbc.common.jmx.JmxConstants;
00044 import org.objectweb.cjdbc.common.jmx.JmxException;
00045 import org.objectweb.cjdbc.common.jmx.mbeans.VirtualDatabaseMBean;
00046 import org.objectweb.cjdbc.common.jmx.notifications.CjdbcNotificationList;
00047 import org.objectweb.cjdbc.common.log.Trace;
00048 import org.objectweb.cjdbc.common.shared.BackendState;
00049 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
00050 import org.objectweb.cjdbc.common.sql.ParsingGranularities;
00051 import org.objectweb.cjdbc.common.sql.SelectRequest;
00052 import org.objectweb.cjdbc.common.sql.StoredProcedure;
00053 import org.objectweb.cjdbc.common.sql.filters.AbstractBlobFilter;
00054 import org.objectweb.cjdbc.common.sql.schema.DatabaseSchema;
00055 import org.objectweb.cjdbc.common.sql.schema.DatabaseTable;
00056 import org.objectweb.cjdbc.common.users.AdminUser;
00057 import org.objectweb.cjdbc.common.users.VirtualDatabaseUser;
00058 import org.objectweb.cjdbc.common.util.Constants;
00059 import org.objectweb.cjdbc.common.util.ReadPrioritaryFIFOWriteLock;
00060 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00061 import org.objectweb.cjdbc.common.xml.XmlComponent;
00062 import org.objectweb.cjdbc.common.xml.XmlTools;
00063 import org.objectweb.cjdbc.controller.authentication.AuthenticationManager;
00064 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00065 import org.objectweb.cjdbc.controller.cache.result.AbstractResultCache;
00066 import org.objectweb.cjdbc.controller.core.Controller;
00067 import org.objectweb.cjdbc.controller.core.shutdown.VirtualDatabaseForceShutdownThread;
00068 import org.objectweb.cjdbc.controller.core.shutdown.VirtualDatabaseSafeShutdownThread;
00069 import org.objectweb.cjdbc.controller.core.shutdown.VirtualDatabaseShutdownThread;
00070 import org.objectweb.cjdbc.controller.core.shutdown.VirtualDatabaseWaitShutdownThread;
00071 import org.objectweb.cjdbc.controller.jmx.AbstractStandardMBean;
00072 import org.objectweb.cjdbc.controller.jmx.MBeanServerManager;
00073 import org.objectweb.cjdbc.controller.jmx.RmiConnector;
00074 import org.objectweb.cjdbc.controller.monitoring.SQLMonitoring;
00075 import org.objectweb.cjdbc.controller.recoverylog.AbstractRecoveryLog;
00076 import org.objectweb.cjdbc.controller.recoverylog.BackendRecoveryInfo;
00077 import org.objectweb.cjdbc.controller.recoverylog.JDBCRecoveryLog;
00078 import org.objectweb.cjdbc.controller.requestmanager.RequestManager;
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 public class VirtualDatabase extends AbstractStandardMBean
00093 implements
00094 Serializable,
00095 VirtualDatabaseMBean,
00096 XmlComponent
00097 {
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 protected String name;
00113
00114
00115
00116
00117
00118 protected AuthenticationManager authenticationManager;
00119
00120
00121 protected ArrayList backends;
00122
00123
00124 protected ReadPrioritaryFIFOWriteLock rwLock;
00125
00126
00127 protected RequestManager requestManager;
00128
00129
00130 public Trace logger = null;
00131 protected Trace requestLogger = null;
00132
00133
00134 private ArrayList activeThreads = new ArrayList();
00135
00136 private int idleThreads = 0;
00137
00138 private ArrayList pendingConnections = new ArrayList();
00139
00140
00141 protected int maxNbOfConnections;
00142
00143
00144 protected boolean poolConnectionThreads;
00145
00146
00147 protected long maxThreadIdleTime;
00148
00149
00150
00151
00152
00153 protected int minNbOfThreads;
00154
00155
00156 protected int maxNbOfThreads;
00157
00158
00159 protected int currentNbOfThreads;
00160
00161
00162 protected VirtualDatabaseDynamicMetaData metadata;
00163 private VirtualDatabaseStaticMetaData staticMetadata;
00164
00165 private SQLMonitoring sqlMonitor = null;
00166
00167
00168 public static final int CHECK_BACKEND_ENABLE = 1;
00169
00170 public static final int CHECK_BACKEND_DISABLE = 0;
00171
00172 public static final int NO_CHECK_BACKEND = -1;
00173
00174
00175 private int sqlShortFormLength;
00176
00177
00178 private AbstractBlobFilter blobFilter;
00179
00180
00181 Controller controller;
00182
00183
00184 private String databaseProductNames = "C-JDBC";
00185
00186
00187 private boolean shuttingDown = false;
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 public VirtualDatabase(Controller controller, String name,
00210 int maxConnections, boolean pool, int minThreads, int maxThreads,
00211 long maxThreadIdleTime, int sqlShortFormLength,
00212 AbstractBlobFilter blobFilter) throws NotCompliantMBeanException,
00213 JmxException
00214 {
00215 super(VirtualDatabaseMBean.class);
00216 this.controller = controller;
00217 this.name = name;
00218 this.maxNbOfConnections = maxConnections;
00219 this.poolConnectionThreads = pool;
00220 this.minNbOfThreads = minThreads;
00221 this.maxNbOfThreads = maxThreads;
00222 this.maxThreadIdleTime = maxThreadIdleTime;
00223 this.sqlShortFormLength = sqlShortFormLength;
00224 this.blobFilter = blobFilter;
00225 backends = new ArrayList();
00226
00227 ObjectName objectName = JmxConstants.getVirtualDbObjectName(name);
00228 MBeanServerManager.registerMBean(this, objectName);
00229
00230 rwLock = new ReadPrioritaryFIFOWriteLock();
00231 logger = Trace.getLogger("org.objectweb.cjdbc.controller.virtualdatabase."
00232 + name);
00233 requestLogger = Trace
00234 .getLogger("org.objectweb.cjdbc.controller.virtualdatabase.request."
00235 + name);
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245 public final void acquireReadLockBackendLists() throws InterruptedException
00246 {
00247 rwLock.acquireRead();
00248 }
00249
00250
00251
00252
00253
00254
00255 public final void releaseReadLockBackendLists()
00256 {
00257 rwLock.releaseRead();
00258 }
00259
00260
00261
00262
00263
00264
00265 public boolean isDistributed()
00266 {
00267 return false;
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 public boolean checkUserAuthentication(String virtualLogin,
00282 String virtualPassword)
00283 {
00284 if (authenticationManager == null)
00285 {
00286 logger.error("No authentification manager defined to check login '"
00287 + virtualLogin + "'");
00288 return false;
00289 }
00290 else
00291 return authenticationManager.isValidVirtualUser(new VirtualDatabaseUser(
00292 virtualLogin, virtualPassword));
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 public boolean checkAdminAuthentication(String adminLogin,
00305 String adminPassword)
00306 {
00307 if (authenticationManager == null)
00308 {
00309 logger.error("No authentification manager defined to check admin login '"
00310 + adminLogin + "'");
00311 return false;
00312 }
00313 else
00314 return authenticationManager.isValidAdminUser(new AdminUser(adminLogin,
00315 adminPassword));
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325 public ControllerResultSet execReadRequest(SelectRequest request)
00326 throws SQLException
00327 {
00328 if (request == null)
00329 {
00330 String msg = "Request failed (null read request received)";
00331 logger.warn(msg);
00332 throw new SQLException(msg);
00333 }
00334
00335 try
00336 {
00337 if (requestLogger.isInfoEnabled())
00338 requestLogger.info("S " + request.getTransactionId() + " "
00339 + request.getSQL());
00340
00341 long start = 0;
00342 if (sqlMonitor != null && sqlMonitor.isActive())
00343 start = System.currentTimeMillis();
00344
00345 ControllerResultSet rs = requestManager.execReadRequest(request);
00346
00347 if (sqlMonitor != null && sqlMonitor.isActive())
00348 sqlMonitor.logRequestTime(request, System.currentTimeMillis() - start);
00349
00350 return rs;
00351 }
00352 catch (SQLException e)
00353 {
00354 String msg = "Request '" + request.getId() + "' failed ("
00355 + e.getMessage() + ")";
00356 logger.warn(msg);
00357 if (sqlMonitor != null && sqlMonitor.isActive())
00358 sqlMonitor.logError(request);
00359 throw e;
00360 }
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370 public int execWriteRequest(AbstractWriteRequest request) throws SQLException
00371 {
00372 if (request == null)
00373 {
00374 String msg = "Request failed (null write request received)";
00375 logger.warn(msg);
00376 throw new SQLException(msg);
00377 }
00378
00379 try
00380 {
00381 if (requestLogger.isInfoEnabled())
00382 requestLogger.info("W " + request.getTransactionId() + " "
00383 + request.getSQL());
00384
00385 long start = 0;
00386 if (sqlMonitor != null && sqlMonitor.isActive())
00387 start = System.currentTimeMillis();
00388
00389 int result = requestManager.execWriteRequest(request);
00390
00391 if (sqlMonitor != null && sqlMonitor.isActive())
00392 sqlMonitor.logRequestTime(request, System.currentTimeMillis() - start);
00393
00394 return result;
00395 }
00396 catch (SQLException e)
00397 {
00398 String msg = "Request '" + request.getId() + "' failed ("
00399 + e.getMessage() + ")";
00400 logger.warn(msg);
00401 if (sqlMonitor != null && sqlMonitor.isActive())
00402 sqlMonitor.logError(request);
00403 throw e;
00404 }
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414 public ControllerResultSet execWriteRequestWithKeys(
00415 AbstractWriteRequest request) throws SQLException
00416 {
00417 if (request == null)
00418 {
00419 String msg = "Request failed (null write request received)";
00420 logger.warn(msg);
00421 throw new SQLException(msg);
00422 }
00423
00424 try
00425 {
00426 if (requestLogger.isInfoEnabled())
00427 requestLogger.info("W " + request.getTransactionId() + " "
00428 + request.getSQL());
00429
00430 long start = 0;
00431 if (sqlMonitor != null && sqlMonitor.isActive())
00432 start = System.currentTimeMillis();
00433
00434 ControllerResultSet result = requestManager
00435 .execWriteRequestWithKeys(request);
00436
00437 if (sqlMonitor != null && sqlMonitor.isActive())
00438 sqlMonitor.logRequestTime(request, System.currentTimeMillis() - start);
00439
00440 return result;
00441 }
00442 catch (SQLException e)
00443 {
00444 String msg = "Request '" + request.getId() + "' failed ("
00445 + e.getMessage() + ")";
00446 logger.warn(msg);
00447 if (sqlMonitor != null && sqlMonitor.isActive())
00448 sqlMonitor.logError(request);
00449 throw e;
00450 }
00451 }
00452
00453
00454
00455
00456
00457
00458
00459
00460 public ControllerResultSet execReadStoredProcedure(StoredProcedure proc)
00461 throws SQLException
00462 {
00463 if (proc == null)
00464 {
00465 String msg = "Request failed (null stored procedure received)";
00466 logger.warn(msg);
00467 throw new SQLException(msg);
00468 }
00469
00470 try
00471 {
00472 if (requestLogger.isInfoEnabled())
00473 requestLogger
00474 .info("S " + proc.getTransactionId() + " " + proc.getSQL());
00475
00476 long start = 0;
00477 if (sqlMonitor != null && sqlMonitor.isActive())
00478 start = System.currentTimeMillis();
00479
00480 ControllerResultSet rs = requestManager.execReadStoredProcedure(proc);
00481
00482 if (sqlMonitor != null && sqlMonitor.isActive())
00483 sqlMonitor.logRequestTime(proc, System.currentTimeMillis() - start);
00484
00485 return rs;
00486 }
00487 catch (SQLException e)
00488 {
00489 String msg = Translate.get("loadbalancer.storedprocedure.failed",
00490 new String[]{String.valueOf(proc.getId()), e.getMessage()});
00491 logger.warn(msg);
00492 if (sqlMonitor != null && sqlMonitor.isActive())
00493 sqlMonitor.logError(proc);
00494 throw e;
00495 }
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505 protected int execWriteStoredProcedure(StoredProcedure proc)
00506 throws SQLException
00507 {
00508 if (proc == null)
00509 {
00510 String msg = "Request failed (null stored procedure received)";
00511 logger.warn(msg);
00512 throw new SQLException(msg);
00513 }
00514
00515 try
00516 {
00517 if (requestLogger.isInfoEnabled())
00518 requestLogger
00519 .info("W " + proc.getTransactionId() + " " + proc.getSQL());
00520
00521 long start = 0;
00522 if (sqlMonitor != null && sqlMonitor.isActive())
00523 start = System.currentTimeMillis();
00524
00525 int result = requestManager.execWriteStoredProcedure(proc);
00526
00527 if (sqlMonitor != null && sqlMonitor.isActive())
00528 sqlMonitor.logRequestTime(proc, System.currentTimeMillis() - start);
00529
00530 return result;
00531 }
00532 catch (SQLException e)
00533 {
00534 String msg = Translate.get("loadbalancer.storedprocedure.failed",
00535 new String[]{String.valueOf(proc.getId()), e.getMessage()});
00536 logger.warn(msg);
00537 if (sqlMonitor != null && sqlMonitor.isActive())
00538 sqlMonitor.logError(proc);
00539 throw e;
00540 }
00541 }
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 public long begin(String login) throws SQLException
00556 {
00557 try
00558 {
00559 long tid = requestManager.begin(login);
00560 if (requestLogger.isInfoEnabled())
00561 requestLogger.info("B " + tid);
00562 return tid;
00563 }
00564 catch (SQLException e)
00565 {
00566 String msg = "Begin failed (" + e.getMessage() + ")";
00567 logger.warn(msg);
00568 throw e;
00569 }
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581 public void abort(long transactionId) throws SQLException
00582 {
00583 requestManager.abort(transactionId);
00584
00585 if (requestLogger.isInfoEnabled())
00586 requestLogger.info("R " + transactionId);
00587 }
00588
00589
00590
00591
00592
00593
00594
00595 public void commit(long transactionId) throws SQLException
00596 {
00597 try
00598 {
00599 if (requestLogger.isInfoEnabled())
00600 requestLogger.info("C " + transactionId);
00601 requestManager.commit(transactionId);
00602 }
00603 catch (SQLException e)
00604 {
00605 String msg = "Commit of transaction '" + transactionId + "' failed ("
00606 + e.getMessage() + ")";
00607 logger.warn(msg);
00608 throw e;
00609 }
00610 }
00611
00612
00613
00614
00615
00616
00617
00618 public void rollback(long transactionId) throws SQLException
00619 {
00620 try
00621 {
00622 if (requestLogger.isInfoEnabled())
00623 requestLogger.info("R " + transactionId);
00624 requestManager.rollback(transactionId);
00625 }
00626 catch (SQLException e)
00627 {
00628 String msg = "Rollback of transaction '" + transactionId + "' failed ("
00629 + e.getMessage() + ")";
00630 logger.warn(msg);
00631 throw e;
00632 }
00633 }
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 public void addBackend(DatabaseBackend db) throws VirtualDatabaseException
00646 {
00647 this.addBackend(db, true);
00648 }
00649
00650
00651
00652
00653
00654
00655
00656
00657 public void addBackend(DatabaseBackend db, boolean checkForCompliance)
00658 throws VirtualDatabaseException
00659 {
00660 if (db == null)
00661 {
00662 String msg = "Illegal null database backend in addBackend(DatabaseBackend) method";
00663 logger.error(msg);
00664 throw new VirtualDatabaseException(msg);
00665 }
00666
00667 if (db.isReadEnabled())
00668 {
00669 String msg = "It is not allowed to add an enabled database.";
00670 logger.error(msg);
00671 throw new VirtualDatabaseException(msg);
00672 }
00673
00674 try
00675 {
00676 rwLock.acquireWrite();
00677 }
00678 catch (InterruptedException e)
00679 {
00680 String msg = Translate.get(
00681 "loadbalancer.backendlist.acquire.writelock.failed", e);
00682 logger.error(msg);
00683 throw new VirtualDatabaseException(msg);
00684 }
00685
00686 if (backends.indexOf(db) == -1)
00687 {
00688
00689 ArrayList logins = authenticationManager.getVirtualLogins();
00690 VirtualDatabaseUser vdu;
00691 String login;
00692 for (int i = 0; i < logins.size(); i++)
00693 {
00694 vdu = (VirtualDatabaseUser) logins.get(i);
00695 login = vdu.getLogin();
00696 if (db.getConnectionManager(login) == null)
00697 throw new VirtualDatabaseException(Translate.get(
00698 "backend.missing.connection.manager", login));
00699 }
00700
00701
00702 try
00703 {
00704 if (logger.isDebugEnabled())
00705 logger.debug("Checking driver compliance");
00706 if (checkForCompliance)
00707 db.checkDriverCompliance();
00708
00709
00710 }
00711 catch (Exception e)
00712 {
00713 rwLock.releaseWrite();
00714 String msg = "Error while adding database backend " + db.getName()
00715 + " (" + e + ")";
00716 logger.warn(msg);
00717 throw new VirtualDatabaseException(msg);
00718 }
00719 db.setSqlShortFormLength(getSQLShortFormLength());
00720 backends.add(db);
00721
00722
00723 if (logger.isDebugEnabled())
00724 logger.debug("Backend " + db.getName() + " added successfully");
00725
00726 rwLock.releaseWrite();
00727
00728
00729 if (MBeanServerManager.isJmxEnabled())
00730 {
00731
00732 Hashtable data = new Hashtable();
00733 data.put(CjdbcNotificationList.DATA_DATABASE, this.name);
00734 data.put(CjdbcNotificationList.DATA_DRIVER, db.getDriverClassName());
00735 String checkpoint = db.getLastKnownCheckpoint();
00736 checkpoint = (checkpoint == null) ? "" : checkpoint;
00737 data.put(CjdbcNotificationList.DATA_CHECKPOINT, checkpoint);
00738 data.put(CjdbcNotificationList.DATA_NAME, db.getName());
00739 data.put(CjdbcNotificationList.DATA_URL, db.getURL());
00740 RmiConnector.broadcastNotification(this,
00741 CjdbcNotificationList.VIRTUALDATABASE_BACKEND_ADDED,
00742 CjdbcNotificationList.NOTIFICATION_LEVEL_INFO, Translate.get(
00743 "notification.backend.added", db.getName()), data);
00744
00745
00746 ObjectName objectName = JmxConstants.getDatabaseBackendObjectName(name,
00747 db.getName());
00748 try
00749 {
00750 MBeanServerManager.registerMBean(db, objectName);
00751 }
00752 catch (JmxException e1)
00753 {
00754 logger.error(Translate.get(
00755 "virtualdatabase.fail.register.backend.mbean", db.getName()), e1);
00756 }
00757 }
00758
00759 }
00760 else
00761 {
00762 rwLock.releaseWrite();
00763 String msg = "Duplicate backend " + db.getURL();
00764 logger.warn(msg);
00765 throw new VirtualDatabaseException(msg);
00766 }
00767
00768 }
00769
00770
00771
00772
00773 public void disableBackend(String backendName)
00774 throws VirtualDatabaseException
00775 {
00776 try
00777 {
00778 DatabaseBackend db = getAndCheckBackend(backendName,
00779 CHECK_BACKEND_DISABLE);
00780 requestManager.disableBackend(db);
00781 requestManager.setDatabaseSchema(
00782 getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames(),
00783 false);
00784
00785
00786 if (MBeanServerManager.isJmxEnabled())
00787 {
00788 Hashtable data = new Hashtable();
00789 data.put("driver", db.getDriverClassName());
00790 String checkpoint = db.getLastKnownCheckpoint();
00791 checkpoint = (checkpoint == null) ? "" : checkpoint;
00792 data.put("checkpoint", checkpoint);
00793 data.put("name", db.getName());
00794 data.put("url", db.getURL());
00795 RmiConnector.broadcastNotification(this,
00796 CjdbcNotificationList.VIRTUALDATABASE_BACKEND_DISABLED,
00797 CjdbcNotificationList.NOTIFICATION_LEVEL_INFO, Translate.get(
00798 "notification.backend.disabled", db.getName()), data);
00799 }
00800 }
00801 catch (Exception e)
00802 {
00803 logger.error("An error occured while disabling backend " + backendName
00804 + " (" + e + ")");
00805 throw new VirtualDatabaseException(e.getMessage());
00806 }
00807 }
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817 public void disableAllBackends() throws VirtualDatabaseException
00818 {
00819 try
00820 {
00821 int size = this.backends.size();
00822 DatabaseBackend dbe;
00823 for (int i = 0; i < size; i++)
00824 {
00825 dbe = (DatabaseBackend) backends.get(i);
00826 if (dbe.isReadEnabled())
00827 requestManager.disableBackend(getAndCheckBackend(dbe.getName(),
00828 CHECK_BACKEND_DISABLE));
00829 }
00830 }
00831 catch (Exception e)
00832 {
00833 throw new VirtualDatabaseException(e.getMessage());
00834 }
00835 }
00836
00837
00838
00839
00840
00841 public void disableBackendWithCheckpoint(String backendName,
00842 String checkpointName) throws VirtualDatabaseException
00843 {
00844 try
00845 {
00846 requestManager.disableBackendForCheckpoint(getAndCheckBackend(
00847 backendName, CHECK_BACKEND_DISABLE), checkpointName);
00848 requestManager.setDatabaseSchema(
00849 getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames(),
00850 false);
00851 }
00852 catch (Exception e)
00853 {
00854 logger.error("An error occured while disabling backend " + backendName
00855 + " (" + e + ")");
00856 throw new VirtualDatabaseException(e.getMessage());
00857 }
00858 }
00859
00860
00861
00862
00863 public void disableAllBackendsWithCheckpoint(String checkpoint)
00864 throws VirtualDatabaseException
00865 {
00866 if (checkpoint == null)
00867 {
00868 disableAllBackends();
00869 return;
00870 }
00871
00872 try
00873 {
00874 this.acquireReadLockBackendLists();
00875 requestManager.disableBackendsForCheckpoint(backends, checkpoint);
00876 this.releaseReadLockBackendLists();
00877 }
00878 catch (Exception e)
00879 {
00880 throw new VirtualDatabaseException(e.getMessage());
00881 }
00882 }
00883
00884
00885
00886
00887 public void enableBackend(String backendName) throws VirtualDatabaseException
00888 {
00889
00890 try
00891 {
00892 DatabaseBackend backend = getAndCheckBackend(backendName,
00893 CHECK_BACKEND_ENABLE);
00894
00895 requestManager.enableBackend(backend);
00896 requestManager.setDatabaseSchema(
00897 getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames(),
00898 false);
00899
00900
00901 if (databaseProductNames.indexOf(backend.getDatabaseProductName()) == -1)
00902 databaseProductNames += "," + backend.getDatabaseProductName();
00903
00904
00905 getStaticMetaData().gatherStaticMetadata(backend);
00906
00907
00908 if (MBeanServerManager.isJmxEnabled())
00909 {
00910 Hashtable data = new Hashtable();
00911 data.put("driver", backend.getDriverClassName());
00912 String checkpoint = backend.getLastKnownCheckpoint();
00913 checkpoint = (checkpoint == null) ? "" : checkpoint;
00914 data.put("checkpoint", checkpoint);
00915 data.put("name", backend.getName());
00916 data.put("url", backend.getURL());
00917 RmiConnector.broadcastNotification(this,
00918 CjdbcNotificationList.VIRTUALDATABASE_BACKEND_ENABLED,
00919 CjdbcNotificationList.NOTIFICATION_LEVEL_INFO, Translate.get(
00920 "notification.backend.enabled", backend.getName()), data);
00921 }
00922 }
00923 catch (Exception e)
00924 {
00925 e.printStackTrace();
00926 throw new VirtualDatabaseException(e.getMessage());
00927 }
00928 }
00929
00930
00931
00932
00933
00934
00935
00936
00937 public void enableBackendFromCheckpoint(String backendName,
00938 String checkpointName) throws VirtualDatabaseException
00939 {
00940
00941 try
00942 {
00943 DatabaseBackend backend = getAndCheckBackend(backendName,
00944 CHECK_BACKEND_ENABLE);
00945 requestManager.enableBackendFromCheckpoint(backend, checkpointName);
00946 requestManager.setDatabaseSchema(
00947 getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames(),
00948 false);
00949
00950
00951 getStaticMetaData().gatherStaticMetadata(backend);
00952
00953
00954 if (databaseProductNames.indexOf(backend.getDatabaseProductName()) == -1)
00955 databaseProductNames += "," + backend.getDatabaseProductName();
00956 }
00957 catch (Exception e)
00958 {
00959 throw new VirtualDatabaseException(
00960 "Failed to enable backend from checkpoint: " + e);
00961 }
00962 }
00963
00964
00965
00966
00967 public void enableBackendFromCheckpoint(String backendName)
00968 throws VirtualDatabaseException
00969 {
00970 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND);
00971 String checkpoint = backend.getLastKnownCheckpoint();
00972 if (checkpoint == null)
00973 throw new VirtualDatabaseException("No last checkpoint for backend:"
00974 + backendName);
00975 else
00976 {
00977 if (logger.isDebugEnabled())
00978 logger.debug("Enabling backend:" + backendName
00979 + " from its last checkpoint " + backend.getLastKnownCheckpoint());
00980 }
00981 enableBackendFromCheckpoint(backendName, backend.getLastKnownCheckpoint());
00982 }
00983
00984
00985
00986
00987
00988
00989 public void enableAllBackends() throws VirtualDatabaseException
00990 {
00991 try
00992 {
00993 int size = this.backends.size();
00994 DatabaseBackend dbe;
00995 for (int i = 0; i < size; i++)
00996 {
00997 dbe = (DatabaseBackend) backends.get(i);
00998 if (!dbe.isReadEnabled())
00999 enableBackend(((DatabaseBackend) backends.get(i)).getName());
01000 }
01001 }
01002 catch (Exception e)
01003 {
01004 logger.error(e);
01005 throw new VirtualDatabaseException(e.getMessage());
01006 }
01007 }
01008
01009
01010
01011
01012 public void enableAllBackendsFromCheckpoint() throws VirtualDatabaseException
01013 {
01014 AbstractRecoveryLog log = requestManager.getRecoveryLog();
01015 if (log == null)
01016 {
01017 logger
01018 .warn("No recovery log has been configured, enabling backend without checkpoint.");
01019 enableAllBackends();
01020 }
01021 else
01022 {
01023 try
01024 {
01025 int size = this.backends.size();
01026 DatabaseBackend dbe;
01027 String backendName;
01028 BackendRecoveryInfo info;
01029 for (int i = 0; i < size; i++)
01030 {
01031 dbe = (DatabaseBackend) backends.get(i);
01032 backendName = dbe.getName();
01033 info = log.getBackendRecoveryInfo(name, backendName);
01034 switch (info.getBackendState())
01035 {
01036 case BackendState.DISABLED :
01037 String checkpoint = info.getCheckpoint();
01038 if (checkpoint == null || checkpoint.equals(""))
01039 {
01040 logger.warn("Enabling backend " + backendName
01041 + " with no checkpoint.");
01042 enableBackend(dbe.getName());
01043 }
01044 else
01045 {
01046 logger.info("Enabling backend " + backendName
01047 + " from checkpoint " + checkpoint);
01048 enableBackendFromCheckpoint(dbe.getName(), checkpoint);
01049 }
01050 continue;
01051 case BackendState.UNKNOWN :
01052 logger.info("Unknown last state for backend " + backendName
01053 + ". Leaving node in "
01054 + (dbe.isReadEnabled() ? "enabled" : "disabled") + " state.");
01055 continue;
01056 case BackendState.BACKUPING :
01057 case BackendState.DISABLING :
01058 case BackendState.RECOVERING :
01059 case BackendState.REPLAYING :
01060 logger.info("Unexpected transition state ("
01061 + info.getBackendState() + ") for backend " + backendName
01062 + ". Leaving node in "
01063 + (dbe.isReadEnabled() ? "enabled" : "disabled") + " state.");
01064 continue;
01065 default :
01066 logger.info("Trying to enable a backend " + backendName
01067 + " that is already in an enabled state.");
01068 break;
01069 }
01070 }
01071 }
01072 catch (Exception e)
01073 {
01074 throw new VirtualDatabaseException(e.getMessage());
01075 }
01076 }
01077
01078 }
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089 public void forceEnableAllBackendsFromCheckpoint(String checkpoint)
01090 throws VirtualDatabaseException
01091 {
01092 if (checkpoint == null || checkpoint.equals(""))
01093 enableAllBackends();
01094 else
01095 {
01096 try
01097 {
01098 int size = this.backends.size();
01099 DatabaseBackend backend;
01100 for (int i = 0; i < size; i++)
01101 {
01102 backend = (DatabaseBackend) backends.get(i);
01103 if (!backend.isReadEnabled())
01104 {
01105 backend.setLastKnownCheckpoint(checkpoint);
01106 enableBackendFromCheckpoint(backend.getName(), checkpoint);
01107 }
01108 }
01109 }
01110 catch (Exception e)
01111 {
01112 throw new VirtualDatabaseException(e.getMessage());
01113 }
01114 }
01115 }
01116
01117
01118
01119
01120 public ArrayList getAllBackendNames() throws VirtualDatabaseException
01121 {
01122 try
01123 {
01124 acquireReadLockBackendLists();
01125 }
01126 catch (InterruptedException e)
01127 {
01128 String msg = "Unable to acquire read lock on backend list in getAllBackendNames ("
01129 + e + ")";
01130 logger.error(msg);
01131 throw new VirtualDatabaseException(msg);
01132 }
01133
01134 int size = backends.size();
01135 ArrayList result = new ArrayList();
01136 for (int i = 0; i < size; i++)
01137 {
01138 result.add(((DatabaseBackend) backends.get(i)).getName());
01139 }
01140
01141 releaseReadLockBackendLists();
01142 return result;
01143 }
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158 public DatabaseBackend getAndCheckBackend(String backendName, int testEnable)
01159 throws VirtualDatabaseException
01160 {
01161 try
01162 {
01163 acquireReadLockBackendLists();
01164 }
01165 catch (InterruptedException e)
01166 {
01167 String msg = "Unable to acquire read lock on backend list in getAndCheckBackend ("
01168 + e + ")";
01169 logger.error(msg);
01170 throw new VirtualDatabaseException(msg);
01171 }
01172
01173
01174 int size = backends.size();
01175 DatabaseBackend b = null;
01176 for (int i = 0; i < size; i++)
01177 {
01178 b = (DatabaseBackend) backends.get(i);
01179 if (b.getName().equals(backendName))
01180 break;
01181 else
01182 b = null;
01183 }
01184
01185
01186 if (b == null)
01187 {
01188 releaseReadLockBackendLists();
01189 String msg = "Trying to access a non-existing backend " + backendName;
01190 logger.warn(msg);
01191 throw new VirtualDatabaseException(msg);
01192 }
01193
01194
01195 switch (testEnable)
01196 {
01197 case NO_CHECK_BACKEND :
01198 break;
01199 case CHECK_BACKEND_DISABLE :
01200 if (!b.isReadEnabled())
01201 {
01202 releaseReadLockBackendLists();
01203 String msg = "Backend " + backendName + " is already disabled";
01204 logger.warn(msg);
01205 throw new VirtualDatabaseException(msg);
01206 }
01207 break;
01208 case CHECK_BACKEND_ENABLE :
01209 if (b.isReadEnabled())
01210 {
01211 releaseReadLockBackendLists();
01212 String msg = "Backend " + backendName + " is already enabled";
01213 logger.warn(msg);
01214 throw new VirtualDatabaseException(msg);
01215 }
01216 break;
01217 default :
01218 releaseReadLockBackendLists();
01219 String msg = "Unexpected parameter in getAndCheckBackend(...)";
01220 logger.error(msg);
01221 throw new VirtualDatabaseException(msg);
01222 }
01223
01224 releaseReadLockBackendLists();
01225
01226 if (testEnable == CHECK_BACKEND_ENABLE)
01227 {
01228
01229 try
01230 {
01231 if (logger.isDebugEnabled())
01232 logger.debug("Initializing connections for backend " + b.getName());
01233 b.initializeConnections();
01234
01235 b.checkDriverCompliance();
01236
01237 if (logger.isDebugEnabled())
01238 logger.debug("Checking schema for backend " + b.getName());
01239 b.checkDatabaseSchema();
01240
01241 DatabaseSchema backendSchema = b.getDatabaseSchema();
01242
01243 if (backendSchema != null)
01244 requestManager.mergeDatabaseSchema(backendSchema);
01245 else
01246 logger.warn("Backend " + b.getName() + " has no defined schema.");
01247 }
01248 catch (SQLException e)
01249 {
01250 String msg = "Error while initalizing database backend " + b.getName()
01251 + " (" + e + ")";
01252 logger.warn(msg, e);
01253 throw new VirtualDatabaseException(msg);
01254 }
01255 }
01256
01257 return b;
01258 }
01259
01260
01261
01262
01263
01264 public void replicateBackend(String backendName, String newBackendName,
01265 Map parameters) throws VirtualDatabaseException
01266 {
01267
01268 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND);
01269 DatabaseBackend newBackend = null;
01270
01271
01272 try
01273 {
01274 newBackend = backend.copy(newBackendName, parameters);
01275 }
01276 catch (Exception e)
01277 {
01278 String msg = Translate.get("virtualdatabase.fail.backend.copy");
01279 logger.warn(msg, e);
01280 throw new VirtualDatabaseException(msg);
01281 }
01282
01283
01284 addBackend(newBackend);
01285 }
01286
01287
01288
01289
01290 public void removeBackend(String backend) throws VirtualDatabaseException
01291 {
01292 removeBackend(getAndCheckBackend(backend, NO_CHECK_BACKEND));
01293 }
01294
01295
01296
01297
01298
01299
01300
01301 public void removeBackend(DatabaseBackend db) throws VirtualDatabaseException
01302 {
01303 if (db == null)
01304 {
01305 String msg = "Illegal null database backend in removeBackend(DatabaseBackend) method";
01306 logger.error(msg);
01307 throw new VirtualDatabaseException(msg);
01308 }
01309
01310 try
01311 {
01312 rwLock.acquireWrite();
01313 }
01314 catch (InterruptedException e)
01315 {
01316 String msg = Translate.get(
01317 "loadbalancer.backendlist.acquire.writelock.failed", e);
01318 logger.error(msg);
01319 throw new VirtualDatabaseException(msg);
01320 }
01321
01322
01323 int idx = backends.indexOf(db);
01324 if (idx == -1)
01325 {
01326 rwLock.releaseWrite();
01327 String msg = "Trying to remove a non-existing backend " + db.getName();
01328 logger.warn(msg);
01329 throw new VirtualDatabaseException(msg);
01330 }
01331
01332 if (((DatabaseBackend) backends.get(idx)).isReadEnabled())
01333 {
01334 rwLock.releaseWrite();
01335 String msg = "Trying to remove an enabled backend " + db.getName();
01336 logger.error(msg);
01337 throw new VirtualDatabaseException(msg);
01338 }
01339
01340
01341 backends.remove(idx);
01342 rwLock.releaseWrite();
01343
01344
01345 if (MBeanServerManager.isJmxEnabled())
01346 {
01347
01348 Hashtable data = new Hashtable();
01349 data.put(CjdbcNotificationList.DATA_DATABASE, this.name);
01350 data.put(CjdbcNotificationList.DATA_DRIVER, db.getDriverClassName());
01351 String checkpoint = db.getLastKnownCheckpoint();
01352 checkpoint = (checkpoint == null) ? "" : checkpoint;
01353 data.put(CjdbcNotificationList.DATA_CHECKPOINT, checkpoint);
01354 data.put(CjdbcNotificationList.DATA_NAME, db.getName());
01355 data.put(CjdbcNotificationList.DATA_URL, db.getURL());
01356 RmiConnector.broadcastNotification(this,
01357 CjdbcNotificationList.VIRTUALDATABASE_BACKEND_REMOVED,
01358 CjdbcNotificationList.NOTIFICATION_LEVEL_INFO, Translate.get(
01359 "notification.backend.removed", db.getName()), data);
01360
01361
01362 ObjectName objectName = JmxConstants.getDatabaseBackendObjectName(name,
01363 db.getName());
01364 try
01365 {
01366 MBeanServerManager.unregister(objectName);
01367 }
01368 catch (JmxException e1)
01369 {
01370 logger.error(Translate.get(
01371 "virtualdatabase.fail.unregister.backend.mbean", db.getName()), e1);
01372 }
01373 }
01374
01375 if (logger.isDebugEnabled())
01376 logger.debug("Backend " + db.getName() + " removed successfully");
01377 }
01378
01379
01380
01381
01382
01383 public void transferBackend(String backend, String controllerDestination)
01384 throws VirtualDatabaseException
01385 {
01386 throw new VirtualDatabaseException("Cannot transfer backend to controller:"
01387 + controllerDestination + " because database is not distributed");
01388 }
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398 public void backupBackendWithCheckpoint(String backendName,
01399 String checkpointName, ArrayList tables) throws VirtualDatabaseException
01400 {
01401 try
01402 {
01403 DatabaseBackend db = getAndCheckBackend(backendName, NO_CHECK_BACKEND);
01404 requestManager.backupBackendWithCheckpoint(db, checkpointName, tables, db
01405 .isReadEnabled(), true, null);
01406 }
01407 catch (SQLException sql)
01408 {
01409 throw new VirtualDatabaseException(sql.getMessage());
01410 }
01411 }
01412
01413
01414
01415
01416 public File[] getAvailableDumpFiles()
01417 {
01418 File f = new File(getRequestManager().getBackupManager().getBackupDir());
01419 if (f.exists())
01420 {
01421 return f.listFiles(new FilenameFilter()
01422 {
01423
01424
01425
01426 public boolean accept(File dir, String name)
01427 {
01428 if (name.endsWith(Constants.ZIP_EXT))
01429 return true;
01430 else
01431 return false;
01432 }
01433 });
01434 }
01435 else
01436 return new File[0];
01437 }
01438
01439
01440
01441
01442 public boolean removeDumpFile(File dumpFile)
01443 {
01444 logger.info(Translate.get("controller.remove.dump", dumpFile.getName()));
01445 if (!dumpFile.delete())
01446 {
01447 logger.info(Translate.get("controller.remove.dump.failed", dumpFile
01448 .getName()));
01449 dumpFile = new File(getRequestManager().getBackupManager().getBackupDir()
01450 + File.separatorChar + dumpFile.getName());
01451 logger.info(Translate.get("controller.remove.dump", dumpFile.getName()));
01452 if (!dumpFile.delete())
01453 {
01454 logger.info(Translate.get("controller.remove.dump.failed", dumpFile
01455 .getName()));
01456 return false;
01457 }
01458 else
01459 return true;
01460 }
01461 else
01462 return true;
01463 }
01464
01465
01466
01467
01468
01469
01470
01471 public void removeCheckpoint(String checkpointName)
01472 throws VirtualDatabaseException
01473 {
01474 try
01475 {
01476 requestManager.removeCheckpoint(checkpointName);
01477 }
01478 catch (Exception e)
01479 {
01480 throw new VirtualDatabaseException(e.getMessage());
01481 }
01482 }
01483
01484
01485
01486
01487
01488 public void restoreDumpOnBackend(String databaseBackendName,
01489 String checkpointName) throws VirtualDatabaseException, BackupException,
01490 OctopusException
01491 {
01492 DatabaseBackend backend = getAndCheckBackend(databaseBackendName,
01493 NO_CHECK_BACKEND);
01494
01495
01496 requestManager.restoreBackendFromBackupCheckpoint(backend, checkpointName,
01497 true, null);
01498 }
01499
01500
01501
01502
01503 public void setBackendLastKnownCheckpoint(String backendName,
01504 String checkpoint) throws VirtualDatabaseException
01505 {
01506 AbstractRecoveryLog log = requestManager.getRecoveryLog();
01507 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND);
01508 if (log == null)
01509 throw new VirtualDatabaseException(ExceptionTypes.NO_RECOVERY_LOG);
01510 else
01511 {
01512 if (!backend.isDisabled())
01513 throw new VirtualDatabaseException(
01514 "Cannot setLastKnownCheckpoint on a non-disabled backend");
01515 else
01516 {
01517 try
01518 {
01519 log.storeBackendRecoveryInfo(this.name,
01520 new BackendRecoveryInfo(backend.getName(), checkpoint, backend
01521 .getStateValue(), this.name));
01522
01523 backend.setLastKnownCheckpoint(checkpoint);
01524 }
01525 catch (SQLException e)
01526 {
01527 throw new VirtualDatabaseException(
01528 "Failed to store recovery info for backend '" + backendName
01529 + "' (" + e + ")");
01530 }
01531 }
01532 }
01533 }
01534
01535
01536
01537
01538 public ArrayList viewCheckpointNames()
01539 {
01540 try
01541 {
01542 AbstractRecoveryLog recoveryLog = requestManager.getRecoveryLog();
01543 if (recoveryLog == null)
01544 return new ArrayList();
01545 else
01546 return recoveryLog.getCheckpointNames();
01547 }
01548 catch (SQLException e)
01549 {
01550 return new ArrayList();
01551 }
01552 }
01553
01554
01555
01556
01557
01558
01559
01560
01561 public void addCurrentNbOfThread()
01562 {
01563 currentNbOfThreads++;
01564 }
01565
01566
01567
01568
01569
01570 public void addIdleThread()
01571 {
01572 idleThreads++;
01573 }
01574
01575
01576
01577
01578 public int getCurrentNbOfThreads()
01579 {
01580 return currentNbOfThreads;
01581 }
01582
01583
01584
01585
01586
01587
01588
01589 public int getIdleThreads()
01590 {
01591 return idleThreads;
01592 }
01593
01594
01595
01596
01597
01598
01599 public int getMaxNbOfThreads()
01600 {
01601 return maxNbOfThreads;
01602 }
01603
01604
01605
01606
01607
01608
01609 public long getMaxThreadIdleTime()
01610 {
01611 return maxThreadIdleTime;
01612 }
01613
01614
01615
01616
01617
01618
01619 public int getMinNbOfThreads()
01620 {
01621 return minNbOfThreads;
01622 }
01623
01624
01625
01626
01627
01628
01629 public boolean isPoolConnectionThreads()
01630 {
01631 return poolConnectionThreads;
01632 }
01633
01634
01635
01636
01637
01638 public void removeCurrentNbOfThread()
01639 {
01640 currentNbOfThreads--;
01641 }
01642
01643
01644
01645
01646
01647 public void removeIdleThread()
01648 {
01649 idleThreads--;
01650 }
01651
01652
01653
01654
01655
01656
01657 public void setMaxThreadIdleTime(long maxThreadIdleTime)
01658 {
01659 this.maxThreadIdleTime = maxThreadIdleTime;
01660 }
01661
01662
01663
01664
01665
01666
01667 public void setMinNbOfThreads(int minNbOfThreads)
01668 {
01669 this.minNbOfThreads = minNbOfThreads;
01670 }
01671
01672
01673
01674
01675
01676
01677 public void setPoolConnectionThreads(boolean poolConnectionThreads)
01678 {
01679 this.poolConnectionThreads = poolConnectionThreads;
01680 }
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691 public ArrayList getActiveThreads()
01692 {
01693 return activeThreads;
01694 }
01695
01696
01697
01698
01699
01700
01701 public AuthenticationManager getAuthenticationManager()
01702 {
01703 return authenticationManager;
01704 }
01705
01706
01707
01708
01709 public String getBackendInformation(String backendName)
01710 throws VirtualDatabaseException
01711 {
01712 try
01713 {
01714 acquireReadLockBackendLists();
01715 }
01716 catch (InterruptedException e)
01717 {
01718 String msg = "Unable to acquire read lock on backend list in getBackendInformation ("
01719 + e + ")";
01720 logger.error(msg);
01721 throw new VirtualDatabaseException(msg);
01722 }
01723
01724
01725 int size = backends.size();
01726 DatabaseBackend b = null;
01727 for (int i = 0; i < size; i++)
01728 {
01729 b = (DatabaseBackend) backends.get(i);
01730 if (b.getName().equals(backendName))
01731 break;
01732 else
01733 b = null;
01734 }
01735
01736 if (b == null)
01737 {
01738 releaseReadLockBackendLists();
01739 String msg = "Backend " + backendName + " does not exists.";
01740 logger.warn(msg);
01741 throw new VirtualDatabaseException(msg);
01742 }
01743
01744 releaseReadLockBackendLists();
01745 return b.getXml();
01746 }
01747
01748
01749
01750
01751
01752
01753 public ArrayList getBackends()
01754 {
01755 return backends;
01756 }
01757
01758
01759
01760
01761 public String getBackendSchema(String backendName)
01762 throws VirtualDatabaseException
01763 {
01764 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND);
01765
01766
01767 try
01768 {
01769 return XmlTools.prettyXml(backend.getSchemaXml(true));
01770 }
01771 catch (Exception e)
01772 {
01773 throw new VirtualDatabaseException(e.getMessage());
01774 }
01775 }
01776
01777
01778
01779
01780 public String getBackendState(String backendName)
01781 throws VirtualDatabaseException
01782 {
01783 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND);
01784 return backend.getState();
01785 }
01786
01787
01788
01789
01790
01791
01792 public AbstractBlobFilter getBlobFilter()
01793 {
01794 return blobFilter;
01795 }
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805 public String getDatabaseName()
01806 {
01807 return name;
01808 }
01809
01810
01811
01812
01813 public String getDatabaseProductName()
01814 {
01815 return databaseProductNames;
01816 }
01817
01818
01819
01820
01821
01822 public VirtualDatabaseDynamicMetaData getDynamicMetaData()
01823 {
01824 if (metadata == null)
01825 {
01826 metadata = new VirtualDatabaseDynamicMetaData(this);
01827 }
01828 return metadata;
01829 }
01830
01831
01832
01833
01834
01835
01836
01837
01838 public DatabaseSchema getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames()
01839 throws SQLException
01840 {
01841 try
01842 {
01843 acquireReadLockBackendLists();
01844 }
01845 catch (InterruptedException e)
01846 {
01847 String msg = "Unable to acquire read lock on backend list in getDatabaseSchemaFromActiveBackends ("
01848 + e + ")";
01849 logger.error(msg);
01850 throw new SQLException(msg);
01851 }
01852
01853 int size = backends.size();
01854 DatabaseSchema schema = null;
01855 DatabaseBackend b = null;
01856 String dbProductNames = "C-JDBC";
01857 for (int i = 0; i < size; i++)
01858 {
01859 b = (DatabaseBackend) backends.get(i);
01860 if (b.isReadEnabled())
01861 {
01862
01863
01864 if (requestManager.getRequiredParsingGranularity() == ParsingGranularities.NO_PARSING)
01865 b.refreshSchema();
01866 if (schema == null)
01867 schema = new DatabaseSchema(b.getDatabaseSchema());
01868 else
01869 schema.mergeSchema(b.getDatabaseSchema());
01870 }
01871
01872
01873 if (dbProductNames.indexOf(b.getDatabaseProductName()) == -1)
01874 dbProductNames += "," + b.getDatabaseProductName();
01875 }
01876
01877 releaseReadLockBackendLists();
01878 databaseProductNames = dbProductNames;
01879 if (logger.isDebugEnabled())
01880 logger.debug("getDatabaseSchemaFromActiveBackends - end");
01881 if (requestManager.getRecoveryLog() != null)
01882 {
01883 try
01884 {
01885 JDBCRecoveryLog log = (JDBCRecoveryLog) requestManager.getRecoveryLog();
01886
01887 if (schema.hasTable(log.getBackendTableName()))
01888 schema.removeTable(new DatabaseTable(log.getBackendTableName()));
01889 if (schema.hasTable(log.getCheckpointTableName()))
01890 schema.removeTable(new DatabaseTable(log.getCheckpointTableName()));
01891 if (schema.hasTable(log.getLogTableName()))
01892 schema.removeTable(new DatabaseTable(log.getLogTableName()));
01893 }
01894 catch (RuntimeException ignore)
01895 {
01896
01897 }
01898 }
01899 return schema;
01900 }
01901
01902
01903
01904
01905
01906
01907 public int getMaxNbOfConnections()
01908 {
01909 return maxNbOfConnections;
01910 }
01911
01912
01913
01914
01915
01916
01917 public ArrayList getPendingConnections()
01918 {
01919 return pendingConnections;
01920 }
01921
01922
01923
01924
01925
01926
01927 public RequestManager getRequestManager()
01928 {
01929 return requestManager;
01930 }
01931
01932
01933
01934
01935
01936
01937
01938 public VirtualDatabaseStaticMetaData getStaticMetaData()
01939 {
01940 if (staticMetadata == null)
01941 {
01942 staticMetadata = new VirtualDatabaseStaticMetaData(this);
01943 }
01944 return staticMetadata;
01945 }
01946
01947
01948
01949
01950
01951
01952 public String getVirtualDatabaseName()
01953 {
01954 return name;
01955 }
01956
01957
01958
01959
01960
01961
01962
01963 public SQLMonitoring getSQLMonitor()
01964 {
01965 return sqlMonitor;
01966 }
01967
01968
01969
01970
01971
01972
01973
01974 public int getSQLShortFormLength()
01975 {
01976 return sqlShortFormLength;
01977 }
01978
01979
01980
01981
01982 public boolean hasRecoveryLog()
01983 {
01984 AbstractRecoveryLog log = requestManager.getRecoveryLog();
01985 if (log == null)
01986 return false;
01987 else
01988 return true;
01989 }
01990
01991
01992
01993
01994 public boolean hasResultCache()
01995 {
01996 AbstractResultCache cache = requestManager.getResultCache();
01997 if (cache == null)
01998 return false;
01999 else
02000 return true;
02001 }
02002
02003
02004
02005
02006
02007
02008
02009 public void setAuthenticationManager(
02010 AuthenticationManager authenticationManager)
02011 {
02012 this.authenticationManager = authenticationManager;
02013 }
02014
02015
02016
02017
02018
02019
02020 public void setBlobFilter(AbstractBlobFilter filter)
02021 {
02022 this.blobFilter = filter;
02023 }
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033 public void setDatabaseSchema(DatabaseSchema schema, boolean isStatic)
02034 {
02035 if (requestManager != null)
02036 requestManager.setDatabaseSchema(schema, isStatic);
02037 else
02038 logger
02039 .warn("Unable to set database schema, no request manager has been defined.");
02040 }
02041
02042
02043
02044
02045
02046
02047 public void setMaxNbOfConnections(int maxNbOfConnections)
02048 {
02049 this.maxNbOfConnections = maxNbOfConnections;
02050 }
02051
02052
02053
02054
02055
02056
02057 public void setMaxNbOfThreads(int maxNbOfThreads)
02058 {
02059 this.maxNbOfThreads = maxNbOfThreads;
02060 }
02061
02062
02063
02064
02065
02066
02067 public void setRequestManager(RequestManager requestManager)
02068 {
02069 this.requestManager = requestManager;
02070 }
02071
02072
02073
02074
02075
02076
02077 public void setSQLMonitor(SQLMonitoring sqlMonitor)
02078 {
02079 this.sqlMonitor = sqlMonitor;
02080 }
02081
02082
02083
02084
02085 public void setMonitoringToActive(boolean active)
02086 throws VirtualDatabaseException
02087 {
02088 if (sqlMonitor == null)
02089 throw new VirtualDatabaseException(Translate
02090 .get("virtualdatabase.monitoring.not.defined"));
02091 else
02092 sqlMonitor.setActive(active);
02093 }
02094
02095
02096
02097
02098
02099
02100
02101 public boolean equals(Object other)
02102 {
02103 if ((other == null) || (!(other instanceof VirtualDatabase)))
02104 return false;
02105 else
02106 {
02107 VirtualDatabase db = (VirtualDatabase) other;
02108 return name.equals(db.getDatabaseName());
02109 }
02110 }
02111
02112
02113
02114
02115
02116
02117
02118
02119 public void cleanMonitoringData() throws VirtualDatabaseException
02120 {
02121 if (sqlMonitor == null)
02122 throw new VirtualDatabaseException(Translate
02123 .get("virtualdatabase.monitoring.not.defined"));
02124 else
02125 sqlMonitor.cleanStats();
02126 }
02127
02128
02129
02130
02131 public String[][] retrieveBackendsData() throws VirtualDatabaseException
02132 {
02133 try
02134 {
02135 acquireReadLockBackendLists();
02136 }
02137 catch (InterruptedException e)
02138 {
02139 String msg = Translate.get("virtualdatabase.fail.read.lock", e);
02140 throw new VirtualDatabaseException(msg);
02141 }
02142 ArrayList backends = this.getBackends();
02143 int backendListSize = backends.size();
02144 String[][] data = new String[backendListSize][];
02145 for (int i = 0; i < backendListSize; i++)
02146 {
02147 data[i] = ((DatabaseBackend) backends.get(i)).getBackendData();
02148 }
02149 releaseReadLockBackendLists();
02150 return data;
02151 }
02152
02153
02154
02155
02156
02157
02158 public boolean isShuttingDown()
02159 {
02160 return shuttingDown;
02161 }
02162
02163
02164
02165
02166 public void shutdown(int level)
02167 {
02168 VirtualDatabaseShutdownThread vdst = null;
02169 synchronized (this)
02170 {
02171 if (shuttingDown)
02172 return;
02173 switch (level)
02174 {
02175 case Constants.SHUTDOWN_WAIT :
02176 vdst = new VirtualDatabaseWaitShutdownThread(this);
02177 logger.info(Translate.get("controller.shutdown.type.wait", this
02178 .getVirtualDatabaseName()));
02179 break;
02180 case Constants.SHUTDOWN_SAFE :
02181 shuttingDown = true;
02182 vdst = new VirtualDatabaseSafeShutdownThread(this);
02183 logger.info(Translate.get("controller.shutdown.type.safe", this
02184 .getVirtualDatabaseName()));
02185 break;
02186 case Constants.SHUTDOWN_FORCE :
02187 shuttingDown = true;
02188 vdst = new VirtualDatabaseForceShutdownThread(this);
02189 logger.warn(Translate.get("controller.shutdown.type.force", this
02190 .getVirtualDatabaseName()));
02191 break;
02192 default :
02193 String msg = Translate
02194 .get("controller.shutdown.unknown.level", level);
02195 logger.error(msg);
02196 throw new RuntimeException(msg);
02197 }
02198 }
02199
02200 new Thread(vdst.getShutdownGroup(), vdst, "VirtualDatabase Shutdown Thread")
02201 .start();
02202 }
02203
02204
02205
02206
02207 public void storeBackendsInfo()
02208 {
02209 requestManager.storeBackendsInfo(this.name, getBackends());
02210 }
02211
02212
02213
02214
02215
02216
02217
02218 public ArrayList viewAllClientNames()
02219 {
02220 ArrayList list = this.getActiveThreads();
02221 int size = list.size();
02222 ArrayList clients = new ArrayList(size);
02223 for (int i = 0; i < list.size(); i++)
02224 clients.add(((VirtualDatabaseWorkerThread) list.get(i)).getUser());
02225 return clients;
02226 }
02227
02228
02229
02230
02231 public String[] viewBackendInformation(String backendName)
02232 throws VirtualDatabaseException
02233 {
02234 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND);
02235 return backend.getBackendData();
02236 }
02237
02238
02239
02240
02241 public String[] viewControllerList()
02242 {
02243 return new String[]{viewOwningController()};
02244 }
02245
02246
02247
02248
02249 public Hashtable viewGroupBackends() throws VirtualDatabaseException
02250 {
02251 Hashtable map = new Hashtable();
02252 map.put(controller.getJmxName(), getAllBackendNames());
02253 return map;
02254 }
02255
02256
02257
02258
02259 public String viewOwningController()
02260 {
02261 return controller.getJmxName();
02262 }
02263
02264
02265
02266
02267 public String getAssociatedString()
02268 {
02269 return "virtualdatabase";
02270 }
02271
02272
02273
02274
02275
02276
02277 public String getXml()
02278 {
02279 StringBuffer info = new StringBuffer();
02280 info.append("<C-JDBC>");
02281 info.append("<" + DatabasesXmlTags.ELT_VirtualDatabase + " "
02282 + DatabasesXmlTags.ATT_name + "=\"" + this.getVirtualDatabaseName()
02283 + "\" " + DatabasesXmlTags.ATT_maxNbOfConnections + "=\""
02284 + this.getMaxNbOfConnections() + "\" "
02285 + DatabasesXmlTags.ATT_poolThreads + "=\""
02286 + this.isPoolConnectionThreads() + "\" "
02287 + DatabasesXmlTags.ATT_minNbOfThreads + "=\""
02288 + this.getMinNbOfThreads() + "\" "
02289 + DatabasesXmlTags.ATT_maxNbOfThreads + "=\""
02290 + this.getMaxNbOfThreads() + "\" "
02291 + DatabasesXmlTags.ATT_maxThreadIdleTime + "=\""
02292 + this.getMaxThreadIdleTime() / 1000 + "\" "
02293 + DatabasesXmlTags.ATT_sqlDumpLength + "=\"" + this.sqlShortFormLength
02294 + "\" " + DatabasesXmlTags.ATT_blobEncodingMethod + "=\""
02295 + this.blobFilter.getXml() + "\">");
02296
02297 info.append(getDistributionXml());
02298
02299 if (this.getSQLMonitor() != null)
02300 info.append(sqlMonitor.getXml());
02301
02302 info.append(requestManager.getBackupManager().getXml());
02303
02304 if (this.getAuthenticationManager() != null)
02305 info.append(authenticationManager.getXml());
02306
02307 try
02308 {
02309 acquireReadLockBackendLists();
02310 int size = backends.size();
02311 for (int i = 0; i < size; i++)
02312 info.append(((DatabaseBackend) backends.get(i)).getXml());
02313 releaseReadLockBackendLists();
02314 }
02315 catch (InterruptedException e)
02316 {
02317 logger.error(Translate.get("virtualdatabase.fail.read.lock", e));
02318 }
02319 if (requestManager != null)
02320 info.append(requestManager.getXml());
02321 info.append("</" + DatabasesXmlTags.ELT_VirtualDatabase + ">");
02322 info.append("</C-JDBC>");
02323 return info.toString();
02324 }
02325
02326
02327
02328
02329
02330
02331 protected String getDistributionXml()
02332 {
02333 return "";
02334 }
02335
02336 }