1 24 25 package org.objectweb.cjdbc.controller.backend; 26 27 import java.io.StringReader ; 28 import java.net.ConnectException ; 29 import java.sql.Connection ; 30 import java.sql.SQLException ; 31 import java.sql.Savepoint ; 32 import java.sql.Statement ; 33 import java.util.ArrayList ; 34 import java.util.HashMap ; 35 import java.util.Hashtable ; 36 import java.util.Iterator ; 37 import java.util.List ; 38 import java.util.Map ; 39 import java.util.Vector ; 40 41 import javax.management.NotCompliantMBeanException ; 42 43 import org.dom4j.Document; 44 import org.dom4j.Element; 45 import org.dom4j.io.SAXReader; 46 import org.objectweb.cjdbc.common.exceptions.NoTransactionStartWhenDisablingException; 47 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException; 48 import org.objectweb.cjdbc.common.i18n.Translate; 49 import org.objectweb.cjdbc.common.jmx.mbeans.DatabaseBackendMBean; 50 import org.objectweb.cjdbc.common.jmx.notifications.CjdbcNotificationList; 51 import org.objectweb.cjdbc.common.log.Trace; 52 import org.objectweb.cjdbc.common.monitor.backend.BackendStatistics; 53 import org.objectweb.cjdbc.common.shared.BackendInfo; 54 import org.objectweb.cjdbc.common.shared.BackendState; 55 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest; 56 import org.objectweb.cjdbc.common.sql.CreateRequest; 57 import org.objectweb.cjdbc.common.sql.metadata.MetadataContainer; 58 import org.objectweb.cjdbc.common.sql.schema.DatabaseSchema; 59 import org.objectweb.cjdbc.common.sql.schema.DatabaseTable; 60 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags; 61 import org.objectweb.cjdbc.common.xml.XmlComponent; 62 import org.objectweb.cjdbc.controller.backend.rewriting.AbstractRewritingRule; 63 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager; 64 import org.objectweb.cjdbc.controller.connection.FailFastPoolConnectionManager; 65 import org.objectweb.cjdbc.controller.connection.RandomWaitPoolConnectionManager; 66 import org.objectweb.cjdbc.controller.connection.SimpleConnectionManager; 67 import org.objectweb.cjdbc.controller.connection.VariablePoolConnectionManager; 68 import org.objectweb.cjdbc.controller.jmx.AbstractStandardMBean; 69 import org.objectweb.cjdbc.controller.jmx.MBeanServerManager; 70 import org.objectweb.cjdbc.controller.jmx.RmiConnector; 71 import org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer; 72 73 86 public final class DatabaseBackend extends AbstractStandardMBean 87 implements 88 XmlComponent, 89 DatabaseBackendMBean 90 { 91 102 103 private String name; 104 105 106 private String driverPath; 107 108 109 private String driverClassName; 110 111 112 private transient DriverCompliance driverCompliance; 113 114 115 private String url; 116 117 118 private String virtualDatabaseName; 119 120 121 private boolean writeCanBeEnabled; 122 123 124 private String connectionTestStatement; 125 126 130 private transient DatabaseSchema schema; 131 132 133 private boolean schemaIsStatic = false; 134 135 139 private boolean schemaIsNeededByVdb = true; 140 141 142 private boolean schemaIsDirty = true; 143 144 145 private transient HashMap connectionManagers; 146 147 148 protected transient Trace logger; 149 150 151 private transient ArrayList activeTransactions = new ArrayList (); 152 153 154 private transient Map savepoints = new HashMap (); 155 156 157 private transient Vector pendingRequests = new Vector (); 158 159 160 private int totalRequest; 161 private int totalWriteRequest; 162 private int totalReadRequest; 163 private int totalTransactions; 164 165 166 private ArrayList rewritingRules; 167 168 169 private int dynamicPrecision; 170 private boolean gatherSystemTables = false; 171 private String schemaName = null; 172 173 174 private int sqlShortFormLength = 40; 175 176 private String lastKnownCheckpoint; 177 178 183 private int state = BackendState.DISABLED; 184 185 private transient BackendStateListener stateListener; 186 187 202 public DatabaseBackend(String name, String driverPath, 203 String driverClassName, String url, String vdbName, 204 boolean writeCanBeEnabled, String connectionTestStatement) 205 throws NotCompliantMBeanException 206 { 207 super(DatabaseBackendMBean.class); 208 if (name == null) 209 throw new IllegalArgumentException (Translate 210 .get("backend.null.backend.name")); 211 212 if (driverClassName == null) 213 throw new IllegalArgumentException (Translate.get("backend.null.driver")); 214 215 if (url == null) 216 throw new IllegalArgumentException (Translate.get("backend.null.url")); 217 218 if (vdbName == null) 219 throw new IllegalArgumentException (Translate 220 .get("backend.null.virtualdatabase.name")); 221 222 if (connectionTestStatement == null) 223 throw new IllegalArgumentException (Translate 224 .get("backend.null.connection.test")); 225 226 this.name = name; 227 this.writeCanBeEnabled = writeCanBeEnabled; 228 this.driverPath = driverPath; 229 this.driverClassName = driverClassName; 230 this.url = url; 231 this.virtualDatabaseName = vdbName; 232 this.connectionTestStatement = connectionTestStatement; 233 this.connectionManagers = new HashMap (); 234 logger = Trace 235 .getLogger("org.objectweb.cjdbc.controller.backend.DatabaseBackend." 236 + name); 237 this.driverCompliance = new DriverCompliance(logger); 238 totalRequest = 0; 239 dynamicPrecision = DatabaseBackendSchemaConstants.DynamicPrecisionAll; 240 } 241 242 249 public DatabaseBackend(BackendInfo info) throws NotCompliantMBeanException 250 { 251 this(info.getName(), info.getDriverPath(), info.getDriverClassName(), info 252 .getUrl(), info.getVirtualDatabaseName(), true, info 253 .getConnectionTestStatement()); 254 setDynamicPrecision(info.getDynamicPrecision(), 255 info.isGatherSystemTables(), info.getSchemaName()); 256 try 257 { 258 String xml = info.getXml(); 259 StringReader sreader = new StringReader (xml); 260 SAXReader reader = new SAXReader(); 261 Document document = reader.read(sreader); 262 Element root = document.getRootElement(); 263 Iterator iter1 = root.elementIterator(); 264 while (iter1.hasNext()) 265 { 266 Element elem = (Element) iter1.next(); 267 if (elem.getName().equals(DatabasesXmlTags.ELT_ConnectionManager)) 268 { 269 String vuser = elem.valueOf("@" + DatabasesXmlTags.ATT_vLogin); 270 String rlogin = elem.valueOf("@" + DatabasesXmlTags.ATT_rLogin); 271 String rpassword = elem.valueOf("@" + DatabasesXmlTags.ATT_rPassword); 272 Iterator iter2 = elem.elementIterator(); 273 while (iter2.hasNext()) 274 { 275 Element connectionManager = (Element) iter2.next(); 276 String cname = connectionManager.getName(); 277 if (cname 278 .equals(DatabasesXmlTags.ELT_VariablePoolConnectionManager)) 279 { 280 int minPoolSize = Integer.parseInt(connectionManager.valueOf("@" 281 + DatabasesXmlTags.ATT_minPoolSize)); 282 int maxPoolSize = Integer.parseInt(connectionManager.valueOf("@" 283 + DatabasesXmlTags.ATT_maxPoolSize)); 284 int idleTimeout = Integer.parseInt(connectionManager.valueOf("@" 285 + DatabasesXmlTags.ATT_idleTimeout)); 286 int waitTimeout = Integer.parseInt(connectionManager.valueOf("@" 287 + DatabasesXmlTags.ATT_waitTimeout)); 288 this.addConnectionManager(vuser, 289 new VariablePoolConnectionManager(url, name, rlogin, 290 rpassword, driverPath, driverClassName, minPoolSize, 291 maxPoolSize, idleTimeout, waitTimeout)); 292 } 293 else if (cname.equals(DatabasesXmlTags.ELT_SimpleConnectionManager)) 294 { 295 this.addConnectionManager(vuser, new SimpleConnectionManager(url, 296 name, rlogin, rpassword, driverPath, driverClassName)); 297 } 298 else if (cname 299 .equals(DatabasesXmlTags.ELT_RandomWaitPoolConnectionManager)) 300 { 301 int poolSize = Integer.parseInt(connectionManager.valueOf("@" 302 + DatabasesXmlTags.ATT_poolSize)); 303 int timeout = Integer.parseInt(connectionManager.valueOf("@" 304 + DatabasesXmlTags.ATT_timeout)); 305 this 306 .addConnectionManager(vuser, 307 new RandomWaitPoolConnectionManager(url, name, rlogin, 308 rpassword, driverPath, driverClassName, poolSize, 309 timeout)); 310 } 311 else if (cname 312 .equals(DatabasesXmlTags.ELT_FailFastPoolConnectionManager)) 313 { 314 int poolSize = Integer.parseInt(connectionManager.valueOf("@" 315 + DatabasesXmlTags.ATT_poolSize)); 316 this.addConnectionManager(vuser, 317 new FailFastPoolConnectionManager(url, name, rlogin, 318 rpassword, driverPath, driverClassName, poolSize)); 319 } 320 } 321 } 322 } 323 324 } 325 catch (Exception e) 326 { 327 logger 328 .error(Translate.get("backend.add.connection.manager.failed", e), e); 329 } 330 } 331 332 349 public DatabaseBackend(String name, String driverPath, 350 String driverClassName, String url, String vdbName, 351 String connectionTestStatement, String dynamicSchemaLevel) 352 throws NotCompliantMBeanException 353 { 354 this(name, driverPath, driverClassName, url, vdbName, true, 355 connectionTestStatement); 356 this.dynamicPrecision = DatabaseBackendSchemaConstants 357 .getDynamicSchemaLevel(dynamicSchemaLevel); 358 } 359 360 365 public void setSqlShortFormLength(int sqlShortFormLength) 366 { 367 this.sqlShortFormLength = sqlShortFormLength; 368 } 369 370 376 public int getSQLShortFormLength() 377 { 378 return sqlShortFormLength; 379 } 380 381 382 383 390 public boolean equals(Object other) 391 { 392 if ((other == null) || (!(other instanceof DatabaseBackend))) 393 return false; 394 else 395 { 396 DatabaseBackend b = (DatabaseBackend) other; 397 return name.equals(b.getName()) 398 && driverClassName.equals(b.getDriverClassName()) 399 && url.equals(b.getURL()); 400 } 401 } 402 403 413 public boolean hasTables(ArrayList tables) 414 { 415 DatabaseSchema schemaPtr = getDatabaseSchema(); 416 if (schemaPtr == null) 417 throw new NullPointerException (Translate.get("backend.schema.not.set")); 418 419 if (tables == null) 420 throw new IllegalArgumentException (Translate.get("backend.null.tables")); 421 422 int size = tables.size(); 423 for (int i = 0; i < size; i++) 424 { 425 if (!schemaPtr.hasTable((String ) tables.get(i))) 426 return false; 427 } 428 return true; 429 } 430 431 440 public boolean hasTable(String table) 441 { 442 DatabaseSchema schemaPtr = getDatabaseSchema(); 443 if (schemaPtr == null) 444 throw new NullPointerException (Translate.get("backend.schema.not.set")); 445 446 return schemaPtr.hasTable(table); 447 } 448 449 454 public ArrayList getTables() 455 { 456 DatabaseSchema schemaPtr = getDatabaseSchema(); 457 if (schemaPtr == null) 458 throw new NullPointerException (Translate.get("backend.schema.not.set")); 459 return schemaPtr.getTables(); 460 } 461 462 471 public boolean hasStoredProcedure(String procedureName) 472 { 473 DatabaseSchema schemaPtr = getDatabaseSchema(); 474 if (schemaPtr == null) 475 throw new NullPointerException (Translate.get("backend.schema.not.set")); 476 477 return schemaPtr.hasProcedure(procedureName); 478 } 479 480 481 482 488 public synchronized void initializeConnections() throws SQLException 489 { 490 if (connectionManagers.isEmpty()) 491 throw new SQLException (Translate.get("backend.not.defined", new String []{ 492 name, url})); 493 494 AbstractConnectionManager connectionManager; 495 Iterator iter = connectionManagers.values().iterator(); 496 while (iter.hasNext()) 497 { 498 connectionManager = (AbstractConnectionManager) iter.next(); 499 if (!connectionManager.isInitialized()) 500 connectionManager.initializeConnections(); 501 } 502 } 503 504 510 public synchronized void finalizeConnections() throws SQLException 511 { 512 if (connectionManagers.isEmpty()) 513 throw new SQLException (Translate.get("backend.not.defined", new String []{ 514 name, url})); 515 516 AbstractConnectionManager connectionManager; 517 Iterator iter = connectionManagers.values().iterator(); 518 while (iter.hasNext()) 519 { 520 connectionManager = (AbstractConnectionManager) iter.next(); 521 if (connectionManager.isInitialized()) 522 connectionManager.finalizeConnections(); 523 } 524 } 525 526 535 public boolean isValidConnection(Connection connection) 536 { 537 try 538 { 539 Statement s = connection.createStatement(); 540 s.executeQuery(connectionTestStatement); 541 } 542 catch (SQLException e) 543 { 544 if ("25P02".equals(e.getSQLState()) 545 || (e.getMessage() != null && e 546 .getMessage() 547 .indexOf( 548 "current transaction is aborted, queries ignored until end of transaction block") > 0)) 549 { 550 return true; 559 } 560 return false; 561 } 562 return true; 563 } 564 565 572 public void addConnectionManager(String vLogin, 573 AbstractConnectionManager connectionManager) 574 { 575 if (connectionManager == null) 576 throw new IllegalArgumentException (Translate.get( 577 "backend.null.connection.manager", new String []{name, url})); 578 if (logger.isInfoEnabled()) 579 logger.info(Translate.get("backend.add.connection.manager.for.user", 580 vLogin)); 581 connectionManager.setVLogin(vLogin); 582 connectionManagers.put(vLogin, connectionManager); 583 } 584 585 603 public synchronized Connection getConnectionForTransactionAndLazyBeginIfNeeded( 604 Long tid, AbstractConnectionManager cm, int transactionIsolationLevel) 605 throws UnreachableBackendException, 606 NoTransactionStartWhenDisablingException, SQLException 607 { 608 if (isStartedTransaction(tid)) 609 { return cm.retrieveConnection(tid.longValue()); 611 } 612 else 613 { 614 if (isDisabling()) 615 throw new NoTransactionStartWhenDisablingException(); 616 617 startTransaction(tid); 619 620 return AbstractLoadBalancer.getConnectionAndBeginTransaction(this, cm, 622 tid.longValue(), transactionIsolationLevel); 623 } 624 } 625 626 627 628 634 public void startTransaction(Long tid) 635 { 636 synchronized (activeTransactions) 637 { 638 totalTransactions++; 639 activeTransactions.add(tid); 640 } 641 } 642 643 649 public void stopTransaction(Long tid) 650 { 651 synchronized (activeTransactions) 652 { 653 if (!activeTransactions.remove(tid)) 654 throw new IllegalArgumentException (Translate.get( 655 "backend.transaction.not.started", new String []{"" + tid, name})); 656 if (activeTransactions.isEmpty()) 659 { 660 activeTransactions.notifyAll(); 661 } 662 } 663 664 synchronized (savepoints) 665 { 666 savepoints.remove(tid); 667 } 668 } 669 670 675 public void waitForAllTransactionsToComplete() 676 { 677 synchronized (activeTransactions) 678 { 679 if (activeTransactions.isEmpty()) 680 return; 681 else 682 try 683 { 684 activeTransactions.wait(); 685 } 686 catch (InterruptedException ignore) 687 { 688 } 689 } 690 } 691 692 699 public boolean isStartedTransaction(Long tid) 700 { 701 synchronized (activeTransactions) 702 { 703 return activeTransactions.contains(tid); 704 } 705 } 706 707 713 public void addSavepoint(Long tid, Savepoint savepoint) 714 { 715 synchronized (savepoints) 716 { 717 List savepointList = (List ) savepoints.get(tid); 718 if (savepointList == null) 719 { savepointList = new ArrayList (); 721 savepoints.put(tid, savepointList); 722 } 723 savepointList.add(savepoint); 724 } 725 } 726 727 733 public void removeSavepoint(Long tid, Savepoint savepoint) 734 { 735 synchronized (savepoints) 736 { 737 List savepointList = (List ) savepoints.get(tid); 738 if (savepointList == null) 739 logger.error("No savepoints found for transaction " + tid); 740 else 741 savepointList.remove(savepoint); 742 } 743 } 744 745 752 public Savepoint getSavepoint(Long tid, String savepointName) 753 { 754 synchronized (savepoints) 755 { 756 List savepointList = (List ) savepoints.get(tid); 757 if (savepointList == null) 758 return null; 760 Iterator i = savepointList.iterator(); 761 while (i.hasNext()) 762 { 763 try 764 { 765 Savepoint savepoint = (Savepoint ) i.next(); 766 if (savepointName.equals(savepoint.getSavepointName())) 767 return savepoint; 768 } 769 catch (SQLException ignore) 770 { 771 } 774 } 775 } 776 777 return null; 779 } 780 781 790 public boolean hasSavepointForTransaction(Long tid, String savepointName) 791 { 792 return (this.getSavepoint(tid, savepointName) != null); 793 } 794 795 801 public synchronized boolean isInitialized() throws SQLException 802 { 803 if (connectionManagers.isEmpty()) 804 throw new SQLException (Translate.get("backend.null.connection.manager", 805 new String []{name, url})); 806 Iterator iter = connectionManagers.values().iterator(); 807 while (iter.hasNext()) 808 { 809 if (!((AbstractConnectionManager) iter.next()).isInitialized()) 810 return false; 811 } 812 return true; 813 } 814 815 821 public synchronized boolean isJDBCConnected() 822 { 823 try 824 { 825 if (connectionManagers.isEmpty()) 826 throw new SQLException (Translate.get("backend.null.connection.manager", 827 new String []{name, url})); 828 829 AbstractConnectionManager connectionManager; 830 Iterator iter = connectionManagers.values().iterator(); 831 connectionManager = (AbstractConnectionManager) iter.next(); 832 833 Connection con = connectionManager.getConnectionFromDriver(); 834 con.createStatement().execute(this.connectionTestStatement); 835 return true; 836 } 837 catch (Exception e) 838 { 839 String msg = Translate.get("loadbalancer.backend.unreacheable", name); 840 logger.warn(msg, e); 841 return false; 842 } 843 } 844 845 850 public synchronized boolean isReadEnabled() 851 { 852 return state == BackendState.READ_ENABLED_WRITE_DISABLED 853 || state == BackendState.READ_ENABLED_WRITE_ENABLED; 854 } 855 856 861 public synchronized boolean isWriteEnabled() 862 { 863 return state == BackendState.READ_ENABLED_WRITE_ENABLED 864 || state == BackendState.READ_DISABLED_WRITE_ENABLED; 865 } 866 867 872 public boolean isRecovering() 873 { 874 return state == BackendState.RECOVERING; 875 } 876 877 882 public boolean isDisabling() 883 { 884 return state == BackendState.DISABLING; 885 } 886 887 890 public boolean isDisabled() 891 { 892 return state == BackendState.DISABLED; 893 } 894 895 901 public boolean isKilled() 902 { 903 return state == BackendState.UNKNOWN; 904 } 905 906 917 public String getState() 918 { 919 switch (state) 920 { 921 case BackendState.READ_ENABLED_WRITE_DISABLED : 922 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_ENABLED; 923 case BackendState.READ_ENABLED_WRITE_ENABLED : 924 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_ENABLED_WRITE; 925 case BackendState.READ_DISABLED_WRITE_ENABLED : 926 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_ENABLED_WRITE; 927 case BackendState.DISABLING : 928 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_DISABLING; 929 case BackendState.BACKUPING : 930 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_BACKINGUP; 931 case BackendState.RECOVERING : 932 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_RECOVERING; 933 case BackendState.REPLAYING : 934 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_REPLAYING; 935 case BackendState.DISABLED : 936 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_DISABLED; 937 case BackendState.UNKNOWN : 938 return CjdbcNotificationList.VIRTUALDATABASE_BACKEND_UNKNOWN; 939 default : 940 throw new IllegalArgumentException ("Unknown backend state:" + state); 941 } 942 } 943 944 951 public int getStateValue() 952 { 953 return state; 954 } 955 956 960 public synchronized void enableRead() 961 { 962 if (isWriteEnabled()) 963 setState(BackendState.READ_ENABLED_WRITE_ENABLED); 964 else 965 setState(BackendState.READ_ENABLED_WRITE_DISABLED); 966 } 967 968 971 public synchronized void disableRead() 972 { 973 if (isWriteEnabled()) 974 setState(BackendState.READ_DISABLED_WRITE_ENABLED); 975 else 976 setState(BackendState.DISABLED); 977 } 978 979 982 public synchronized void disableWrite() 983 { 984 if (isReadEnabled()) 985 setState(BackendState.READ_ENABLED_WRITE_DISABLED); 986 else 987 setState(BackendState.DISABLED); 988 } 989 990 994 public synchronized void enableWrite() 995 { 996 setLastKnownCheckpoint(null); 999 if (isReadEnabled()) 1000 setState(BackendState.READ_ENABLED_WRITE_ENABLED); 1001 else 1002 setState(BackendState.READ_DISABLED_WRITE_ENABLED); 1003 } 1004 1005 1017 public void setDisabling() 1018 { 1019 setState(BackendState.DISABLING); 1020 } 1021 1022 1028 public synchronized void disable() 1029 { 1030 setState(BackendState.DISABLED); 1031 } 1032 1033 1034 1035 1042 public AbstractConnectionManager getConnectionManager(String vLogin) 1043 { 1044 return (AbstractConnectionManager) connectionManagers.get(vLogin); 1045 } 1046 1047 1053 public HashMap getConnectionManagers() 1054 { 1055 return this.connectionManagers; 1056 } 1057 1058 1063 public String getConnectionTestStatement() 1064 { 1065 return connectionTestStatement; 1066 } 1067 1068 1071 public String getDriverPath() 1072 { 1073 return driverPath; 1074 } 1075 1076 1079 public String getAssociatedString() 1080 { 1081 return "backend"; 1082 } 1083 1084 1089 public String getDriverClassName() 1090 { 1091 return driverClassName; 1092 } 1093 1094 1099 public String getName() 1100 { 1101 return name; 1102 } 1103 1104 1109 public String getVirtualDatabaseName() 1110 { 1111 return virtualDatabaseName; 1112 } 1113 1114 1120 public Vector getPendingRequests() 1121 { 1122 return pendingRequests; 1123 } 1124 1125 1129 public ArrayList getPendingRequestsDescription(int count, boolean fromFirst, 1130 boolean clone) 1131 { 1132 int size = pendingRequests.size(); 1133 int limit = (count == 0 || count > size) ? size : Math.min(size, count); 1134 ArrayList list = new ArrayList (limit); 1135 int start = (fromFirst) ? 0 : Math.min(limit - count, 0); 1136 if (!clone) 1137 { 1138 synchronized (pendingRequests) 1139 { 1140 for (int i = start; i < limit; i++) 1141 list.add(pendingRequests.get(i).toString()); 1142 } 1143 return list; 1144 } 1145 else 1146 { 1147 Vector cloneVector = (Vector ) pendingRequests.clone(); 1148 for (int i = start; i < limit; i++) 1149 list.add(cloneVector.get(i).toString()); 1150 return list; 1151 } 1152 } 1153 1154 1160 public void addPendingReadRequest(Object request) 1161 { 1162 synchronized (this) 1163 { 1164 totalRequest++; 1165 totalReadRequest++; 1166 } 1167 pendingRequests.add(request); 1168 } 1169 1170 1176 public void addPendingWriteRequest(Object request) 1177 { 1178 synchronized (this) 1179 { 1180 totalRequest++; 1181 totalWriteRequest++; 1182 } 1183 pendingRequests.add(request); 1184 } 1185 1186 1193 public boolean removePendingRequest(Object request) 1194 { 1195 return pendingRequests.remove(request); 1196 } 1197 1198 1202 1205 public synchronized boolean checkDatabaseSchema() 1206 { 1207 if (logger.isDebugEnabled()) 1208 logger.debug(Translate.get("backend.dynamic.schema", 1209 DatabaseBackendSchemaConstants 1210 .getDynamicSchemaLevel(dynamicPrecision))); 1211 1212 boolean checked = true; 1213 AbstractConnectionManager connectionMananger; 1214 Iterator iter = connectionManagers.values().iterator(); 1215 while (iter.hasNext()) 1216 { 1217 connectionMananger = (AbstractConnectionManager) iter.next(); 1218 1219 DatabaseBackendMetaData meta = new DatabaseBackendMetaData( 1221 connectionMananger, logger, dynamicPrecision, gatherSystemTables, 1222 schemaName); 1223 1224 DatabaseSchema metaSchema; 1225 try 1226 { 1227 if (logger.isInfoEnabled()) 1228 logger.info(Translate.get("backend.gathering.database.schema")); 1229 metaSchema = meta.getDatabaseSchema(); 1230 } 1231 catch (SQLException e) 1232 { 1233 if (logger.isWarnEnabled()) 1234 logger.warn(Translate.get("backend.gather.schema.failed", e)); 1235 return false; 1236 } 1237 if (schema == null) 1238 { 1239 if (logger.isDebugEnabled()) 1240 logger.debug(Translate.get("backend.use.gathered.schema.as.new")); 1241 schema = metaSchema; 1242 } 1243 else 1244 { 1245 if (dynamicPrecision == DatabaseBackendSchemaConstants.DynamicPrecisionStatic) 1246 { 1247 if (logger.isInfoEnabled()) 1248 logger.info(Translate.get("backend.schema.static.no.check", name)); 1249 } 1250 else 1251 { 1252 if (logger.isInfoEnabled()) 1253 logger.info(Translate.get("backend.check.schema.compatibility")); 1254 if (schema.isCompatibleSubset(metaSchema)) 1255 logger.info(Translate.get("backend.schema.compatible.for.login", 1256 connectionMananger.getLogin())); 1257 else 1258 { 1259 checked = false; 1260 logger.warn(Translate.get( 1261 "backend.schema.not.compatible.for.login", connectionMananger 1262 .getLogin())); 1263 } 1264 } 1265 } 1266 } 1267 setSchemaIsDirty(false); 1268 return checked; 1269 } 1270 1271 1278 public synchronized DatabaseSchema getDatabaseSchema() 1279 { 1280 if (schemaIsNeededByVdb && schemaIsDirty && !schemaIsStatic) 1281 refreshSchema(); 1282 return schema; 1283 } 1284 1285 1291 public MetadataContainer getDatabaseStaticMetadata() 1292 { 1293 AbstractConnectionManager connectionMananger; 1294 Iterator iter = connectionManagers.values().iterator(); 1295 if (iter.hasNext()) 1296 { 1297 connectionMananger = (AbstractConnectionManager) iter.next(); 1298 DatabaseBackendMetaData meta = new DatabaseBackendMetaData( 1300 connectionMananger, logger, dynamicPrecision, gatherSystemTables, 1301 schemaName); 1302 try 1303 { 1304 return meta.retrieveDatabaseMetadata(); 1305 } 1306 catch (SQLException e) 1307 { 1308 return null; 1309 } 1310 } 1311 else 1312 return null; 1313 } 1314 1315 1318 public int getDynamicPrecision() 1319 { 1320 return dynamicPrecision; 1321 } 1322 1323 1328 public String getSchemaName() 1329 { 1330 return schemaName; 1331 } 1332 1333 1338 public boolean isGatherSystemTables() 1339 { 1340 return gatherSystemTables; 1341 } 1342 1343 1349 public boolean isSchemaDirty() 1350 { 1351 return schemaIsDirty; 1352 } 1353 1354 1357 public boolean isSchemaStatic() 1358 { 1359 return schemaIsStatic; 1360 } 1361 1362 1367 public boolean isSchemaNeededByVdb() 1368 { 1369 return schemaIsNeededByVdb; 1370 } 1371 1372 1375 private synchronized void refreshSchema() 1376 { 1377 setDatabaseSchema(null, isSchemaStatic()); 1378 checkDatabaseSchema(); } 1380 1381 1388 public synchronized void setDatabaseSchema(DatabaseSchema databaseSchema, 1389 boolean isStatic) 1390 { 1391 if (schema == null) 1392 { 1393 schemaIsStatic = isStatic; 1394 schema = databaseSchema; 1395 } 1396 else 1397 { 1398 if (!isStatic) 1399 schema = databaseSchema; 1400 } 1401 } 1402 1403 1411 public void setDynamicPrecision(int dynamicPrecision, 1412 boolean gatherSystemTables, String schemaName) 1413 { 1414 this.dynamicPrecision = dynamicPrecision; 1415 this.gatherSystemTables = gatherSystemTables; 1416 this.schemaName = schemaName; 1417 } 1418 1419 1424 public void setSchemaIsDirty(boolean schemaIsDirty) 1425 { 1426 this.schemaIsDirty = schemaIsDirty; 1427 } 1428 1429 1434 public void setSchemaIsNeededByVdb(boolean schemaIsNeededByVdb) 1435 { 1436 this.schemaIsNeededByVdb = schemaIsNeededByVdb; 1437 } 1438 1439 1446 public void updateDatabaseBackendSchema(AbstractWriteRequest request) 1447 { 1448 if (!request.isDDL()) 1449 return; 1450 1451 if (isSchemaNeededByVdb()) 1453 { 1454 if (request.isCreate()) 1455 { DatabaseSchema dbs = getDatabaseSchema(); 1457 if (dbs != null) 1458 { 1459 CreateRequest createRequest = (CreateRequest) request; 1460 if (createRequest.altersDatabaseSchema()) 1461 { 1462 DatabaseTable t = createRequest.getDatabaseTable(); 1463 if (t != null) 1464 { 1465 dbs.addTable(t); 1466 if (logger.isDebugEnabled()) 1467 logger.debug("Added table '" + request.getTableName() 1468 + "' to backend database schema"); 1469 } 1470 else 1471 setSchemaIsDirty(true); 1473 } 1474 else 1475 setSchemaIsDirty(true); 1477 } 1478 } 1479 else if (request.isDrop()) 1480 { DatabaseSchema dbs = getDatabaseSchema(); 1482 if (dbs != null) 1483 { 1484 DatabaseTable t = dbs.getTable(request.getTableName()); 1485 if (t != null) 1486 { 1487 dbs.removeTable(t); 1488 if (logger.isDebugEnabled()) 1489 logger.debug("Removed table '" + request.getTableName() 1490 + "' from backend database schema"); 1491 } 1492 else 1493 setSchemaIsDirty(true); 1495 } 1496 else 1497 setSchemaIsDirty(true); 1499 } 1500 else 1501 setSchemaIsDirty(true); 1503 } 1504 else 1505 setSchemaIsDirty(true); 1507 } 1508 1509 1513 1516 public DriverCompliance getDriverCompliance() 1517 { 1518 return driverCompliance; 1519 } 1520 1521 1526 public void checkDriverCompliance() throws SQLException 1527 { 1528 if (connectionManagers.isEmpty()) 1529 throw new SQLException (Translate.get("backend.null.connection.manager", 1530 new String []{name, url})); 1531 1532 AbstractConnectionManager connectionManager; 1533 Iterator iter = connectionManagers.values().iterator(); 1534 connectionManager = (AbstractConnectionManager) iter.next(); 1535 1536 try 1537 { 1538 if (!driverCompliance.complianceTest(url, connectionManager.getLogin(), 1539 connectionManager.getPassword(), connectionManager.getDriverPath(), 1540 connectionManager.getDriverClassName(), connectionTestStatement)) 1541 throw new SQLException (Translate.get("backend.driver.not.compliant", 1542 driverClassName)); 1543 } 1544 catch (ConnectException e) 1545 { 1546 throw new SQLException (Translate.get("backend.cannot.connect.to", e)); 1547 } 1548 } 1549 1550 1555 public String getURL() 1556 { 1557 return url; 1558 } 1559 1560 1563 1564 1569 public void addRewritingRule(AbstractRewritingRule rule) 1570 { 1571 if (rewritingRules == null) 1572 rewritingRules = new ArrayList (); 1573 if (logger.isDebugEnabled()) 1574 logger.debug(Translate.get("backend.rewriting.rule.add", new String []{ 1575 rule.getQueryPattern(), rule.getRewrite()})); 1576 rewritingRules.add(rule); 1577 } 1578 1579 1585 public String rewriteQuery(String sqlQuery) 1586 { 1587 if (rewritingRules == null) 1588 return sqlQuery; 1589 int size = rewritingRules.size(); 1590 for (int i = 0; i < size; i++) 1591 { 1592 AbstractRewritingRule rule = (AbstractRewritingRule) rewritingRules 1593 .get(i); 1594 sqlQuery = rule.rewrite(sqlQuery); 1595 if (rule.hasMatched()) 1596 { if (logger.isDebugEnabled()) 1598 logger.debug(Translate.get("backend.rewriting.query", sqlQuery)); 1599 if (rule.isStopOnMatch()) 1600 break; } 1602 } 1603 return sqlQuery; 1604 } 1605 1606 1609 1610 1615 public synchronized String getXml() 1616 { 1617 StringBuffer info = new StringBuffer (); 1618 info.append("<" + DatabasesXmlTags.ELT_DatabaseBackend + " " 1619 + DatabasesXmlTags.ATT_name + "=\"" + name + "\" " 1620 + DatabasesXmlTags.ATT_driver + "=\"" + driverClassName + "\" " 1621 + DatabasesXmlTags.ATT_url + "=\"" + url + "\" " 1622 + DatabasesXmlTags.ATT_connectionTestStatement + "=\"" 1623 + connectionTestStatement + "\">"); 1624 1625 boolean expandSchema = this.schema != null 1626 && dynamicPrecision == DatabaseBackendSchemaConstants.DynamicPrecisionStatic; 1627 1628 info.append(getSchemaXml(expandSchema)); 1629 1630 if (rewritingRules != null) 1631 { 1632 int size = rewritingRules.size(); 1633 for (int i = 0; i < size; i++) 1634 info.append(((AbstractRewritingRule) rewritingRules.get(i)).getXml()); 1635 } 1636 if (connectionManagers != null) 1637 { 1638 if (connectionManagers.isEmpty() == false) 1639 { 1640 AbstractConnectionManager connectionManager; 1641 Iterator iter = connectionManagers.values().iterator(); 1642 while (iter.hasNext()) 1643 { 1644 connectionManager = (AbstractConnectionManager) iter.next(); 1645 info.append(connectionManager.getXml()); 1646 } 1647 } 1648 } 1649 info.append("</" + DatabasesXmlTags.ELT_DatabaseBackend + ">"); 1650 return info.toString(); 1651 } 1652 1653 1656 public String getSchemaXml(boolean expandSchema) 1657 { 1658 StringBuffer info = new StringBuffer (); 1659 info.append("<" 1660 + DatabasesXmlTags.ELT_DatabaseSchema 1661 + " " 1662 + DatabasesXmlTags.ATT_dynamicPrecision 1663 + "=\"" 1664 + DatabaseBackendSchemaConstants 1665 .getDynamicSchemaLevel(dynamicPrecision) + "\" " 1666 + DatabasesXmlTags.ATT_gatherSystemTables + "=\"" 1667 + (gatherSystemTables ? "true" : "false") + "\">"); 1668 synchronized (this) 1669 { 1670 if (expandSchema && (schema != null)) 1671 info.append(schema.getXml()); 1672 } 1673 info.append("</" + DatabasesXmlTags.ELT_DatabaseSchema + ">"); 1674 return info.toString(); 1675 } 1676 1677 1680 public ArrayList getActiveTransactions() 1681 { 1682 return activeTransactions; 1683 } 1684 1685 1707 public String [] getBackendData() 1708 { 1709 String [] data = new String [14]; 1710 data[0] = this.name; 1711 data[1] = this.driverClassName; 1712 data[2] = this.url; 1713 data[3] = String.valueOf(this.activeTransactions.size()); 1714 data[4] = String.valueOf(this.pendingRequests.size()); 1715 data[5] = String.valueOf(this.isReadEnabled()); 1716 data[6] = String.valueOf(this.isWriteEnabled()); 1717 try 1718 { 1719 data[7] = String.valueOf(this.isInitialized()); 1720 } 1721 catch (Exception e) 1722 { 1723 data[7] = "unknown"; 1724 } 1725 data[8] = String.valueOf(this.schemaIsStatic); 1726 1727 data[9] = String.valueOf(this.connectionManagers.size()); 1728 data[10] = String.valueOf(getTotalActiveConnections()); 1729 data[11] = String.valueOf(totalRequest); 1730 data[12] = String.valueOf(totalTransactions); 1731 if (lastKnownCheckpoint == null || lastKnownCheckpoint.equalsIgnoreCase("")) 1732 data[13] = "<unknown>"; 1733 else 1734 data[13] = lastKnownCheckpoint; 1735 return data; 1736 } 1737 1738 1743 public BackendStatistics getBackendStats() 1744 { 1745 BackendStatistics stats = new BackendStatistics(); 1746 stats.setBackendName(name); 1747 stats.setDriverClassName(driverClassName); 1748 stats.setUrl(url); 1749 stats.setNumberOfActiveTransactions(activeTransactions.size()); 1750 stats.setNumberOfPendingRequests(pendingRequests.size()); 1751 stats.setReadEnabled(isReadEnabled()); 1752 stats.setWriteEnabled(isWriteEnabled()); 1753 String initializationStatus = "<unknown>"; 1754 try 1755 { 1756 initializationStatus = String.valueOf(this.isInitialized()); 1757 } 1758 catch (Exception e) 1759 { 1760 } 1761 stats.setInitializationStatus(initializationStatus); 1762 stats.setSchemaStatic(schemaIsStatic); 1763 stats.setNumberOfConnectionManagers(connectionManagers.size()); 1764 stats.setNumberOfTotalActiveConnections(getTotalActiveConnections()); 1765 stats.setNumberOfTotalRequests(totalRequest); 1766 stats.setNumberOfTotalTransactions(totalTransactions); 1767 if (lastKnownCheckpoint == null || lastKnownCheckpoint.equalsIgnoreCase("")) 1768 stats.setLastKnownCheckpoint("<unknown>"); 1769 else 1770 stats.setLastKnownCheckpoint(lastKnownCheckpoint); 1771 return stats; 1772 } 1773 1774 1780 public long getTotalActiveConnections() 1781 { 1782 int activeConnections = 0; 1783 Iterator iter = connectionManagers.keySet().iterator(); 1784 while (iter.hasNext()) 1785 activeConnections += ((AbstractConnectionManager) connectionManagers 1786 .get(iter.next())).getCurrentNumberOfConnections(); 1787 return activeConnections; 1788 } 1789 1790 1795 public int getTotalTransactions() 1796 { 1797 return totalTransactions; 1798 } 1799 1800 1805 public int getTotalReadRequest() 1806 { 1807 return totalReadRequest; 1808 } 1809 1810 1815 public int getTotalWriteRequest() 1816 { 1817 return totalWriteRequest; 1818 } 1819 1820 1825 public int getTotalRequest() 1826 { 1827 return totalRequest; 1828 } 1829 1830 1835 public void setLastKnownCheckpoint(String checkpoint) 1836 { 1837 this.lastKnownCheckpoint = checkpoint; 1838 } 1839 1840 1845 public String getLastKnownCheckpoint() 1846 { 1847 return lastKnownCheckpoint; 1848 } 1849 1850 1855 public String getDatabaseProductName() 1856 { 1857 return driverCompliance.getDatabaseProductName(); 1858 } 1859 1860 1865 public ArrayList getRewritingRules() 1866 { 1867 return rewritingRules; 1868 } 1869 1870 1875 public void setRewritingRules(ArrayList rewritingRules) 1876 { 1877 this.rewritingRules = rewritingRules; 1878 } 1879 1880 1900 public DatabaseBackend copy(String newName, Map parameters) throws Exception 1901 { 1902 String fromDriverPath = parameters 1905 .containsKey(DatabasesXmlTags.ATT_driverPath) ? (String ) parameters 1906 .get(DatabasesXmlTags.ATT_driverPath) : this.getDriverPath(); 1907 1908 String fromDriverClassName = parameters 1909 .containsKey(DatabasesXmlTags.ATT_driver) ? (String ) parameters 1910 .get(DatabasesXmlTags.ATT_driver) : this.getDriverClassName(); 1911 1912 String fromUrl = parameters.containsKey(DatabasesXmlTags.ATT_url) 1913 ? (String ) parameters.get(DatabasesXmlTags.ATT_url) 1914 : this.getURL(); 1915 1916 String fromConnectionTestStatement = parameters 1917 .containsKey(DatabasesXmlTags.ATT_connectionTestStatement) 1918 ? (String ) parameters.get(DatabasesXmlTags.ATT_connectionTestStatement) 1919 : this.getConnectionTestStatement(); 1920 1921 DatabaseBackend newBackend = new DatabaseBackend(newName, fromDriverPath, 1923 fromDriverClassName, fromUrl, virtualDatabaseName, writeCanBeEnabled, 1924 fromConnectionTestStatement); 1925 1926 newBackend.setDynamicPrecision(this.dynamicPrecision, 1928 this.gatherSystemTables, this.schemaName); 1929 1930 newBackend.setRewritingRules(this.getRewritingRules()); 1933 1934 HashMap fromConnectionManagers = this.getConnectionManagers(); 1936 Iterator iter = fromConnectionManagers.keySet().iterator(); 1937 1938 String vlogin = null; 1939 AbstractConnectionManager connectionManager; 1940 while (iter.hasNext()) 1941 { 1942 vlogin = (String ) iter.next(); 1943 connectionManager = (AbstractConnectionManager) fromConnectionManagers 1944 .get(vlogin); 1945 newBackend.addConnectionManager(vlogin, connectionManager.copy(fromUrl, 1946 newName)); 1947 } 1948 1949 return newBackend; 1950 } 1951 1952 1957 public boolean isBackuping() 1958 { 1959 return state == BackendState.BACKUPING; 1960 } 1961 1962 1968 public synchronized void setState(int state) 1969 { 1970 switch (state) 1971 { 1972 case BackendState.UNKNOWN : 1973 lastKnownCheckpoint = null; 1974 break; 1975 case BackendState.READ_ENABLED_WRITE_DISABLED : 1976 case BackendState.READ_ENABLED_WRITE_ENABLED : 1977 case BackendState.READ_DISABLED_WRITE_ENABLED : 1978 case BackendState.DISABLING : 1979 case BackendState.BACKUPING : 1980 case BackendState.RECOVERING : 1981 case BackendState.REPLAYING : 1982 case BackendState.DISABLED : 1983 break; 1984 default : 1985 throw new IllegalArgumentException ("Unknown backend state:" + state); 1986 } 1987 this.state = state; 1988 if (logger.isDebugEnabled()) 1989 logger.debug(Translate.get("backend.state.changed", new String []{name, 1990 getState()})); 1991 notifyStateChange(); 1992 } 1993 1994 2002 public void notifyStateChange() 2003 { 2004 if (stateListener != null) 2005 stateListener.changeState(this); 2006 notifyJmx(getState()); 2007 } 2008 2009 2015 public void notifyJmx(String type) 2016 { 2017 notifyJmx(type, CjdbcNotificationList.NOTIFICATION_LEVEL_INFO, Translate 2018 .get(type, getName())); 2019 } 2020 2021 2028 public void notifyJmxError(String type, Exception e) 2029 { 2030 notifyJmx(type, CjdbcNotificationList.NOTIFICATION_LEVEL_ERROR, Translate 2031 .get(type, new String []{getName(), e.getMessage()})); 2032 2033 } 2034 2035 private void notifyJmx(String type, String level, String message) 2036 { 2037 if (MBeanServerManager.isJmxEnabled()) 2038 { 2039 Hashtable data = new Hashtable (); 2041 data.put(CjdbcNotificationList.DATA_DATABASE, getVirtualDatabaseName()); 2042 data.put(CjdbcNotificationList.DATA_DRIVER, getDriverClassName()); 2043 String checkpoint = getLastKnownCheckpoint(); 2044 checkpoint = (checkpoint == null) ? "" : checkpoint; 2045 data.put(CjdbcNotificationList.DATA_CHECKPOINT, checkpoint); 2046 data.put(CjdbcNotificationList.DATA_NAME, getName()); 2047 data.put(CjdbcNotificationList.DATA_URL, getURL()); 2048 RmiConnector.broadcastNotification(this, type, level, message, data); 2049 } 2050 } 2051 2052 2057 public boolean isWriteCanBeEnabled() 2058 { 2059 return writeCanBeEnabled; 2060 } 2061 2062 2067 public void setStateListener(BackendStateListener stateListener) 2068 { 2069 this.stateListener = stateListener; 2070 } 2071 2072 2077 public String toString() 2078 { 2079 return "Backend: Name[" + this.name + "] State[" + this.state 2080 + "] JDBCConnected[" + isJDBCConnected() + "] ActiveTransactions[" 2081 + activeTransactions.size() + "] PendingRequests[" 2082 + pendingRequests.size() + "]"; 2083 } 2084 2085} | Popular Tags |