Source Code Cross Referenced for VirtualDatabase.java in  » Database-JDBC-Connection-Pool » sequoia-2.10.9 » org » continuent » sequoia » controller » virtualdatabase » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » sequoia 2.10.9 » org.continuent.sequoia.controller.virtualdatabase 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**
0002:         * Sequoia: Database clustering technology.
0003:         * Copyright (C) 2002-2004 French National Institute For Research In Computer
0004:         * Science And Control (INRIA).
0005:         * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
0006:         * Copyright (C) 2005-2006 Continuent, Inc.
0007:         * Contact: sequoia@continuent.org
0008:         *
0009:         * Licensed under the Apache License, Version 2.0 (the "License");
0010:         * you may not use this file except in compliance with the License.
0011:         * You may obtain a copy of the License at
0012:         *
0013:         * http://www.apache.org/licenses/LICENSE-2.0
0014:         *
0015:         * Unless required by applicable law or agreed to in writing, software
0016:         * distributed under the License is distributed on an "AS IS" BASIS,
0017:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0018:         * See the License for the specific language governing permissions and
0019:         * limitations under the License.
0020:         *
0021:         * Initial developer(s): Emmanuel Cecchet.
0022:         * Contributor(s): Mathieu Peltier, Nicolas Modrzyk, Vadim Kassin, Olivier Fambon, Jean-Bernard van Zuylen.
0023:         */package org.continuent.sequoia.controller.virtualdatabase;
0024:
0025:        import java.sql.SQLException;
0026:        import java.sql.SQLWarning;
0027:        import java.text.SimpleDateFormat;
0028:        import java.util.ArrayList;
0029:        import java.util.ConcurrentModificationException;
0030:        import java.util.Date;
0031:        import java.util.Hashtable;
0032:        import java.util.Iterator;
0033:        import java.util.LinkedList;
0034:        import java.util.List;
0035:        import java.util.Map;
0036:
0037:        import javax.management.MalformedObjectNameException;
0038:        import javax.management.Notification;
0039:        import javax.management.NotificationBroadcasterSupport;
0040:        import javax.management.ObjectName;
0041:
0042:        import org.continuent.sequoia.common.authentication.AuthenticationManager;
0043:        import org.continuent.sequoia.common.exceptions.BackupException;
0044:        import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
0045:        import org.continuent.sequoia.common.exceptions.VirtualDatabaseException;
0046:        import org.continuent.sequoia.common.i18n.Translate;
0047:        import org.continuent.sequoia.common.jmx.JmxConstants;
0048:        import org.continuent.sequoia.common.jmx.management.BackendInfo;
0049:        import org.continuent.sequoia.common.jmx.management.BackendState;
0050:        import org.continuent.sequoia.common.jmx.management.DumpInfo;
0051:        import org.continuent.sequoia.common.jmx.monitoring.backend.BackendStatistics;
0052:        import org.continuent.sequoia.common.jmx.notifications.SequoiaNotificationList;
0053:        import org.continuent.sequoia.common.locks.ReadPrioritaryFIFOWriteLock;
0054:        import org.continuent.sequoia.common.log.Trace;
0055:        import org.continuent.sequoia.common.sql.schema.DatabaseSchema;
0056:        import org.continuent.sequoia.common.users.AdminUser;
0057:        import org.continuent.sequoia.common.users.VirtualDatabaseUser;
0058:        import org.continuent.sequoia.common.util.Constants;
0059:        import org.continuent.sequoia.common.xml.DatabasesXmlTags;
0060:        import org.continuent.sequoia.common.xml.XmlComponent;
0061:        import org.continuent.sequoia.common.xml.XmlTools;
0062:        import org.continuent.sequoia.controller.backend.DatabaseBackend;
0063:        import org.continuent.sequoia.controller.backend.result.ControllerResultSet;
0064:        import org.continuent.sequoia.controller.backend.result.ExecuteResult;
0065:        import org.continuent.sequoia.controller.backend.result.ExecuteUpdateResult;
0066:        import org.continuent.sequoia.controller.backend.result.GeneratedKeysResult;
0067:        import org.continuent.sequoia.controller.backup.Backuper;
0068:        import org.continuent.sequoia.controller.cache.result.AbstractResultCache;
0069:        import org.continuent.sequoia.controller.core.Controller;
0070:        import org.continuent.sequoia.controller.core.shutdown.VirtualDatabaseForceShutdownThread;
0071:        import org.continuent.sequoia.controller.core.shutdown.VirtualDatabaseSafeShutdownThread;
0072:        import org.continuent.sequoia.controller.core.shutdown.VirtualDatabaseShutdownThread;
0073:        import org.continuent.sequoia.controller.core.shutdown.VirtualDatabaseWaitShutdownThread;
0074:        import org.continuent.sequoia.controller.jmx.MBeanServerManager;
0075:        import org.continuent.sequoia.controller.loadbalancer.AllBackendsFailedException;
0076:        import org.continuent.sequoia.controller.monitoring.SQLMonitoring;
0077:        import org.continuent.sequoia.controller.recoverylog.BackendRecoveryInfo;
0078:        import org.continuent.sequoia.controller.recoverylog.RecoverThread;
0079:        import org.continuent.sequoia.controller.recoverylog.RecoveryLog;
0080:        import org.continuent.sequoia.controller.requestmanager.RAIDbLevels;
0081:        import org.continuent.sequoia.controller.requestmanager.RequestManager;
0082:        import org.continuent.sequoia.controller.requests.AbstractRequest;
0083:        import org.continuent.sequoia.controller.requests.AbstractWriteRequest;
0084:        import org.continuent.sequoia.controller.requests.SelectRequest;
0085:        import org.continuent.sequoia.controller.requests.StoredProcedure;
0086:        import org.continuent.sequoia.controller.virtualdatabase.management.AbstractAdminOperation;
0087:        import org.continuent.sequoia.controller.virtualdatabase.management.BackupBackendOperation;
0088:        import org.continuent.sequoia.controller.virtualdatabase.management.EnableBackendOperation;
0089:        import org.continuent.sequoia.controller.virtualdatabase.management.RestoreDumpOperation;
0090:
0091:        /**
0092:         * A <code>VirtualDatabase</code> represents a database from client point of
0093:         * view and hide the complexity of the cluster distribution to the client. The
0094:         * client always uses the virtual database name and the Sequoia Controller will
0095:         * use the real connections when an SQL request comes in.
0096:         *
0097:         * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
0098:         * @author <a href="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
0099:         * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
0100:         * @author <a href="mailto:vadim@kase.kz">Vadim Kassin </a>
0101:         * @author <a href="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
0102:         *         </a>
0103:         * @version 1.0
0104:         */
0105:        public class VirtualDatabase implements  XmlComponent {
0106:            private static final long serialVersionUID = 1399418136380336827L;
0107:
0108:            //
0109:            // How the code is organized ?
0110:            //
0111:            // 1. Member variables
0112:            // 2. Constructor(s)
0113:            // 3. Request handling
0114:            // 4. Transaction handling
0115:            // 5. Database backend management
0116:            // 6. Checkpoint management
0117:            // 7. Getter/Setter (possibly in alphabetical order)
0118:            // 8. Shutdown
0119:            //
0120:
0121:            /** Virtual database name */
0122:            protected String name;
0123:
0124:            /**
0125:             * Authentification manager matching virtual database login/password to
0126:             * backends login/password
0127:             */
0128:            protected AuthenticationManager authenticationManager;
0129:
0130:            /** <code>ArrayList</code> of <code>DatabaseBackend</code> objects */
0131:            protected ArrayList backends;
0132:
0133:            /** Read/Write lock for backend list */
0134:            protected ReadPrioritaryFIFOWriteLock rwLock;
0135:
0136:            /** The request manager to use for this database */
0137:            protected RequestManager requestManager;
0138:
0139:            /** ArrayList to store the order of requests */
0140:            protected LinkedList totalOrderQueue = null;
0141:
0142:            /** Virtual database logger */
0143:            protected Trace logger = null;
0144:            protected Trace requestLogger = null;
0145:
0146:            /** end user logger */
0147:            static Trace endUserLogger = Trace
0148:                    .getLogger("org.continuent.sequoia.enduser");
0149:
0150:            // List of current active Worker Threads
0151:            private ArrayList activeThreads = new ArrayList();
0152:            // List of current idle Worker Threads
0153:            private int idleThreads = 0;
0154:            // List of current pending connections (Socket objects)
0155:            private ArrayList pendingConnections = new ArrayList();
0156:
0157:            /** Maximum number of concurrent accepted for this virtual database */
0158:            protected int maxNbOfConnections;
0159:
0160:            /** If false one worker thread is forked per connection else */
0161:            protected boolean poolConnectionThreads;
0162:
0163:            /** Maximum time a worker thread can remain idle before dying */
0164:            protected long maxThreadIdleTime;
0165:
0166:            /**
0167:             * Minimum number of worker threads to keep in the pool if
0168:             * poolConnectionThreads is true
0169:             */
0170:            protected int minNbOfThreads;
0171:
0172:            /** Maximum number of worker threads to fork */
0173:            protected int maxNbOfThreads;
0174:
0175:            /** Current number of worker threads */
0176:            protected int currentNbOfThreads;
0177:
0178:            /** Virtual Database MetaData */
0179:            protected VirtualDatabaseDynamicMetaData metadata;
0180:            private boolean useStaticResultSetMetaData = true;
0181:            protected VirtualDatabaseStaticMetaData staticMetadata;
0182:
0183:            private SQLMonitoring sqlMonitor = null;
0184:
0185:            /** Use for method getAndCheck */
0186:            public static final int CHECK_BACKEND_ENABLE = 1;
0187:            /** Use for method getAndCheck */
0188:            public static final int CHECK_BACKEND_DISABLE = 0;
0189:            /** Use for method getAndCheck */
0190:            public static final int NO_CHECK_BACKEND = -1;
0191:
0192:            /** Short form of SQL statements to include in traces and exceptions */
0193:            private int sqlShortFormLength;
0194:
0195:            /** The controller we belong to */
0196:            Controller controller;
0197:
0198:            /** Comma separated list of database product names (one instance per name) */
0199:            private String databaseProductNames = "Sequoia";
0200:
0201:            /** Marker to see if the database is shutting down */
0202:            protected boolean shuttingDown = false;
0203:            private boolean refusingNewTransaction = false;
0204:            /** List of currently executing admin operations (preventing shutdown) */
0205:            private List currentAdminOperations;
0206:
0207:            protected NotificationBroadcasterSupport notificationBroadcasterSupport;
0208:
0209:            protected int notificationSequence = 0;
0210:
0211:            protected long connectionId = 0;
0212:
0213:            private boolean enforceTableExistenceIntoSchema = false;
0214:
0215:            /**
0216:             * Creates a new <code>VirtualDatabase</code> instance.
0217:             *
0218:             * @param name the virtual database name.
0219:             * @param maxConnections maximum number of concurrent connections.
0220:             * @param pool should we use a pool of threads for handling connections?
0221:             * @param minThreads minimum number of threads in the pool
0222:             * @param maxThreads maximum number of threads in the pool
0223:             * @param maxThreadIdleTime maximum time a thread can remain idle before being
0224:             *          removed from the pool.
0225:             * @param sqlShortFormLength maximum number of characters of an SQL statement
0226:             *          to diplay in traces or exceptions
0227:             * @param useStaticResultSetMetaData true if DatabaseResultSetMetaData should
0228:             *          use static fields or try to fetch the metadata from the underlying
0229:             *          database
0230:             * @param controller the controller we belong to
0231:             */
0232:            public VirtualDatabase(Controller controller, String name,
0233:                    int maxConnections, boolean pool, int minThreads,
0234:                    int maxThreads, long maxThreadIdleTime,
0235:                    int sqlShortFormLength, boolean useStaticResultSetMetaData,
0236:                    boolean enforceTableExistenceIntoSchema) {
0237:                this .controller = controller;
0238:                this .name = name;
0239:                this .maxNbOfConnections = maxConnections;
0240:                this .poolConnectionThreads = pool;
0241:                this .minNbOfThreads = minThreads;
0242:                this .maxNbOfThreads = maxThreads;
0243:                this .maxThreadIdleTime = maxThreadIdleTime;
0244:                this .sqlShortFormLength = sqlShortFormLength;
0245:                this .useStaticResultSetMetaData = useStaticResultSetMetaData;
0246:                this .enforceTableExistenceIntoSchema = enforceTableExistenceIntoSchema;
0247:                backends = new ArrayList();
0248:                currentAdminOperations = new LinkedList();
0249:
0250:                rwLock = new ReadPrioritaryFIFOWriteLock();
0251:                logger = Trace
0252:                        .getLogger("org.continuent.sequoia.controller.virtualdatabase."
0253:                                + name);
0254:                requestLogger = Trace
0255:                        .getLogger("org.continuent.sequoia.controller.virtualdatabase.request."
0256:                                + name);
0257:            }
0258:
0259:            /**
0260:             * Sets the NotificationBroadcasterSupport associated with the MBean managing
0261:             * this virtual database.
0262:             *
0263:             * @param notificationBroadcasterSupport the notificationBroadcasterSuppor
0264:             *          associated with the mbean managing this virtual database
0265:             */
0266:            public void setNotificationBroadcasterSupport(
0267:                    NotificationBroadcasterSupport notificationBroadcasterSupport) {
0268:                this .notificationBroadcasterSupport = notificationBroadcasterSupport;
0269:            }
0270:
0271:            /**
0272:             * Sends a JMX Notification on behalf of the MBean associated with this
0273:             * virtual database
0274:             *
0275:             * @param type type of the JMX notification
0276:             * @param message message associated with the notification
0277:             * @see SequoiaNotificationList
0278:             */
0279:            protected void sendJmxNotification(String type, String message) {
0280:                if (!MBeanServerManager.isJmxEnabled()) {
0281:                    // do not send jmx notification if jmx is not enabled
0282:                    return;
0283:                }
0284:                try {
0285:                    notificationBroadcasterSupport
0286:                            .sendNotification(new Notification(
0287:                                    type,
0288:                                    JmxConstants
0289:                                            .getVirtualDataBaseObjectName(name),
0290:                                    notificationSequence++, message));
0291:                } catch (MalformedObjectNameException e) {
0292:                    // unable to get a correct vdb object name: do nothing
0293:                    logger.warn("Unable to send JMX notification", e);
0294:                }
0295:            }
0296:
0297:            /**
0298:             * Acquires a read lock on the backend lists (both enabled and disabled
0299:             * backends). This should be called prior traversing the backend
0300:             * <code>ArrayList</code>.
0301:             *
0302:             * @throws InterruptedException if an error occurs
0303:             */
0304:            public final void acquireReadLockBackendLists()
0305:                    throws InterruptedException {
0306:                rwLock.acquireRead();
0307:            }
0308:
0309:            /**
0310:             * Releases the read lock on the backend lists (both enabled and disabled
0311:             * backends). This should be called after traversing the backend
0312:             * <code>ArrayList</code>.
0313:             */
0314:            public final void releaseReadLockBackendLists() {
0315:                rwLock.releaseRead();
0316:            }
0317:
0318:            /**
0319:             * Is this virtual database distributed ?
0320:             *
0321:             * @return false
0322:             */
0323:            public boolean isDistributed() {
0324:                return false;
0325:            }
0326:
0327:            /* Request Handling */
0328:
0329:            /**
0330:             * Checks if a given virtual login/password is ok.
0331:             *
0332:             * @param virtualLogin the virtual user login
0333:             * @param virtualPassword the virtual user password
0334:             * @return <code>true</code> if the login/password is known from the
0335:             *         <code>AuthenticationManager</code>. Returns <code>false</code>
0336:             *         if no <code>AuthenticationManager</code> is defined.
0337:             */
0338:            public boolean checkUserAuthentication(String virtualLogin,
0339:                    String virtualPassword) {
0340:                if (authenticationManager == null) {
0341:                    logger
0342:                            .error("No authentification manager defined to check login '"
0343:                                    + virtualLogin + "'");
0344:                    return false;
0345:                } else {
0346:                    boolean result = authenticationManager
0347:                            .isValidVirtualUser(new VirtualDatabaseUser(
0348:                                    virtualLogin, virtualPassword));
0349:                    if (!result)
0350:                        endUserLogger.error(Translate.get(
0351:                                "virtualdatabase.authentication.failed",
0352:                                virtualLogin));
0353:                    return result;
0354:                }
0355:            }
0356:
0357:            /**
0358:             * Checks if a given admin login/password is ok.
0359:             *
0360:             * @param adminLogin admin user login
0361:             * @param adminPassword admin user password
0362:             * @return <code>true</code> if the login/password is known from the
0363:             *         <code>AuthenticationManager</code>. Returns <code>false</code>
0364:             *         if no <code>AuthenticationManager</code> is defined.
0365:             */
0366:            public boolean checkAdminAuthentication(String adminLogin,
0367:                    String adminPassword) {
0368:                if (authenticationManager == null) {
0369:                    endUserLogger.info(Translate.get(
0370:                            "virtualdatabase.checking.authentication",
0371:                            new String[] { adminLogin,
0372:                                    this .getVirtualDatabaseName() }));
0373:                    String msg = "No authentification manager defined to check admin login '"
0374:                            + adminLogin + "'";
0375:                    logger.error(msg);
0376:                    endUserLogger.error(Translate.get(
0377:                            "virtualdatabase.check.authentication.failed",
0378:                            new String[] { adminLogin,
0379:                                    this .getVirtualDatabaseName(), msg }));
0380:                    return false;
0381:                } else {
0382:                    boolean result = authenticationManager
0383:                            .isValidAdminUser(new AdminUser(adminLogin,
0384:                                    adminPassword));
0385:                    if (!result)
0386:                        endUserLogger.error(Translate.get(
0387:                                "virtualdatabase.authentication.failed",
0388:                                adminLogin));
0389:                    return result;
0390:                }
0391:            }
0392:
0393:            /**
0394:             * Adds a new vdb user. Uses the vdb login/password as real user
0395:             * login/password. Only creates the user if vdb login/password are valid for
0396:             * all backends hosting the vdb.
0397:             *
0398:             * @param vdbUser vdb user to be added.
0399:             */
0400:            public void checkAndAddVirtualDatabaseUser(
0401:                    VirtualDatabaseUser vdbUser) {
0402:                // If user does not exist in all backends leave
0403:                if (!isValidUserForAllBackends(vdbUser)) {
0404:                    if (logger.isWarnEnabled()) {
0405:                        logger.warn("Could not create new vdb user "
0406:                                + vdbUser.getLogin()
0407:                                + " because it does not exist on all backends");
0408:                    }
0409:                    return;
0410:                }
0411:
0412:                // Add user
0413:                try {
0414:                    performAddVirtualDatabaseUser(vdbUser);
0415:                    if (logger.isInfoEnabled()) {
0416:                        logger.info("Added new vdb user " + vdbUser.getLogin());
0417:                    }
0418:                } catch (SQLException e) {
0419:                    if (logger.isWarnEnabled()) {
0420:                        logger
0421:                                .warn("Problem when adding default connection manager for user "
0422:                                        + vdbUser.getLogin()
0423:                                        + ", trying to clean-up...");
0424:                        removeVirtualDatabaseUser(vdbUser);
0425:                    }
0426:                }
0427:            }
0428:
0429:            /**
0430:             * Removes vdb user.
0431:             *
0432:             * @param vdbUser vdb user to be removed.
0433:             */
0434:            private void removeVirtualDatabaseUser(VirtualDatabaseUser vdbUser) {
0435:                performRemoveVirtualDatabaseUser(vdbUser);
0436:            }
0437:
0438:            /**
0439:             * Adds new vdb user and its corresponding connection managers.
0440:             *
0441:             * @param vdbUser vdb user to be added.
0442:             * @throws SQLException thrown if problem occurred when adding connection
0443:             *           manager
0444:             */
0445:            public void performAddVirtualDatabaseUser(
0446:                    VirtualDatabaseUser vdbUser) throws SQLException {
0447:                for (Iterator iter = backends.iterator(); iter.hasNext();) {
0448:                    DatabaseBackend backend = (DatabaseBackend) iter.next();
0449:                    backend.addDefaultConnectionManager(vdbUser);
0450:                }
0451:                authenticationManager.addVirtualUser(vdbUser);
0452:                // Should we invoke authenticationManager.addRealUser() here?
0453:            }
0454:
0455:            /**
0456:             * Removes vdb user and its corresponding connection managers.
0457:             *
0458:             * @param vdbUser vdb user to be removed.
0459:             */
0460:            public void performRemoveVirtualDatabaseUser(
0461:                    VirtualDatabaseUser vdbUser) {
0462:                authenticationManager.removeVirtualUser(vdbUser);
0463:                for (Iterator iter = backends.iterator(); iter.hasNext();) {
0464:                    DatabaseBackend backend = (DatabaseBackend) iter.next();
0465:                    try {
0466:                        backend.removeConnectionManager(vdbUser);
0467:                    } catch (SQLException e) {
0468:                        if (logger.isWarnEnabled()) {
0469:                            logger
0470:                                    .warn("Problem when removing default connection manager for user "
0471:                                            + vdbUser.getLogin());
0472:                        }
0473:                    }
0474:                }
0475:                if (logger.isInfoEnabled()) {
0476:                    logger.info("Removed vdb user " + vdbUser.getLogin());
0477:                }
0478:            }
0479:
0480:            /**
0481:             * Checks if a vdb user is valid as a user for allbackends.
0482:             *
0483:             * @param vdbUser vdb user to be checked.
0484:             * @return true if vdb user is valid for all backends, false otherwise.
0485:             */
0486:            public boolean isValidUserForAllBackends(VirtualDatabaseUser vdbUser) {
0487:                boolean result = true;
0488:                for (Iterator iter = backends.iterator(); iter.hasNext();) {
0489:                    DatabaseBackend backend = (DatabaseBackend) iter.next();
0490:                    if (!backend.isValidBackendUser(vdbUser)) {
0491:                        result = false;
0492:                        break;
0493:                    }
0494:                }
0495:                return result;
0496:            }
0497:
0498:            /**
0499:             * Performs a read request and returns the reply.
0500:             *
0501:             * @param request the request to execute
0502:             * @return a <code>ControllerResultSet</code> value
0503:             * @exception SQLException if the request fails
0504:             */
0505:            protected ControllerResultSet statementExecuteQuery(
0506:                    SelectRequest request) throws SQLException {
0507:                if (request == null) {
0508:                    String msg = "Request failed (null read request received)";
0509:                    logger.warn(msg);
0510:                    throw new SQLException(msg);
0511:                }
0512:
0513:                try {
0514:                    if (requestLogger.isInfoEnabled())
0515:                        requestLogger.info("S " + request.getId() + " "
0516:                                + request.getTransactionId() + " "
0517:                                + request.getUniqueKey());
0518:
0519:                    request.setStartTime(System.currentTimeMillis());
0520:
0521:                    ControllerResultSet rs = requestManager
0522:                            .statementExecuteQuery(request);
0523:
0524:                    request.setEndTime(System.currentTimeMillis());
0525:                    if (sqlMonitor != null && sqlMonitor.isActive())
0526:                        sqlMonitor.logRequestTime(request);
0527:
0528:                    return rs;
0529:                } catch (SQLException e) {
0530:                    String msg = "Request '" + request.getId() + "' failed ("
0531:                            + e.getMessage() + ")";
0532:                    if (!request.isAutoCommit()) {
0533:                        // If the request fails in a transaction, the transaction is likely
0534:                        // to be rollbacked by the underlying database. Then we have to abort
0535:                        // the transaction.
0536:                        msg = Translate
0537:                                .get(
0538:                                        "loadbalancer.request.failed.and.abort",
0539:                                        new String[] {
0540:                                                request
0541:                                                        .getSqlShortForm(getSqlShortFormLength()),
0542:                                                e.getMessage() });
0543:                        try {
0544:                            abort(request.getTransactionId(), true, false);
0545:                        } catch (SQLException e1) {
0546:                            if (logger.isInfoEnabled())
0547:                                logger
0548:                                        .info(
0549:                                                "Abort after request failure in transaction did not succeed probably because the transaction has already been aborted",
0550:                                                e);
0551:                        }
0552:                    }
0553:                    logger.warn(msg);
0554:                    if (sqlMonitor != null && sqlMonitor.isActive())
0555:                        sqlMonitor.logError(request);
0556:                    throw e;
0557:                }
0558:            }
0559:
0560:            /**
0561:             * Performs a write request and returns the number of rows affected.
0562:             *
0563:             * @param request the request to execute
0564:             * @return number of rows affected
0565:             * @exception SQLException if the request fails
0566:             */
0567:            protected ExecuteUpdateResult statementExecuteUpdate(
0568:                    AbstractWriteRequest request) throws SQLException {
0569:                if (request == null) {
0570:                    String msg = "Request failed (null write request received)";
0571:                    logger.warn(msg);
0572:                    throw new SQLException(msg);
0573:                }
0574:
0575:                try {
0576:                    if (requestLogger.isInfoEnabled())
0577:                        requestLogger.info("W " + request.getId() + " "
0578:                                + request.getTransactionId() + " "
0579:                                + request.getUniqueKey());
0580:
0581:                    request.setStartTime(System.currentTimeMillis());
0582:
0583:                    ExecuteUpdateResult result = requestManager
0584:                            .statementExecuteUpdate(request);
0585:
0586:                    request.setEndTime(System.currentTimeMillis());
0587:                    if (sqlMonitor != null && sqlMonitor.isActive())
0588:                        sqlMonitor.logRequestTime(request);
0589:
0590:                    return result;
0591:                } catch (SQLException e) {
0592:                    String msg = "Request '" + request.getId() + "' failed ("
0593:                            + e.getMessage() + ")";
0594:
0595:                    if (!request.isAutoCommit()) {
0596:                        // If the request fails in a transaction, the transaction is likely
0597:                        // to be rollbacked by the underlying database. Then we have to abort
0598:                        // the transaction.
0599:                        msg = Translate
0600:                                .get(
0601:                                        "loadbalancer.request.failed.and.abort",
0602:                                        new String[] {
0603:                                                request
0604:                                                        .getSqlShortForm(getSqlShortFormLength()),
0605:                                                e.getMessage() });
0606:                        try {
0607:                            if (requestManager.getTransactionMetaData(new Long(
0608:                                    request.getTransactionId())) != null)
0609:                                abort(request.getTransactionId(), true, false);
0610:                        } catch (SQLException e1) {
0611:                            if (logger.isInfoEnabled())
0612:                                logger
0613:                                        .info(
0614:                                                "Abort after request failure in transaction did not succeed probably because the transaction has already been aborted",
0615:                                                e);
0616:                        }
0617:                    }
0618:
0619:                    logger.warn(msg);
0620:                    if (sqlMonitor != null && sqlMonitor.isActive())
0621:                        sqlMonitor.logError(request);
0622:                    throw e;
0623:                }
0624:            }
0625:
0626:            /**
0627:             * Performs a write request and returns the auto generated keys.
0628:             *
0629:             * @param request the request to execute
0630:             * @return auto generated keys
0631:             * @exception SQLException if the request fails
0632:             */
0633:            protected GeneratedKeysResult statementExecuteUpdateWithKeys(
0634:                    AbstractWriteRequest request) throws SQLException {
0635:                if (request == null) {
0636:                    String msg = "Request failed (null write request received)";
0637:                    logger.warn(msg);
0638:                    throw new SQLException(msg);
0639:                }
0640:
0641:                try {
0642:                    if (requestLogger.isInfoEnabled())
0643:                        requestLogger.info("W " + request.getId() + " "
0644:                                + request.getTransactionId() + " "
0645:                                + request.getUniqueKey());
0646:
0647:                    request.setStartTime(System.currentTimeMillis());
0648:
0649:                    GeneratedKeysResult result = requestManager
0650:                            .statementExecuteUpdateWithKeys(request);
0651:
0652:                    request.setEndTime(System.currentTimeMillis());
0653:                    if (sqlMonitor != null && sqlMonitor.isActive())
0654:                        sqlMonitor.logRequestTime(request);
0655:
0656:                    return result;
0657:                } catch (SQLException e) {
0658:                    String msg = "Request '" + request.getId() + "' failed ("
0659:                            + e.getMessage() + ")";
0660:                    if (!request.isAutoCommit()) {
0661:                        // If the request fails in a transaction, the transaction is likely
0662:                        // to be rollbacked by the underlying database. Then we have to abort
0663:                        // the transaction.
0664:                        abort(request.getTransactionId(), true, false);
0665:                        msg = Translate
0666:                                .get(
0667:                                        "loadbalancer.request.failed.and.abort",
0668:                                        new String[] {
0669:                                                request
0670:                                                        .getSqlShortForm(getSqlShortFormLength()),
0671:                                                e.getMessage() });
0672:                    }
0673:                    logger.warn(msg);
0674:                    if (sqlMonitor != null && sqlMonitor.isActive())
0675:                        sqlMonitor.logError(request);
0676:                    throw e;
0677:                }
0678:            }
0679:
0680:            /**
0681:             * Execute a request using Statement.execute(). Handle this as a stored
0682:             * procedure for which we have no metadata information.
0683:             *
0684:             * @param request the request to execute
0685:             * @return an <code>ExecuteResult</code> object
0686:             * @exception SQLException if an error occurs
0687:             */
0688:            protected ExecuteResult statementExecute(AbstractRequest request)
0689:                    throws SQLException {
0690:                if (request == null) {
0691:                    String msg = "Statement.execute() failed (null request received)";
0692:                    logger.warn(msg);
0693:                    throw new SQLException(msg);
0694:                }
0695:
0696:                try {
0697:                    if (requestLogger.isInfoEnabled())
0698:                        requestLogger.info("E " + request.getId() + " "
0699:                                + request.getTransactionId() + " "
0700:                                + request.getUniqueKey());
0701:
0702:                    request.setStartTime(System.currentTimeMillis());
0703:
0704:                    ExecuteResult result = requestManager
0705:                            .statementExecute(request);
0706:
0707:                    request.setEndTime(System.currentTimeMillis());
0708:                    if (sqlMonitor != null && sqlMonitor.isActive())
0709:                        sqlMonitor.logRequestTime(request);
0710:
0711:                    return result;
0712:                } catch (AllBackendsFailedException e) {
0713:                    String msg = Translate
0714:                            .get(
0715:                                    "loadbalancer.storedprocedure.failed.on.all.backends",
0716:                                    new String[] {
0717:                                            String.valueOf(request.getId()),
0718:                                            e.getMessage() });
0719:                    if (!request.isAutoCommit()) {
0720:                        // If the request fails in a transaction, the transaction is likely
0721:                        // to be rollbacked by the underlying database. Then we have to abort
0722:                        // the transaction.
0723:                        abort(request.getTransactionId(), true, false);
0724:                        msg = Translate
0725:                                .get(
0726:                                        "loadbalancer.request.failed.and.abort",
0727:                                        new String[] {
0728:                                                request
0729:                                                        .getSqlShortForm(getSqlShortFormLength()),
0730:                                                e.getMessage() });
0731:                    }
0732:                    logger.warn(msg);
0733:                    if (sqlMonitor != null && sqlMonitor.isActive())
0734:                        sqlMonitor.logError(request);
0735:                    throw new SQLException(msg);
0736:                } catch (SQLException e) {
0737:                    String msg = Translate.get(
0738:                            "loadbalancer.storedprocedure.failed",
0739:                            new String[] { String.valueOf(request.getId()),
0740:                                    e.getMessage() });
0741:                    if (!request.isAutoCommit()) {
0742:                        // If the request fails in a transaction, the transaction is likely
0743:                        // to be rollbacked by the underlying database. Then we have to abort
0744:                        // the transaction.
0745:                        abort(request.getTransactionId(), true, false);
0746:                        msg = Translate
0747:                                .get(
0748:                                        "loadbalancer.request.failed.and.abort",
0749:                                        new String[] {
0750:                                                request
0751:                                                        .getSqlShortForm(getSqlShortFormLength()),
0752:                                                e.getMessage() });
0753:                    }
0754:                    logger.warn(msg);
0755:                    if (sqlMonitor != null && sqlMonitor.isActive())
0756:                        sqlMonitor.logError(request);
0757:                    throw e;
0758:                }
0759:            }
0760:
0761:            /**
0762:             * Call a stored procedure that returns a ResultSet.
0763:             *
0764:             * @param proc the stored procedure call
0765:             * @return a <code>java.sql.ResultSet</code> value
0766:             * @exception SQLException if an error occurs
0767:             */
0768:            protected ControllerResultSet callableStatementExecuteQuery(
0769:                    StoredProcedure proc) throws SQLException {
0770:                if (proc == null) {
0771:                    String msg = "Request failed (null stored procedure received)";
0772:                    logger.warn(msg);
0773:                    throw new SQLException(msg);
0774:                }
0775:
0776:                try {
0777:                    if (requestLogger.isInfoEnabled())
0778:                        requestLogger.info("S " + proc.getId() + " "
0779:                                + proc.getTransactionId() + " "
0780:                                + proc.getUniqueKey());
0781:
0782:                    proc.setStartTime(System.currentTimeMillis());
0783:
0784:                    ControllerResultSet rs = requestManager
0785:                            .callableStatementExecuteQuery(proc);
0786:
0787:                    proc.setEndTime(System.currentTimeMillis());
0788:                    if (sqlMonitor != null && sqlMonitor.isActive())
0789:                        sqlMonitor.logRequestTime(proc);
0790:
0791:                    return rs;
0792:                } catch (AllBackendsFailedException e) {
0793:                    String msg = Translate
0794:                            .get(
0795:                                    "loadbalancer.storedprocedure.failed.on.all.backends",
0796:                                    new String[] {
0797:                                            String.valueOf(proc.getId()),
0798:                                            e.getMessage() });
0799:                    if (!proc.isAutoCommit()) {
0800:                        // If the request fails in a transaction, the transaction is likely
0801:                        // to be rollbacked by the underlying database. Then we have to abort
0802:                        // the transaction.
0803:                        abort(proc.getTransactionId(), true, false);
0804:                        msg = Translate
0805:                                .get(
0806:                                        "loadbalancer.request.failed.and.abort",
0807:                                        new String[] {
0808:                                                proc
0809:                                                        .getSqlShortForm(getSqlShortFormLength()),
0810:                                                e.getMessage() });
0811:                    }
0812:                    logger.warn(msg);
0813:                    if (sqlMonitor != null && sqlMonitor.isActive())
0814:                        sqlMonitor.logError(proc);
0815:                    throw new SQLException(msg);
0816:                } catch (SQLException e) {
0817:                    String msg = Translate.get(
0818:                            "loadbalancer.storedprocedure.failed",
0819:                            new String[] { String.valueOf(proc.getId()),
0820:                                    e.getMessage() });
0821:                    if (!proc.isAutoCommit()) {
0822:                        // If the request fails in a transaction, the transaction is likely
0823:                        // to be rollbacked by the underlying database. Then we have to abort
0824:                        // the transaction.
0825:                        abort(proc.getTransactionId(), true, false);
0826:                        msg = Translate
0827:                                .get(
0828:                                        "loadbalancer.request.failed.and.abort",
0829:                                        new String[] {
0830:                                                proc
0831:                                                        .getSqlShortForm(getSqlShortFormLength()),
0832:                                                e.getMessage() });
0833:                    }
0834:                    logger.warn(msg);
0835:                    if (sqlMonitor != null && sqlMonitor.isActive())
0836:                        sqlMonitor.logError(proc);
0837:                    throw e;
0838:                }
0839:            }
0840:
0841:            /**
0842:             * Call a stored procedure that performs an update.
0843:             *
0844:             * @param proc the stored procedure call
0845:             * @return number of rows affected
0846:             * @exception SQLException if an error occurs
0847:             */
0848:            protected ExecuteUpdateResult callableStatementExecuteUpdate(
0849:                    StoredProcedure proc) throws SQLException {
0850:                if (proc == null) {
0851:                    String msg = "Request failed (null stored procedure received)";
0852:                    logger.warn(msg);
0853:                    throw new SQLException(msg);
0854:                }
0855:
0856:                try {
0857:                    if (requestLogger.isInfoEnabled())
0858:                        requestLogger.info("W " + proc.getId() + " "
0859:                                + proc.getTransactionId() + " "
0860:                                + proc.getUniqueKey());
0861:
0862:                    proc.setStartTime(System.currentTimeMillis());
0863:
0864:                    ExecuteUpdateResult result = requestManager
0865:                            .callableStatementExecuteUpdate(proc);
0866:
0867:                    proc.setEndTime(System.currentTimeMillis());
0868:                    if (sqlMonitor != null && sqlMonitor.isActive())
0869:                        sqlMonitor.logRequestTime(proc);
0870:
0871:                    return result;
0872:                } catch (AllBackendsFailedException e) {
0873:                    String msg = Translate
0874:                            .get(
0875:                                    "loadbalancer.storedprocedure.failed.on.all.backends",
0876:                                    new String[] {
0877:                                            String.valueOf(proc.getId()),
0878:                                            e.getMessage() });
0879:                    if (!proc.isAutoCommit()) {
0880:                        // If the request fails in a transaction, the transaction is likely
0881:                        // to be rollbacked by the underlying database. Then we have to abort
0882:                        // the transaction.
0883:                        abort(proc.getTransactionId(), true, false);
0884:                        msg = Translate
0885:                                .get(
0886:                                        "loadbalancer.request.failed.and.abort",
0887:                                        new String[] {
0888:                                                proc
0889:                                                        .getSqlShortForm(getSqlShortFormLength()),
0890:                                                e.getMessage() });
0891:                    }
0892:                    logger.warn(msg);
0893:                    if (sqlMonitor != null && sqlMonitor.isActive())
0894:                        sqlMonitor.logError(proc);
0895:                    throw new SQLException(msg);
0896:                } catch (SQLException e) {
0897:                    String msg = Translate.get(
0898:                            "loadbalancer.storedprocedure.failed",
0899:                            new String[] { String.valueOf(proc.getId()),
0900:                                    e.getMessage() });
0901:                    if (!proc.isAutoCommit()) {
0902:                        // If the request fails in a transaction, the transaction is likely
0903:                        // to be rollbacked by the underlying database. Then we have to abort
0904:                        // the transaction.
0905:                        abort(proc.getTransactionId(), true, false);
0906:                        msg = Translate
0907:                                .get(
0908:                                        "loadbalancer.request.failed.and.abort",
0909:                                        new String[] {
0910:                                                proc
0911:                                                        .getSqlShortForm(getSqlShortFormLength()),
0912:                                                e.getMessage() });
0913:                    }
0914:                    logger.warn(msg);
0915:                    if (sqlMonitor != null && sqlMonitor.isActive())
0916:                        sqlMonitor.logError(proc);
0917:                    throw e;
0918:                }
0919:            }
0920:
0921:            /**
0922:             * Execute a call to CallableStatement.execute() and returns a suite of
0923:             * updateCount and/or ResultSets.
0924:             *
0925:             * @param proc the stored procedure to execute
0926:             * @return an <code>ExecuteResult</code> object
0927:             * @exception SQLException if an error occurs
0928:             */
0929:            protected ExecuteResult callableStatementExecute(
0930:                    StoredProcedure proc) throws SQLException {
0931:                if (proc == null) {
0932:                    String msg = "Request failed (null stored procedure received)";
0933:                    logger.warn(msg);
0934:                    throw new SQLException(msg);
0935:                }
0936:
0937:                try {
0938:                    if (requestLogger.isInfoEnabled())
0939:                        requestLogger.info("E " + proc.getId() + " "
0940:                                + proc.getTransactionId() + " "
0941:                                + proc.getUniqueKey());
0942:
0943:                    proc.setStartTime(System.currentTimeMillis());
0944:
0945:                    ExecuteResult result = requestManager
0946:                            .callableStatementExecute(proc);
0947:
0948:                    proc.setEndTime(System.currentTimeMillis());
0949:                    if (sqlMonitor != null && sqlMonitor.isActive())
0950:                        sqlMonitor.logRequestTime(proc);
0951:
0952:                    return result;
0953:                } catch (AllBackendsFailedException e) {
0954:                    String msg = Translate
0955:                            .get(
0956:                                    "loadbalancer.storedprocedure.failed.on.all.backends",
0957:                                    new String[] {
0958:                                            String.valueOf(proc.getId()),
0959:                                            e.getMessage() });
0960:                    if (!proc.isAutoCommit()) {
0961:                        // If the request fails in a transaction, the transaction is likely
0962:                        // to be rollbacked by the underlying database. Then we have to abort
0963:                        // the transaction.
0964:                        abort(proc.getTransactionId(), true, false);
0965:                        msg = Translate
0966:                                .get(
0967:                                        "loadbalancer.request.failed.and.abort",
0968:                                        new String[] {
0969:                                                proc
0970:                                                        .getSqlShortForm(getSqlShortFormLength()),
0971:                                                e.getMessage() });
0972:                    }
0973:                    logger.warn(msg);
0974:                    if (sqlMonitor != null && sqlMonitor.isActive())
0975:                        sqlMonitor.logError(proc);
0976:                    throw new SQLException(msg);
0977:                } catch (SQLException e) {
0978:                    String msg = Translate.get(
0979:                            "loadbalancer.storedprocedure.failed",
0980:                            new String[] { String.valueOf(proc.getId()),
0981:                                    e.getMessage() });
0982:                    if (!proc.isAutoCommit()) {
0983:                        // If the request fails in a transaction, the transaction is likely
0984:                        // to be rollbacked by the underlying database. Then we have to abort
0985:                        // the transaction.
0986:                        abort(proc.getTransactionId(), true, false);
0987:                        msg = Translate
0988:                                .get(
0989:                                        "loadbalancer.request.failed.and.abort",
0990:                                        new String[] {
0991:                                                proc
0992:                                                        .getSqlShortForm(getSqlShortFormLength()),
0993:                                                e.getMessage() });
0994:                    }
0995:                    logger.warn(msg);
0996:                    if (sqlMonitor != null && sqlMonitor.isActive())
0997:                        sqlMonitor.logError(proc);
0998:                    throw e;
0999:                }
1000:            }
1001:
1002:            /**
1003:             * Close the given persistent connection.
1004:             *
1005:             * @param login login to use to retrieve the right connection pool
1006:             * @param persistentConnectionId id of the persistent connection to close
1007:             */
1008:            public void closePersistentConnection(String login,
1009:                    long persistentConnectionId) {
1010:                requestManager.closePersistentConnection(login,
1011:                        persistentConnectionId);
1012:            }
1013:
1014:            /**
1015:             * Returns true if the virtual database has opened the given persistent
1016:             * connection.
1017:             *
1018:             * @param persistentConnectionId id of the persistent connection to check
1019:             * @return true if the connection is open
1020:             */
1021:            public boolean hasPersistentConnection(long persistentConnectionId) {
1022:                return requestManager
1023:                        .hasPersistentConnection(persistentConnectionId);
1024:            }
1025:
1026:            /**
1027:             * Open the given persistent connection.
1028:             *
1029:             * @param login login to use to retrieve the right connection pool
1030:             * @param persistentConnectionId id of the persistent connection to open
1031:             * @throws SQLException if an error occurs while opening the connection
1032:             */
1033:            public void openPersistentConnection(String login,
1034:                    long persistentConnectionId) throws SQLException {
1035:                requestManager.openPersistentConnection(login,
1036:                        persistentConnectionId, null);
1037:            }
1038:
1039:            /**
1040:             * Notify the failover of the given transaction (really useful for
1041:             * DistributedVirtualDatabase)
1042:             *
1043:             * @param currentTid transaction id
1044:             */
1045:            public void failoverForTransaction(long currentTid) {
1046:                logger
1047:                        .info("Transparent client failover operated for transaction "
1048:                                + currentTid);
1049:            }
1050:
1051:            /**
1052:             * Notify the failover of the given persistent connection (really useful for
1053:             * DistributedVirtualDatabase)
1054:             *
1055:             * @param persistentConnectionId the persistent connection id
1056:             */
1057:            public void failoverForPersistentConnection(
1058:                    long persistentConnectionId) {
1059:                // This should never happen when we have a single controller since when we
1060:                // die there is no one to fail over.
1061:                logger
1062:                        .info("Unexpected transparent client failover operated for persistent connection "
1063:                                + persistentConnectionId);
1064:            }
1065:
1066:            protected final Object CONNECTION_ID_SYNC_OBJECT = new Object();
1067:
1068:            /**
1069:             * Return the next connection identifier (monotically increasing number).
1070:             *
1071:             * @return a connection identifier
1072:             */
1073:            public long getNextConnectionId() {
1074:                synchronized (CONNECTION_ID_SYNC_OBJECT) {
1075:                    return connectionId++;
1076:                }
1077:            }
1078:
1079:            /**
1080:             * Return the next request identifier (monotically increasing number).
1081:             *
1082:             * @return a request identifier
1083:             */
1084:            public long getNextRequestId() {
1085:                return requestManager.getNextRequestId();
1086:            }
1087:
1088:            /**
1089:             * Return a ControllerResultSet containing the PreparedStatement metaData of
1090:             * the given sql template
1091:             *
1092:             * @param request the request containing the sql template
1093:             * @return an empty ControllerResultSet with the metadata
1094:             * @throws SQLException if a database error occurs
1095:             */
1096:            public ControllerResultSet getPreparedStatementGetMetaData(
1097:                    AbstractRequest request) throws SQLException {
1098:                try {
1099:                    return requestManager
1100:                            .getPreparedStatementGetMetaData(request);
1101:                } catch (NoMoreBackendException e) {
1102:                    throw e;
1103:                }
1104:            }
1105:
1106:            /*
1107:             * Transaction management
1108:             */
1109:
1110:            /**
1111:             * Begins a new transaction and returns the corresponding transaction
1112:             * identifier. This method is called from the driver when
1113:             * {@link org.continuent.sequoia.driver.Connection#setAutoCommit(boolean)}is
1114:             * called with <code>false</code> argument.
1115:             * <p>
1116:             * Note that the transaction begin is not logged in the recovery log by this
1117:             * method, you will have to call logLazyTransactionBegin.
1118:             *
1119:             * @param login the login used by the connection
1120:             * @param isPersistentConnection true if the transaction is started on a
1121:             *          persistent connection
1122:             * @param persistentConnectionId persistent connection id if the transaction
1123:             *          must be started on a persistent connection
1124:             * @return an unique transaction identifier
1125:             * @exception SQLException if an error occurs
1126:             * @see RequestManager#logLazyTransactionBegin(long)
1127:             */
1128:            public long begin(String login, boolean isPersistentConnection,
1129:                    long persistentConnectionId) throws SQLException {
1130:                try {
1131:                    long tid = requestManager.begin(login,
1132:                            isPersistentConnection, persistentConnectionId);
1133:                    if (requestLogger.isInfoEnabled())
1134:                        requestLogger.info("B " + tid);
1135:                    return tid;
1136:                } catch (SQLException e) {
1137:                    String msg = "Begin failed (" + e.getMessage() + ")";
1138:                    logger.warn(msg);
1139:                    throw e;
1140:                }
1141:            }
1142:
1143:            /**
1144:             * Abort a transaction that has been started but in which no query was
1145:             * executed. As we use lazy transaction begin, there is no need to rollback
1146:             * such transaction but just to cleanup the metadata associated with this not
1147:             * effectively started transaction.
1148:             *
1149:             * @param transactionId id of the transaction to abort
1150:             * @param logAbort true if the abort (in fact rollback) should be logged in
1151:             *          the recovery log
1152:             * @param forceAbort true if the abort will be forced. Actually, abort will do
1153:             *          nothing when a transaction has savepoints (we do not abort the
1154:             *          whole transaction, so that the user can rollback to a previous
1155:             *          savepoint), except when the connection is closed. In this last
1156:             *          case, if the transaction is not aborted, it prevents future
1157:             *          maintenance operations such as shutdowns, enable/disable from
1158:             *          completing, so we have to force this abort operation. It also
1159:             *          applies to the DeadlockDetectionThread and the cleanup of the
1160:             *          VirtualDatabaseWorkerThread.
1161:             * @throws SQLException if an error occurs
1162:             */
1163:            public void abort(long transactionId, boolean logAbort,
1164:                    boolean forceAbort) throws SQLException {
1165:                requestManager.abort(transactionId, logAbort, forceAbort);
1166:                // Emulate this as a rollback for the RequestPlayer
1167:                if (requestLogger.isInfoEnabled())
1168:                    requestLogger.info("R " + transactionId);
1169:            }
1170:
1171:            /**
1172:             * Commits a transaction given its id.
1173:             *
1174:             * @param transactionId the transaction id
1175:             * @param logCommit true if the commit should be logged in the recovery log
1176:             * @param emptyTransaction true if this transaction has not executed any
1177:             *          request
1178:             * @exception SQLException if an error occurs
1179:             */
1180:            public void commit(long transactionId, boolean logCommit,
1181:                    boolean emptyTransaction) throws SQLException {
1182:                try {
1183:                    if (requestLogger.isInfoEnabled())
1184:                        requestLogger.info("C " + transactionId);
1185:                    requestManager.commit(transactionId, logCommit,
1186:                            emptyTransaction);
1187:                } catch (SQLException e) {
1188:
1189:                    String msg = "Commit of transaction '" + transactionId
1190:                            + "' failed (" + e.getMessage() + ")";
1191:
1192:                    // If the commit fails in a transaction, the transaction is likely
1193:                    // to be rollbacked by the underlying database. Then we have to abort
1194:                    // the transaction.
1195:                    msg = Translate.get("loadbalancer.commit.failed.and.abort",
1196:                            new String[] { Long.toString(transactionId),
1197:                                    e.getMessage() });
1198:                    try {
1199:                        abort(transactionId, true, false);
1200:                    } catch (SQLException e1) {
1201:                        if (logger.isInfoEnabled())
1202:                            logger
1203:                                    .info(
1204:                                            "Abort after commit failure in transaction did not succeed probably because the transaction has already been aborted",
1205:                                            e);
1206:                    }
1207:
1208:                    logger.warn(msg);
1209:                    throw e;
1210:                }
1211:            }
1212:
1213:            /**
1214:             * Rollbacks a transaction given its id.
1215:             *
1216:             * @param transactionId the transaction id
1217:             * @param logRollback true if the rollback should be logged in the recovery
1218:             *          log
1219:             * @exception SQLException if an error occurs
1220:             */
1221:            public void rollback(long transactionId, boolean logRollback)
1222:                    throws SQLException {
1223:                try {
1224:                    if (requestLogger.isInfoEnabled())
1225:                        requestLogger.info("R " + transactionId);
1226:                    requestManager.rollback(transactionId, logRollback);
1227:                } catch (SQLException e) {
1228:                    String msg = "Rollback of transaction '" + transactionId
1229:                            + "' failed (" + e.getMessage() + ")";
1230:
1231:                    // If the rollback fails in a transaction, the transaction is likely
1232:                    // to be rollbacked by the underlying database. Then we have to abort
1233:                    // the transaction.
1234:                    msg = Translate.get(
1235:                            "loadbalancer.rollback.failed.and.abort",
1236:                            new String[] { Long.toString(transactionId),
1237:                                    e.getMessage() });
1238:                    try {
1239:                        abort(transactionId, true, false);
1240:                    } catch (SQLException e1) {
1241:                        if (logger.isInfoEnabled())
1242:                            logger
1243:                                    .info(
1244:                                            "Abort after rollback failure in transaction did not succeed probably because the transaction has already been aborted",
1245:                                            e);
1246:                    }
1247:
1248:                    logger.warn(msg);
1249:                    throw e;
1250:                }
1251:            }
1252:
1253:            /**
1254:             * Rollbacks a transaction given its id to a savepoint given its name
1255:             *
1256:             * @param transactionId the transaction id
1257:             * @param savepointName the name of the savepoint
1258:             * @exception SQLException if an error occurs
1259:             */
1260:            public void rollback(long transactionId, String savepointName)
1261:                    throws SQLException {
1262:                try {
1263:                    if (requestLogger.isInfoEnabled())
1264:                        requestLogger.info("R " + transactionId + " "
1265:                                + savepointName);
1266:                    requestManager.rollback(transactionId, savepointName);
1267:                } catch (SQLException e) {
1268:                    String msg = "Rollback to savepoint '" + savepointName
1269:                            + "' for " + "transaction '" + transactionId
1270:                            + "' failed (" + e.getMessage() + ")";
1271:
1272:                    // If the rollback fails in a transaction, the transaction is likely
1273:                    // to be rollbacked by the underlying database. Then we have to abort
1274:                    // the transaction.
1275:                    msg = Translate.get(
1276:                            "loadbalancer.rollback.failed.and.abort",
1277:                            new String[] { Long.toString(transactionId),
1278:                                    e.getMessage() });
1279:                    try {
1280:                        abort(transactionId, true, false);
1281:                    } catch (SQLException e1) {
1282:                        if (logger.isInfoEnabled())
1283:                            logger
1284:                                    .info(
1285:                                            "Abort after rollback failure in transaction did not succeed probably because the transaction has already been aborted",
1286:                                            e);
1287:                    }
1288:
1289:                    logger.warn(msg);
1290:                    throw e;
1291:                }
1292:            }
1293:
1294:            /**
1295:             * Sets a unnamed savepoint to a transaction given its id.
1296:             *
1297:             * @param transactionId the transaction id
1298:             * @return the savepoint id
1299:             * @exception SQLException if an error occurs
1300:             */
1301:            public int setSavepoint(long transactionId) throws SQLException {
1302:                try {
1303:                    int savepointId = requestManager
1304:                            .setSavepoint(transactionId);
1305:                    if (requestLogger.isInfoEnabled())
1306:                        requestLogger.info("P " + transactionId + " "
1307:                                + savepointId);
1308:                    return savepointId;
1309:                } catch (SQLException e) {
1310:                    String msg = "Setting unnamed savepoint to transaction '"
1311:                            + transactionId + "' failed (" + e.getMessage()
1312:                            + ")";
1313:                    logger.warn(msg);
1314:                    throw e;
1315:                }
1316:            }
1317:
1318:            /**
1319:             * Sets a savepoint given its desired name to a transaction given its id.
1320:             *
1321:             * @param transactionId the transaction id
1322:             * @param name the desired name of the savepoint
1323:             * @exception SQLException if an error occurs
1324:             */
1325:            public void setSavepoint(long transactionId, String name)
1326:                    throws SQLException {
1327:                try {
1328:                    if (requestLogger.isInfoEnabled())
1329:                        requestLogger.info("P " + transactionId + " " + name);
1330:                    requestManager.setSavepoint(transactionId, name);
1331:                } catch (SQLException e) {
1332:                    String msg = "Setting savepoint with name '" + name
1333:                            + "' to transaction " + "'" + transactionId
1334:                            + "' failed (" + e.getMessage() + ")";
1335:                    logger.warn(msg);
1336:                    throw e;
1337:                }
1338:            }
1339:
1340:            /**
1341:             * Releases a savepoint given its name from a transaction given its id.
1342:             *
1343:             * @param transactionId the transaction id
1344:             * @param savepointName the name of the savepoint
1345:             * @exception SQLException if an error occurs
1346:             */
1347:            public void releaseSavepoint(long transactionId,
1348:                    String savepointName) throws SQLException {
1349:                try {
1350:                    if (requestLogger.isInfoEnabled())
1351:                        requestLogger.info("F " + transactionId + " "
1352:                                + savepointName);
1353:                    requestManager.releaseSavepoint(transactionId,
1354:                            savepointName);
1355:                } catch (SQLException e) {
1356:                    String msg = "Releasing savepoint with name '"
1357:                            + savepointName + "' from " + "transaction '"
1358:                            + transactionId + "' failed (" + e.getMessage()
1359:                            + ")";
1360:                    logger.warn(msg);
1361:                    throw e;
1362:                }
1363:            }
1364:
1365:            //
1366:            // Database backends management
1367:            //
1368:
1369:            /**
1370:             * Add a backend to this virtual database.
1371:             *
1372:             * @param db the database backend to add
1373:             * @throws VirtualDatabaseException if an error occurs
1374:             */
1375:            public void addBackend(DatabaseBackend db)
1376:                    throws VirtualDatabaseException {
1377:                this .addBackend(db, true);
1378:            }
1379:
1380:            /**
1381:             * Add a backend to this virtual database.
1382:             *
1383:             * @param db the database backend to add
1384:             * @param checkForCompliance should load the driver ?
1385:             * @throws VirtualDatabaseException if an error occurs
1386:             */
1387:            public void addBackend(DatabaseBackend db,
1388:                    boolean checkForCompliance) throws VirtualDatabaseException {
1389:                if (db == null) {
1390:                    String msg = "Illegal null database backend in addBackend(DatabaseBackend) method";
1391:                    logger.error(msg);
1392:                    throw new VirtualDatabaseException(msg);
1393:                }
1394:
1395:                if (db.isReadEnabled()) {
1396:                    String msg = "It is not allowed to add an enabled database.";
1397:                    logger.error(msg);
1398:                    throw new VirtualDatabaseException(msg);
1399:                }
1400:
1401:                // Get the lock on the list of backends
1402:                try {
1403:                    rwLock.acquireWrite();
1404:                } catch (InterruptedException e) {
1405:                    String msg = Translate
1406:                            .get(
1407:                                    "loadbalancer.backendlist.acquire.writelock.failed",
1408:                                    e);
1409:                    logger.error(msg);
1410:                    throw new VirtualDatabaseException(msg);
1411:                }
1412:
1413:                // Check that the backend is not already up
1414:                if (backends.indexOf(db) != -1) {
1415:                    rwLock.releaseWrite();
1416:                    String msg = "Duplicate backend " + db.getURL();
1417:                    logger.warn(msg);
1418:                    throw new VirtualDatabaseException(msg);
1419:                }
1420:
1421:                // Check the authentication manager has all virtual logins defined
1422:                ArrayList logins = authenticationManager.getVirtualLogins();
1423:                VirtualDatabaseUser vdu;
1424:                String login;
1425:                for (int i = 0; i < logins.size(); i++) {
1426:                    vdu = (VirtualDatabaseUser) logins.get(i);
1427:                    login = vdu.getLogin();
1428:                    if (db.getConnectionManager(login) == null) {
1429:                        rwLock.releaseWrite();
1430:                        throw new VirtualDatabaseException(Translate.get(
1431:                                "backend.missing.connection.manager", login));
1432:                    }
1433:                }
1434:
1435:                // Initialize the driver and check the compliance
1436:                try {
1437:                    if (logger.isDebugEnabled())
1438:                        logger.debug("Checking driver compliance");
1439:                    if (checkForCompliance)
1440:                        db.checkDriverCompliance(); // Also loads the driver
1441:                } catch (Exception e) {
1442:                    rwLock.releaseWrite();
1443:                    String msg = "Error while adding database backend "
1444:                            + db.getName() + " (" + e + ")";
1445:                    logger.warn(msg);
1446:                    throw new VirtualDatabaseException(msg);
1447:                }
1448:
1449:                db.setSqlShortFormLength(getSqlShortFormLength());
1450:
1451:                // Add the backend to the list
1452:                backends.add(db);
1453:                if (logger.isDebugEnabled())
1454:                    logger.debug("Backend " + db.getName()
1455:                            + " added successfully");
1456:
1457:                // Set the backend state listener so that the state is logged into the
1458:                // recovery log - if any. When there is no recovery log,
1459:                // getBackendStateListener returns null, and stateListener is consequently
1460:                // set to null. Looks like the only state listner ever is the recoveryLog.
1461:                /*
1462:                 * Note: getRequestManager() is null, at load time, thus the test. At load
1463:                 * time, if there is a recovery log, the state listner eventually gets set,
1464:                 * but in a different fashion: it is set by RequestManager c'tor, when
1465:                 * calling setRecoveryLog().
1466:                 */
1467:                if (getRequestManager() != null) {
1468:                    db.setStateListener(getRequestManager()
1469:                            .getBackendStateListener());
1470:                }
1471:
1472:                // Release the lock
1473:                rwLock.releaseWrite();
1474:
1475:                // Notify Jmx listeners of the backend addition
1476:                sendJmxNotification(
1477:                        SequoiaNotificationList.VIRTUALDATABASE_BACKEND_ADDED,
1478:                        Translate.get("notification.backend.added", db
1479:                                .getName()));
1480:
1481:                // Add backend mbean to jmx server
1482:                if (MBeanServerManager.isJmxEnabled()) {
1483:                    try {
1484:                        ObjectName objectName = JmxConstants
1485:                                .getDatabaseBackendObjectName(name, db
1486:                                        .getName());
1487:                        org.continuent.sequoia.controller.backend.management.DatabaseBackend managingBackend = new org.continuent.sequoia.controller.backend.management.DatabaseBackend(
1488:                                db);
1489:                        db.setNotificationBroadcaster(managingBackend
1490:                                .getBroadcaster());
1491:                        MBeanServerManager.registerMBean(managingBackend,
1492:                                objectName);
1493:                    } catch (Exception e) {
1494:                        logger.error(Translate.get(
1495:                                "virtualdatabase.fail.register.backend.mbean",
1496:                                db.getName()), e);
1497:                    }
1498:                }
1499:            }
1500:
1501:            /**
1502:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#forceDisableBackend(String)
1503:             */
1504:            public void forceDisableBackend(String backendName)
1505:                    throws VirtualDatabaseException {
1506:                try {
1507:                    DatabaseBackend db = getAndCheckBackend(backendName,
1508:                            CHECK_BACKEND_DISABLE);
1509:                    requestManager.disableBackend(db, true);
1510:                    requestManager
1511:                            .setDatabaseSchema(
1512:                                    getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames(),
1513:                                    false);
1514:
1515:                    sendJmxNotification(
1516:                            SequoiaNotificationList.VIRTUALDATABASE_BACKEND_DISABLED,
1517:                            Translate.get("notification.backend.disabled", db
1518:                                    .getName()));
1519:                } catch (Exception e) {
1520:                    logger.error("An error occured while disabling backend "
1521:                            + backendName + " (" + e + ")");
1522:                    throw new VirtualDatabaseException(e.getMessage(), e);
1523:                }
1524:            }
1525:
1526:            /**
1527:             * Prepare this virtual database for shutdown. This turns off all the backends
1528:             * by cutting communication from this database. This does not prevents other
1529:             * virtual database to use shared backends. This doesn't create checkpoints
1530:             * either.
1531:             *
1532:             * @param forceEnable true if backend disabling must be forced, false for
1533:             *          regular/clean disabling
1534:             * @throws VirtualDatabaseException if an error occurs
1535:             */
1536:            public void disableAllBackends(boolean forceEnable)
1537:                    throws VirtualDatabaseException {
1538:                try {
1539:                    int size = this .backends.size();
1540:                    DatabaseBackend dbe;
1541:                    for (int i = 0; i < size; i++) {
1542:                        dbe = (DatabaseBackend) backends.get(i);
1543:                        if (dbe.isReadEnabled())
1544:                            requestManager.disableBackend(getAndCheckBackend(
1545:                                    dbe.getName(), CHECK_BACKEND_DISABLE),
1546:                                    forceEnable);
1547:                    }
1548:                } catch (Exception e) {
1549:                    throw new VirtualDatabaseException(e.getMessage(), e);
1550:                }
1551:            }
1552:
1553:            /**
1554:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#disableBackendWithCheckpoint(String)
1555:             */
1556:            public void disableBackendWithCheckpoint(String backendName)
1557:                    throws VirtualDatabaseException {
1558:                try {
1559:                    DatabaseBackend backend = getAndCheckBackend(backendName,
1560:                            NO_CHECK_BACKEND);
1561:                    if (backend.isDisabled()) {
1562:                        logger.info("Backend " + backendName
1563:                                + " is already disabled.");
1564:                        // disabling a disabled backend is a no-op
1565:                        return;
1566:                    }
1567:                    requestManager.disableBackendWithCheckpoint(backend,
1568:                            buildCheckpointName("disable " + backendName));
1569:                    // Force a schema refresh if we are not in RAIDb-1
1570:                    if (requestManager.getLoadBalancer().getRAIDbLevel() != RAIDbLevels.RAIDb1)
1571:                        requestManager
1572:                                .setDatabaseSchema(
1573:                                        getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames(),
1574:                                        false);
1575:                } catch (Exception e) {
1576:                    logger.error("An error occured while disabling backend "
1577:                            + backendName + " (" + e + ")");
1578:                    throw new VirtualDatabaseException(e.getMessage(), e);
1579:                }
1580:            }
1581:
1582:            /**
1583:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#disableAllBackendsWithCheckpoint(java.lang.String)
1584:             */
1585:            public void disableAllBackendsWithCheckpoint(String checkpoint)
1586:                    throws VirtualDatabaseException {
1587:                if (checkpoint == null) {
1588:                    disableAllBackends(false);
1589:                    return;
1590:                }
1591:
1592:                try {
1593:                    this .acquireReadLockBackendLists();
1594:                } catch (InterruptedException e) {
1595:                    throw new VirtualDatabaseException(e.getMessage(), e);
1596:                }
1597:
1598:                try {
1599:                    ArrayList backendInfos = new ArrayList();
1600:                    Iterator iter = backends.iterator();
1601:                    while (iter.hasNext()) {
1602:                        DatabaseBackend backend = (DatabaseBackend) iter.next();
1603:                        backendInfos.add(new BackendInfo(backend));
1604:                    }
1605:                    requestManager.disableBackendsWithCheckpoint(backendInfos,
1606:                            checkpoint);
1607:                } catch (Exception e) {
1608:                    throw new VirtualDatabaseException(e.getMessage(), e);
1609:                } finally {
1610:                    this .releaseReadLockBackendLists();
1611:                }
1612:            }
1613:
1614:            /**
1615:             * Check that the virtual database is not resyncing its recovery log or
1616:             * shutting down. This would prevent enable operations to take place.
1617:             *
1618:             * @throws VirtualDatabaseException if virtual database is resyncing or
1619:             *           shutting down.
1620:             */
1621:            private void enableBackendSanityChecks()
1622:                    throws VirtualDatabaseException {
1623:                if (isResyncing()) {
1624:                    String msg = Translate
1625:                            .get("virtualdatabase.fail.enable.cause.resyncing");
1626:                    logger.warn(msg);
1627:                    throw new VirtualDatabaseException(msg);
1628:                }
1629:
1630:                if (isShuttingDown()) {
1631:                    String msg = Translate
1632:                            .get("virtualdatabase.fail.enable.cause.shutdown");
1633:                    logger.warn(msg);
1634:                    throw new VirtualDatabaseException(msg);
1635:                }
1636:            }
1637:
1638:            /**
1639:             * Enable the given backend from the given checkpoint. This method returns
1640:             * once the recovery is complete.
1641:             *
1642:             * @param backendName backend to enable
1643:             * @param checkpointName checkpoint to enable from
1644:             * @throws VirtualDatabaseException if an error occurs
1645:             */
1646:            public void enableBackendFromCheckpoint(String backendName,
1647:                    String checkpointName) throws VirtualDatabaseException {
1648:                enableBackendSanityChecks();
1649:
1650:                EnableBackendOperation enableOperation = new EnableBackendOperation(
1651:                        backendName);
1652:                addAdminOperation(enableOperation);
1653:
1654:                // Call the Request Manager
1655:                try {
1656:                    DatabaseBackend backend = getAndCheckBackend(backendName,
1657:                            CHECK_BACKEND_ENABLE);
1658:                    RecoverThread recoverThread = requestManager
1659:                            .enableBackendFromCheckpoint(backend,
1660:                                    checkpointName);
1661:                    // Wait for recovery to complete
1662:                    recoverThread.join();
1663:                    if (recoverThread.getException() != null) {
1664:                        throw recoverThread.getException();
1665:                    }
1666:                    requestManager.setSchemaIsDirty(true);
1667:
1668:                    // Update the static metadata
1669:                    getStaticMetaData().gatherStaticMetadata(backend);
1670:
1671:                    // Update the list of database product names
1672:                    if (databaseProductNames.indexOf(backend
1673:                            .getDatabaseProductName()) == -1)
1674:                        databaseProductNames += ","
1675:                                + backend.getDatabaseProductName();
1676:                } catch (Exception e) {
1677:                    String msg = Translate.get(
1678:                            "virtualdatabase.enable.from.checkpoint.failed",
1679:                            new Object[] { name, backendName, e });
1680:                    logger.warn(msg, e);
1681:                    throw new VirtualDatabaseException(msg, e);
1682:                } finally {
1683:                    removeAdminOperation(enableOperation);
1684:                }
1685:            }
1686:
1687:            /**
1688:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#enableBackendFromCheckpoint(java.lang.String)
1689:             */
1690:            public void enableBackendFromCheckpoint(String backendName)
1691:                    throws VirtualDatabaseException {
1692:                enableBackendSanityChecks();
1693:
1694:                DatabaseBackend backend = getAndCheckBackend(backendName,
1695:                        NO_CHECK_BACKEND);
1696:                String checkpoint = backend.getLastKnownCheckpoint();
1697:                if ((checkpoint == null) || ("".equals(checkpoint)))
1698:                    throw new VirtualDatabaseException(
1699:                            "Cannot enable backend "
1700:                                    + backendName
1701:                                    + " from a known state. Resynchronize this backend by restoring a dump.");
1702:                else {
1703:                    if (logger.isDebugEnabled())
1704:                        logger.debug("Enabling backend " + backendName
1705:                                + " from its last checkpoint "
1706:                                + backend.getLastKnownCheckpoint());
1707:                }
1708:                enableBackendFromCheckpoint(backendName, backend
1709:                        .getLastKnownCheckpoint());
1710:            }
1711:
1712:            /**
1713:             * Enable all the backends without any check.
1714:             *
1715:             * @throws VirtualDatabaseException if fails
1716:             */
1717:            public void enableAllBackends() throws VirtualDatabaseException {
1718:                enableBackendSanityChecks();
1719:
1720:                try {
1721:                    int size = this .backends.size();
1722:                    DatabaseBackend dbe;
1723:                    for (int i = 0; i < size; i++) {
1724:                        dbe = (DatabaseBackend) backends.get(i);
1725:                        if (!dbe.isReadEnabled())
1726:                            forceEnableBackend(((DatabaseBackend) backends
1727:                                    .get(i)).getName());
1728:                    }
1729:                } catch (RuntimeException e) {
1730:                    logger.error("Runtime error in enableAllBackends", e);
1731:                    throw new VirtualDatabaseException(e.getMessage(), e);
1732:                }
1733:            }
1734:
1735:            /**
1736:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#enableAllBackendsFromCheckpoint()
1737:             */
1738:            public void enableAllBackendsFromCheckpoint()
1739:                    throws VirtualDatabaseException {
1740:                RecoveryLog log = requestManager.getRecoveryLog();
1741:                if (log == null) {// If no recovery log is defined ignore fallback to a forced enable
1742:                    logger
1743:                            .warn("No recovery log has been configured, enabling backend without checkpoint.");
1744:                    enableAllBackends();
1745:                } else {
1746:                    enableBackendSanityChecks();
1747:
1748:                    try {
1749:                        int size = this .backends.size();
1750:                        DatabaseBackend dbe;
1751:                        String backendName;
1752:                        BackendRecoveryInfo info;
1753:                        for (int i = 0; i < size; i++) {
1754:                            dbe = (DatabaseBackend) backends.get(i);
1755:                            backendName = dbe.getName();
1756:                            info = log
1757:                                    .getBackendRecoveryInfo(name, backendName);
1758:                            switch (info.getBackendState()) {
1759:                            case BackendState.DISABLED:
1760:                                String checkpoint = info.getCheckpoint();
1761:                                if (checkpoint == null || checkpoint.equals("")) {
1762:                                    logger
1763:                                            .warn("Cannot enable backend "
1764:                                                    + backendName
1765:                                                    + " from a known state. Resynchronize this backend by restoring a dump.");
1766:                                } else {
1767:                                    logger.info("Enabling backend "
1768:                                            + backendName + " from checkpoint "
1769:                                            + checkpoint);
1770:                                    enableBackendFromCheckpoint(dbe.getName(),
1771:                                            checkpoint);
1772:                                }
1773:                                continue;
1774:                            case BackendState.UNKNOWN:
1775:                                logger.info("Unknown last state for backend "
1776:                                        + backendName
1777:                                        + ". Leaving node in "
1778:                                        + (dbe.isReadEnabled() ? "enabled"
1779:                                                : "disabled") + " state.");
1780:                                continue;
1781:                            case BackendState.BACKUPING:
1782:                            case BackendState.DISABLING:
1783:                            case BackendState.RESTORING:
1784:                            case BackendState.REPLAYING:
1785:                                if (!dbe.isReadEnabled()) {
1786:                                    logger
1787:                                            .info("Unexpected transition state ("
1788:                                                    + info.getBackendState()
1789:                                                    + ") for backend "
1790:                                                    + backendName
1791:                                                    + ". Forcing backend to disabled state.");
1792:                                    info.setBackendState(BackendState.DISABLED);
1793:                                    log.storeBackendRecoveryInfo(name, info);
1794:                                } else
1795:                                    logger
1796:                                            .info("Unexpected transition state ("
1797:                                                    + info.getBackendState()
1798:                                                    + ") for backend "
1799:                                                    + backendName
1800:                                                    + ". Leaving backend in its current state.");
1801:                                continue;
1802:                            default:
1803:                                if (!dbe.isReadEnabled()) {
1804:                                    logger
1805:                                            .info("Unexpected enabled state ("
1806:                                                    + info.getBackendState()
1807:                                                    + ") for backend "
1808:                                                    + backendName
1809:                                                    + ". Forcing backend to disabled state.");
1810:                                    info.setBackendState(BackendState.DISABLED);
1811:                                    log.storeBackendRecoveryInfo(name, info);
1812:                                } else
1813:                                    logger
1814:                                            .info("Unexpected enabled state ("
1815:                                                    + info.getBackendState()
1816:                                                    + ") for backend "
1817:                                                    + backendName
1818:                                                    + ". Leaving backend in its current state.");
1819:                                continue;
1820:                            }
1821:                        }
1822:                    } catch (Exception e) {
1823:                        throw new VirtualDatabaseException(e.getMessage(), e);
1824:                    }
1825:                }
1826:            }
1827:
1828:            /**
1829:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#forceEnableBackend(String)
1830:             */
1831:            public void forceEnableBackend(String backendName)
1832:                    throws VirtualDatabaseException {
1833:                enableBackendSanityChecks();
1834:
1835:                EnableBackendOperation enableOperation = new EnableBackendOperation(
1836:                        backendName + " (force)");
1837:                addAdminOperation(enableOperation);
1838:
1839:                // Call the Request Manager
1840:                try {
1841:                    DatabaseBackend backend = getAndCheckBackend(backendName,
1842:                            CHECK_BACKEND_ENABLE);
1843:
1844:                    requestManager.enableBackend(backend);
1845:                    requestManager.setSchemaIsDirty(true);
1846:
1847:                    // Update the list of database product names
1848:                    if (databaseProductNames.indexOf(backend
1849:                            .getDatabaseProductName()) == -1)
1850:                        databaseProductNames += ","
1851:                                + backend.getDatabaseProductName();
1852:
1853:                    // Update the static metadata
1854:                    getStaticMetaData().gatherStaticMetadata(backend);
1855:
1856:                    sendJmxNotification(
1857:                            SequoiaNotificationList.VIRTUALDATABASE_BACKEND_ENABLED,
1858:                            Translate.get("notification.backend.enabled"));
1859:                } catch (Exception e) {
1860:                    throw new VirtualDatabaseException(e.getMessage(), e);
1861:                } finally {
1862:                    removeAdminOperation(enableOperation);
1863:                }
1864:            }
1865:
1866:            /**
1867:             * Prepare this virtual database for startup. This turns on all the backends
1868:             * from the given checkpoint. If the checkpoint is null or an empty String,
1869:             * the backends are enabled without further check else the backend states are
1870:             * overriden to use the provided checkpoint.
1871:             *
1872:             * @param checkpoint checkpoint for recovery log
1873:             * @throws VirtualDatabaseException if fails
1874:             */
1875:            public void forceEnableAllBackendsFromCheckpoint(String checkpoint)
1876:                    throws VirtualDatabaseException {
1877:                enableBackendSanityChecks();
1878:
1879:                if (checkpoint == null || checkpoint.equals(""))
1880:                    enableAllBackends();
1881:                else {
1882:                    try {
1883:                        int size = this .backends.size();
1884:                        DatabaseBackend backend;
1885:                        for (int i = 0; i < size; i++) {
1886:                            backend = (DatabaseBackend) backends.get(i);
1887:                            if (!backend.isReadEnabled()) {
1888:                                backend.setLastKnownCheckpoint(checkpoint);
1889:                                enableBackendFromCheckpoint(backend.getName(),
1890:                                        checkpoint);
1891:                            }
1892:                        }
1893:                    } catch (RuntimeException e) {
1894:                        logger
1895:                                .error(
1896:                                        "Runtime error in forceEnableAllBackendsFromCheckpoint",
1897:                                        e);
1898:                        throw new VirtualDatabaseException(e.getMessage(), e);
1899:                    }
1900:                }
1901:            }
1902:
1903:            /**
1904:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getAllBackendNames()
1905:             */
1906:            public ArrayList getAllBackendNames()
1907:                    throws VirtualDatabaseException {
1908:                try {
1909:                    acquireReadLockBackendLists();
1910:                } catch (InterruptedException e) {
1911:                    String msg = "Unable to acquire read lock on backend list in getAllBackendNames ("
1912:                            + e + ")";
1913:                    logger.error(msg);
1914:                    throw new VirtualDatabaseException(msg);
1915:                }
1916:
1917:                int size = backends.size();
1918:                ArrayList result = new ArrayList();
1919:                for (int i = 0; i < size; i++) {
1920:                    result.add(((DatabaseBackend) backends.get(i)).getName());
1921:                }
1922:
1923:                releaseReadLockBackendLists();
1924:                return result;
1925:            }
1926:
1927:            /**
1928:             * Find the DatabaseBackend corresponding to the given backend name and check
1929:             * if it is possible to disable this backend. In the case enable, this method
1930:             * also updates the virtual database schema by merging it with the one
1931:             * provided by this backend.
1932:             *
1933:             * @param backendName backend to look for
1934:             * @param testEnable NO_CHECK_BACKEND no check is done, CHECK_BACKEND_DISABLE
1935:             *          check if it is possible to disable the backend,
1936:             *          CHECK_BACKEND_ENABLE check if it is possible to enable the backend
1937:             * @return the backend to disable
1938:             * @throws VirtualDatabaseException if an error occurs
1939:             */
1940:            public DatabaseBackend getAndCheckBackend(String backendName,
1941:                    int testEnable) throws VirtualDatabaseException {
1942:                try {
1943:                    acquireReadLockBackendLists();
1944:                } catch (InterruptedException e) {
1945:                    String msg = "Unable to acquire read lock on backend list in getAndCheckBackend ("
1946:                            + e + ")";
1947:                    logger.error(msg);
1948:                    throw new VirtualDatabaseException(msg);
1949:                }
1950:
1951:                DatabaseBackend b;
1952:                try {
1953:                    // Find the backend
1954:                    int size = backends.size();
1955:                    b = null;
1956:                    for (int i = 0; i < size; i++) {
1957:                        b = (DatabaseBackend) backends.get(i);
1958:                        if (b.getName().equals(backendName))
1959:                            break;
1960:                        else
1961:                            b = null;
1962:                    }
1963:
1964:                    // Check not null
1965:                    if (b == null) {
1966:                        String msg = "Trying to access a non-existing backend "
1967:                                + backendName;
1968:                        logger.warn(msg);
1969:                        throw new VirtualDatabaseException(msg);
1970:                    }
1971:
1972:                    // Check enable/disable
1973:                    switch (testEnable) {
1974:                    case NO_CHECK_BACKEND:
1975:                        break;
1976:                    case CHECK_BACKEND_DISABLE:
1977:                        if (!b.isReadEnabled()) {
1978:                            String msg = "Backend " + backendName
1979:                                    + " is already disabled";
1980:                            logger.warn(msg);
1981:                            throw new VirtualDatabaseException(msg);
1982:                        }
1983:                        break;
1984:                    case CHECK_BACKEND_ENABLE:
1985:                        if (b.isReadEnabled()) {
1986:                            String msg = "Backend " + backendName
1987:                                    + " is already enabled";
1988:                            logger.warn(msg);
1989:                            throw new VirtualDatabaseException(msg);
1990:                        }
1991:                        break;
1992:                    default:
1993:                        String msg = "Unexpected parameter in getAndCheckBackend(...)";
1994:                        logger.error(msg);
1995:                        throw new VirtualDatabaseException(msg);
1996:                    }
1997:                } finally {
1998:                    releaseReadLockBackendLists();
1999:                }
2000:
2001:                if (testEnable == CHECK_BACKEND_ENABLE) {
2002:                    // Initialize backend for enable
2003:                    try {
2004:                        if (logger.isDebugEnabled())
2005:                            logger
2006:                                    .debug("Initializing connections for backend "
2007:                                            + b.getName());
2008:                        b.initializeConnections();
2009:
2010:                        b.checkDriverCompliance();
2011:
2012:                        if (logger.isDebugEnabled())
2013:                            logger.debug("Checking schema for backend "
2014:                                    + b.getName());
2015:                        b.checkDatabaseSchema(null);
2016:
2017:                        DatabaseSchema backendSchema = b.getDatabaseSchema();
2018:
2019:                        if (backendSchema != null)
2020:                            requestManager.mergeDatabaseSchema(backendSchema);
2021:                        else
2022:                            logger.warn("Backend " + b.getName()
2023:                                    + " has no defined schema.");
2024:                    } catch (SQLException e) {
2025:                        String msg = "Error while initalizing database backend "
2026:                                + b.getName() + " (" + e + ")";
2027:                        logger.warn(msg, e);
2028:                        throw new VirtualDatabaseException(msg, e);
2029:                    }
2030:                }
2031:
2032:                return b;
2033:            }
2034:
2035:            /**
2036:             * Returns true if this vdb is resynching. This can only happen for
2037:             * distributed vdbs that have recovery logs.
2038:             *
2039:             * @return true if db is resynching
2040:             */
2041:            protected boolean isResyncing() {
2042:                return false;
2043:            }
2044:
2045:            /**
2046:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#replicateBackend(java.lang.String,
2047:             *      java.lang.String, java.util.Map)
2048:             */
2049:            public void replicateBackend(String backendName,
2050:                    String newBackendName, Map parameters)
2051:                    throws VirtualDatabaseException {
2052:                // Access the backend we want to replicate
2053:                DatabaseBackend backend = getAndCheckBackend(backendName,
2054:                        NO_CHECK_BACKEND);
2055:                DatabaseBackend newBackend = null;
2056:
2057:                // Create a clone of the backend with additionnal parameters
2058:                try {
2059:                    newBackend = backend.copy(newBackendName, parameters);
2060:                } catch (Exception e) {
2061:                    String msg = Translate.get(
2062:                            "virtualdatabase.fail.backend.copy", e);
2063:                    logger.warn(msg, e);
2064:                    throw new VirtualDatabaseException(msg, e);
2065:                }
2066:
2067:                // Add the backend to the virtual database.
2068:                addBackend(newBackend);
2069:            }
2070:
2071:            /**
2072:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#removeBackend(java.lang.String)
2073:             */
2074:            public void removeBackend(String backend)
2075:                    throws VirtualDatabaseException {
2076:                removeBackend(getAndCheckBackend(backend, NO_CHECK_BACKEND));
2077:            }
2078:
2079:            /**
2080:             * Remove a backend from this virtual database.
2081:             *
2082:             * @param db the database backend to remove
2083:             * @throws VirtualDatabaseException if an error occurs
2084:             */
2085:            public void removeBackend(DatabaseBackend db)
2086:                    throws VirtualDatabaseException {
2087:                if (db == null) {
2088:                    String msg = "Illegal null database backend in removeBackend(DatabaseBackend) method";
2089:                    logger.error(msg);
2090:                    throw new VirtualDatabaseException(msg);
2091:                }
2092:
2093:                try {
2094:                    rwLock.acquireWrite();
2095:                } catch (InterruptedException e) {
2096:                    String msg = Translate
2097:                            .get(
2098:                                    "loadbalancer.backendlist.acquire.writelock.failed",
2099:                                    e);
2100:                    logger.error(msg);
2101:                    throw new VirtualDatabaseException(msg);
2102:                }
2103:
2104:                // Sanity checks
2105:                int idx = backends.indexOf(db);
2106:                if (idx == -1) {
2107:                    rwLock.releaseWrite(); // Release the lock
2108:                    String msg = "Trying to remove a non-existing backend "
2109:                            + db.getName();
2110:                    logger.warn(msg);
2111:                    throw new VirtualDatabaseException(msg);
2112:                }
2113:
2114:                if (((DatabaseBackend) backends.get(idx)).isReadEnabled()) {
2115:                    rwLock.releaseWrite(); // Release the lock
2116:                    String msg = "Trying to remove an enabled backend "
2117:                            + db.getName();
2118:                    logger.error(msg);
2119:                    throw new VirtualDatabaseException(msg);
2120:                }
2121:
2122:                // Remove it
2123:                backends.remove(idx);
2124:                rwLock.releaseWrite(); // Relase the lock
2125:
2126:                sendJmxNotification(
2127:                        SequoiaNotificationList.VIRTUALDATABASE_BACKEND_REMOVED,
2128:                        Translate.get("notification.backend.removed"));
2129:
2130:                // Remove backend mbean to jmx server
2131:                if (MBeanServerManager.isJmxEnabled()) {
2132:                    try {
2133:                        ObjectName objectName = JmxConstants
2134:                                .getDatabaseBackendObjectName(name, db
2135:                                        .getName());
2136:                        MBeanServerManager.unregister(objectName);
2137:                    } catch (Exception e) {
2138:                        logger
2139:                                .error(
2140:                                        Translate
2141:                                                .get(
2142:                                                        "virtualdatabase.fail.unregister.backend.mbean",
2143:                                                        db.getName()), e);
2144:                    }
2145:                }
2146:
2147:                if (logger.isDebugEnabled())
2148:                    logger.debug("Backend " + db.getName()
2149:                            + " removed successfully");
2150:            }
2151:
2152:            /**
2153:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#transferBackend(java.lang.String,
2154:             *      java.lang.String)
2155:             */
2156:            public void transferBackend(String backend,
2157:                    String controllerDestination)
2158:                    throws VirtualDatabaseException {
2159:                throw new VirtualDatabaseException(
2160:                        "Cannot transfer backend to controller:"
2161:                                + controllerDestination
2162:                                + " because database is not distributed");
2163:            }
2164:
2165:            //
2166:            // Backup & Checkpoint management
2167:            //
2168:
2169:            /**
2170:             * Returns a cluster-wide unique checkpoint name.
2171:             * <p>
2172:             * Unicity is needed since checkpoints are always set cluster-wide.
2173:             *
2174:             * @param event the reason why this checkpoint is being set
2175:             * @return a cluster-wide unique checkpoint name
2176:             */
2177:            public String buildCheckpointName(String event) {
2178:                /*
2179:                 * Checkpoints name are now built such as they can be sorted alphabetically
2180:                 */
2181:                SimpleDateFormat dateFormat = new SimpleDateFormat(
2182:                        "yyyyMMddHHmmssSSSZ");
2183:                return (event + "-" + controller.getControllerName() + "-" + dateFormat
2184:                        .format(new Date(System.currentTimeMillis())));
2185:            }
2186:
2187:            /**
2188:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#backupBackend(String,
2189:             *      String, String, String, String, String, boolean, ArrayList)
2190:             */
2191:            public void backupBackend(String backendName, String login,
2192:                    String password, String dumpName, String backuperName,
2193:                    String path, boolean force, ArrayList tables)
2194:                    throws VirtualDatabaseException {
2195:                // Sanity checks
2196:                if (!isDumpNameAvailable(dumpName)) {
2197:                    throw new VirtualDatabaseException(Translate.get(
2198:                            "virtualdatabase.backup.dumpNameError", dumpName));
2199:                }
2200:                if (!force && (getNumberOfEnabledBackends() == 1)) {
2201:                    throw new VirtualDatabaseException(Translate
2202:                            .get("virtualdatabase.backup.onlyOneBackendLeft"));
2203:                }
2204:
2205:                // Perform the backup
2206:                BackupBackendOperation backupOperation = new BackupBackendOperation(
2207:                        backendName, dumpName);
2208:                try {
2209:                    addAdminOperation(backupOperation);
2210:                    DatabaseBackend db = getAndCheckBackend(backendName,
2211:                            NO_CHECK_BACKEND);
2212:                    requestManager.backupBackend(db, login, password, dumpName,
2213:                            backuperName, path, tables);
2214:                } catch (SQLException sql) {
2215:                    throw new VirtualDatabaseException(sql);
2216:                } finally {
2217:                    removeAdminOperation(backupOperation);
2218:                }
2219:            }
2220:
2221:            protected int getNumberOfEnabledBackends()
2222:                    throws VirtualDatabaseException {
2223:                // This check is not sufficient. Disable functionality. (see SEQUOIA-556)
2224:                if (true)
2225:                    return -1;
2226:
2227:                try {
2228:                    acquireReadLockBackendLists();
2229:                } catch (InterruptedException e) {
2230:                    String msg = Translate
2231:                            .get("virtualdatabase.fail.read.lock");
2232:                    logger.error(msg, e);
2233:                    throw new VirtualDatabaseException(msg, e);
2234:                }
2235:
2236:                int nbActive = 0;
2237:                DatabaseBackend b;
2238:                int size = backends.size();
2239:                b = null;
2240:                for (int i = 0; i < size; i++) {
2241:                    b = (DatabaseBackend) backends.get(i);
2242:                    if (b.isReadEnabled() || b.isWriteEnabled())
2243:                        // test symetrical to RequestManager.backupBackend()
2244:                        nbActive++;
2245:                }
2246:
2247:                releaseReadLockBackendLists();
2248:
2249:                return nbActive;
2250:            }
2251:
2252:            /**
2253:             * Checks if the dump name is available. If the <code>dumpName</code> is
2254:             * already taken by an existing dump, return <code>false</code>; else
2255:             * return <code>true</code>
2256:             *
2257:             * @param tentativeDumpName tentative dump name we want to check availability
2258:             * @return <code>true</code> is the name is available, <code>false</code>
2259:             *         else.
2260:             */
2261:            public boolean isDumpNameAvailable(String tentativeDumpName) {
2262:                DumpInfo[] dumps;
2263:                try {
2264:                    dumps = getAvailableDumps();
2265:                } catch (VirtualDatabaseException e) {
2266:                    return true;
2267:                }
2268:                for (int i = 0; i < dumps.length; i++) {
2269:                    DumpInfo dump = dumps[i];
2270:                    if (dump.getDumpName().equals(tentativeDumpName)) {
2271:                        return false;
2272:                    }
2273:                }
2274:                return true;
2275:            }
2276:
2277:            /**
2278:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#copyDump(java.lang.String,
2279:             *      java.lang.String)
2280:             */
2281:            public void copyDump(String dumpName, String remoteControllerName)
2282:                    throws VirtualDatabaseException {
2283:                if (!isDistributed())
2284:                    throw new VirtualDatabaseException(
2285:                            "can not copy dumps on non-distributed virtual database");
2286:            }
2287:
2288:            /**
2289:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#copyLogFromCheckpoint(java.lang.String,
2290:             *      java.lang.String)
2291:             */
2292:            public void copyLogFromCheckpoint(String dumpName,
2293:                    String controllerName) throws VirtualDatabaseException {
2294:                if (!hasRecoveryLog())
2295:                    throw new VirtualDatabaseException(Translate
2296:                            .get("virtualdatabase.no.recovery.log"));
2297:                if (!isDistributed())
2298:                    throw new VirtualDatabaseException(Translate
2299:                            .get("virtualdatabase.not.distributed"));
2300:
2301:                /**
2302:                 * Implemented in the distributed incarnation of the vdb.
2303:                 *
2304:                 * @see org.continuent.sequoia.controller.virtualdatabase.DistributedVirtualDatabase#copyLogFromCheckpoint(String,
2305:                 *      String)
2306:                 */
2307:            }
2308:
2309:            /**
2310:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#deleteLogUpToCheckpoint(java.lang.String)
2311:             */
2312:            public void deleteLogUpToCheckpoint(String checkpointName)
2313:                    throws VirtualDatabaseException {
2314:                if (!hasRecoveryLog())
2315:                    throw new VirtualDatabaseException(Translate
2316:                            .get("virtualdatabase.no.recovery.log"));
2317:
2318:                try {
2319:                    getRequestManager().getRecoveryLog()
2320:                            .deleteLogEntriesBeforeCheckpoint(checkpointName);
2321:                } catch (SQLException e) {
2322:                    throw new VirtualDatabaseException(e);
2323:                }
2324:            }
2325:
2326:            /**
2327:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getBackuperNames()
2328:             */
2329:            public String[] getBackuperNames() {
2330:                return requestManager.getBackupManager().getBackuperNames();
2331:            }
2332:
2333:            /**
2334:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getAvailableDumps()
2335:             */
2336:            public DumpInfo[] getAvailableDumps()
2337:                    throws VirtualDatabaseException {
2338:                try {
2339:                    RecoveryLog recoveryLog = requestManager.getRecoveryLog();
2340:                    if (recoveryLog == null) {
2341:                        return new DumpInfo[0];
2342:                    } else {
2343:                        ArrayList dumps = recoveryLog.getDumpList();
2344:                        return (DumpInfo[]) dumps.toArray(new DumpInfo[dumps
2345:                                .size()]);
2346:                    }
2347:                } catch (SQLException e) {
2348:                    throw new VirtualDatabaseException(e);
2349:                }
2350:            }
2351:
2352:            /**
2353:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getDumpFormatForBackuper(java.lang.String)
2354:             */
2355:            public String getDumpFormatForBackuper(String backuperName) {
2356:                Backuper backuper = requestManager.getBackupManager()
2357:                        .getBackuperByName(backuperName);
2358:                if (backuper == null) {
2359:                    return null;
2360:                }
2361:                return backuper.getDumpFormat();
2362:            }
2363:
2364:            /**
2365:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#initializeFromBackend(java.lang.String,
2366:             *      boolean)
2367:             */
2368:            public void initializeFromBackend(String databaseBackendName,
2369:                    boolean force) throws VirtualDatabaseException {
2370:                RecoveryLog log = requestManager.getRecoveryLog();
2371:                if (log == null)
2372:                    throw new VirtualDatabaseException(Translate
2373:                            .get("virtualdatabase.no.recovery.log"));
2374:
2375:                try {
2376:                    // Check that all backends are in a disabled state without any last known
2377:                    // checkpoint
2378:                    int size = this .backends.size();
2379:                    DatabaseBackend backendToInitializeFrom = null;
2380:                    for (int i = 0; i < size; i++) {
2381:                        DatabaseBackend dbe = (DatabaseBackend) backends.get(i);
2382:                        String backendName = dbe.getName();
2383:                        if (backendName.equals(databaseBackendName)) {
2384:                            backendToInitializeFrom = dbe;
2385:                        }
2386:                        if (force)
2387:                            continue;
2388:                        BackendRecoveryInfo info = log.getBackendRecoveryInfo(
2389:                                name, backendName);
2390:                        if ((info.getBackendState() != BackendState.DISABLED)
2391:                                && (info.getBackendState() != BackendState.UNKNOWN))
2392:                            throw new VirtualDatabaseException(
2393:                                    "Backend "
2394:                                            + backendName
2395:                                            + " is not in a disabled state (current state is "
2396:                                            + BackendState.description(info
2397:                                                    .getBackendState()) + ")");
2398:                        String checkpoint = info.getCheckpoint();
2399:                        if ((checkpoint != null) && !checkpoint.equals(""))
2400:                            throw new VirtualDatabaseException("Backend "
2401:                                    + backendName
2402:                                    + " has a last known checkpoint ("
2403:                                    + checkpoint + ")");
2404:                    }
2405:                    if (backendToInitializeFrom == null) {
2406:                        throw new VirtualDatabaseException("backend "
2407:                                + databaseBackendName + " does not exist");
2408:                    }
2409:                    // Ok, the backends are in a clean state, clean the recovery log
2410:                    log.resetRecoveryLog(true);
2411:                    // set the last known checkpoint to Initial_empty_recovery_log
2412:                    BackendRecoveryInfo info = log.getBackendRecoveryInfo(name,
2413:                            databaseBackendName);
2414:                    backendToInitializeFrom
2415:                            .setLastKnownCheckpoint("Initial_empty_recovery_log");
2416:                    backendToInitializeFrom.setState(BackendState.DISABLED);
2417:                    info.setCheckpoint("Initial_empty_recovery_log");
2418:                    info.setBackendState(BackendState.DISABLED);
2419:                    log.storeBackendRecoveryInfo(name, info);
2420:                } catch (SQLException e) {
2421:                    throw new VirtualDatabaseException(e.getMessage());
2422:                }
2423:            }
2424:
2425:            /**
2426:             * Remove a checkpoint from the recovery log of this virtual database
2427:             *
2428:             * @param checkpointName to remove
2429:             * @throws VirtualDatabaseException if an error occurs
2430:             */
2431:            public void removeCheckpoint(String checkpointName)
2432:                    throws VirtualDatabaseException {
2433:                try {
2434:                    requestManager.removeCheckpoint(checkpointName);
2435:                } catch (Exception e) {
2436:                    throw new VirtualDatabaseException(e.getMessage());
2437:                }
2438:            }
2439:
2440:            /**
2441:             * Delete the dump entry associated to the <code>dumpName</code>.<br />
2442:             * If <code>keepsFile</code> is false, the dump file is also removed from
2443:             * the file system.
2444:             *
2445:             * @param dumpName name of the dump entry to remove
2446:             * @param keepsFile <code>true</code> if the dump should be also removed
2447:             *          from the file system, <code>false</code> else
2448:             * @throws VirtualDatabaseException if an exception occured while removing the
2449:             *           dump entry or the dump file
2450:             */
2451:            public void deleteDump(String dumpName, boolean keepsFile)
2452:                    throws VirtualDatabaseException {
2453:                if (dumpName == null) {
2454:                    throw new VirtualDatabaseException(
2455:                            "dump name can not be null");
2456:                }
2457:                RecoveryLog recoveryLog = requestManager.getRecoveryLog();
2458:                if (recoveryLog == null) {
2459:                    throw new VirtualDatabaseException(
2460:                            "no recovery log for the virtual database"
2461:                                    + getVirtualDatabaseName());
2462:                }
2463:                DumpInfo dumpInfo;
2464:                try {
2465:                    dumpInfo = recoveryLog.getDumpInfo(dumpName);
2466:                } catch (SQLException e) {
2467:                    throw new VirtualDatabaseException(e);
2468:                }
2469:                if (dumpInfo == null) {
2470:                    throw new VirtualDatabaseException(
2471:                            "Dump of name "
2472:                                    + dumpName
2473:                                    + " not found in the recovery log of virtual database "
2474:                                    + getVirtualDatabaseName());
2475:                }
2476:                Backuper backuper = requestManager.getBackupManager()
2477:                        .getBackuperByFormat(dumpInfo.getDumpFormat());
2478:                if (backuper == null) {
2479:                    throw new VirtualDatabaseException(
2480:                            "No backuper found for format "
2481:                                    + dumpInfo.getDumpFormat()
2482:                                    + " for the virtual database "
2483:                                    + getVirtualDatabaseName());
2484:                }
2485:                try {
2486:                    recoveryLog.removeDump(dumpInfo);
2487:                } catch (SQLException e) {
2488:                    throw new VirtualDatabaseException(e);
2489:                }
2490:                if (!keepsFile) {
2491:                    try {
2492:                        backuper.deleteDump(dumpInfo.getDumpPath(), dumpInfo
2493:                                .getDumpName());
2494:                    } catch (BackupException e) {
2495:                        throw new VirtualDatabaseException(e);
2496:                    }
2497:                }
2498:            }
2499:
2500:            /**
2501:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#restoreDumpOnBackend(String,
2502:             *      String, String, String, ArrayList)
2503:             */
2504:            public void restoreDumpOnBackend(String databaseBackendName,
2505:                    String login, String password, String dumpName,
2506:                    ArrayList tables) throws VirtualDatabaseException {
2507:                DatabaseBackend backend = getAndCheckBackend(
2508:                        databaseBackendName, NO_CHECK_BACKEND);
2509:                // Backend cannot be null, otherwise the above throws a
2510:                // VirtualDatabaseException
2511:
2512:                RestoreDumpOperation restoreOperation = new RestoreDumpOperation(
2513:                        databaseBackendName, dumpName);
2514:                try {
2515:                    addAdminOperation(restoreOperation);
2516:                    requestManager.restoreBackendFromBackupCheckpoint(backend,
2517:                            login, password, dumpName, tables);
2518:                } catch (BackupException e) {
2519:                    throw new VirtualDatabaseException(e);
2520:                } finally {
2521:                    removeAdminOperation(restoreOperation);
2522:                }
2523:            }
2524:
2525:            /**
2526:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#setBackendLastKnownCheckpoint
2527:             */
2528:            public void setBackendLastKnownCheckpoint(String backendName,
2529:                    String checkpoint) throws VirtualDatabaseException {
2530:                RecoveryLog log = requestManager.getRecoveryLog();
2531:                DatabaseBackend backend = getAndCheckBackend(backendName,
2532:                        NO_CHECK_BACKEND);
2533:                if (log == null)
2534:                    throw new VirtualDatabaseException(
2535:                            "No recovery log has been defined");
2536:                else {
2537:                    if (!backend.isDisabled())
2538:                        throw new VirtualDatabaseException(
2539:                                "Cannot setLastKnownCheckpoint on a non-disabled backend");
2540:                    else {
2541:                        try {
2542:                            log
2543:                                    .storeBackendRecoveryInfo(this .name,
2544:                                            new BackendRecoveryInfo(backend
2545:                                                    .getName(), checkpoint,
2546:                                                    backend.getStateValue(),
2547:                                                    this .name));
2548:
2549:                            backend.setLastKnownCheckpoint(checkpoint);
2550:                        } catch (SQLException e) {
2551:                            throw new VirtualDatabaseException(
2552:                                    "Failed to store recovery info for backend '"
2553:                                            + backendName + "' (" + e + ")");
2554:                        }
2555:                    }
2556:                }
2557:            }
2558:
2559:            /**
2560:             * Sets a checkpoint indicating that this vdb has shutdown.
2561:             */
2562:            public void setShutdownCheckpoint() {
2563:                RecoveryLog recoveryLog = requestManager.getRecoveryLog();
2564:                if (recoveryLog != null)
2565:                    try {
2566:                        recoveryLog.storeCheckpoint("shutdown"
2567:                                + controller.getControllerName());
2568:                    } catch (SQLException e) {
2569:                        logger.warn("Error while setting shutdown checkpoint",
2570:                                e);
2571:                    }
2572:            }
2573:
2574:            /**
2575:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#transferDump(java.lang.String,
2576:             *      java.lang.String, boolean)
2577:             */
2578:            public void transferDump(String dumpName,
2579:                    String remoteControllerName, boolean noCopy)
2580:                    throws VirtualDatabaseException {
2581:                if (!isDistributed())
2582:                    throw new VirtualDatabaseException(
2583:                            "can not transfer dumps on non-distributed virtual database");
2584:            }
2585:
2586:            /**
2587:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#updateDumpPath(java.lang.String,
2588:             *      java.lang.String)
2589:             */
2590:            public void updateDumpPath(String dumpName, String newPath)
2591:                    throws VirtualDatabaseException {
2592:                try {
2593:                    RecoveryLog recoveryLog = requestManager.getRecoveryLog();
2594:                    if (recoveryLog == null) {
2595:                        throw new VirtualDatabaseException("no recovery log"); // TODO I18N
2596:                    } else {
2597:                        recoveryLog.updateDumpPath(dumpName, newPath);
2598:                    }
2599:                } catch (SQLException e) {
2600:                    throw new VirtualDatabaseException(e);
2601:                }
2602:            }
2603:
2604:            /**
2605:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#viewCheckpointNames()
2606:             */
2607:            public ArrayList viewCheckpointNames() {
2608:                try {
2609:                    RecoveryLog recoveryLog = requestManager.getRecoveryLog();
2610:                    if (recoveryLog == null)
2611:                        return new ArrayList();
2612:                    else
2613:                        return recoveryLog.getCheckpointNames();
2614:                } catch (SQLException e) {
2615:                    return new ArrayList();
2616:                }
2617:            }
2618:
2619:            //
2620:            // Thread management mainly used by controller and monitoring
2621:            //
2622:
2623:            /**
2624:             * Add a VirtualDatabaseWorkerThread to the list of active threads.
2625:             *
2626:             * @param thread the VirtualDatabaseWorkerThread to add
2627:             */
2628:            public void addVirtualDatabaseWorkerThread(
2629:                    VirtualDatabaseWorkerThread thread) {
2630:                synchronized (activeThreads) {
2631:                    activeThreads.add(thread);
2632:                    incrementCurrentNbOfThread();
2633:                }
2634:            }
2635:
2636:            /**
2637:             * Substract one to currentNbOfThreads. Warning! This method is not
2638:             * synchronized.
2639:             */
2640:            protected void decreaseCurrentNbOfThread() {
2641:                currentNbOfThreads--;
2642:            }
2643:
2644:            /**
2645:             * Remove an idle thread. Warning! This method must be called in a
2646:             * synchronized block on activeThreads.
2647:             */
2648:            protected void decreaseIdleThread() {
2649:                idleThreads--;
2650:            }
2651:
2652:            /**
2653:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getCurrentNbOfThreads()
2654:             */
2655:            public int getCurrentNbOfThreads() {
2656:                return currentNbOfThreads;
2657:            }
2658:
2659:            /**
2660:             * Returns the number of idle worker threads. Warning! This method must be
2661:             * called in a synchronized block on activeThreads.
2662:             *
2663:             * @return int number of idle worker threads
2664:             */
2665:            public int getIdleThreads() {
2666:                return idleThreads;
2667:            }
2668:
2669:            /**
2670:             * Returns the maxNbOfThreads.
2671:             *
2672:             * @return int maximum number of threads
2673:             */
2674:            public int getMaxNbOfThreads() {
2675:                return maxNbOfThreads;
2676:            }
2677:
2678:            /**
2679:             * Returns the maxThreadIdleTime.
2680:             *
2681:             * @return long maximum thread idle time in ms
2682:             */
2683:            public long getMaxThreadIdleTime() {
2684:                return maxThreadIdleTime;
2685:            }
2686:
2687:            /**
2688:             * Returns the minNbOfThreads.
2689:             *
2690:             * @return int minimum number of threads
2691:             */
2692:            public int getMinNbOfThreads() {
2693:                return minNbOfThreads;
2694:            }
2695:
2696:            //
2697:            // Thread management mainly used by controller and monitoring
2698:            //
2699:
2700:            /**
2701:             * Return the VirtualDatabaseWorkerThread that is currently executing the
2702:             * transaction identified by the provided id.
2703:             *
2704:             * @param transactionId the transaction id to look for
2705:             * @return the corresponding VirtualDatabaseWorkerThread or null if none is
2706:             *         found
2707:             */
2708:            public VirtualDatabaseWorkerThread getVirtualDatabaseWorkerThreadForTransaction(
2709:                    long transactionId) {
2710:                synchronized (activeThreads) {
2711:                    for (Iterator iter = activeThreads.iterator(); iter
2712:                            .hasNext();) {
2713:                        VirtualDatabaseWorkerThread vdbwt = (VirtualDatabaseWorkerThread) iter
2714:                                .next();
2715:                        if (vdbwt.getCurrentTransactionId() == transactionId)
2716:                            return vdbwt;
2717:                    }
2718:                }
2719:                return null;
2720:            }
2721:
2722:            /**
2723:             * Return the VirtualDatabaseWorkerThread that is currently executing the
2724:             * persistent connection identified by the provided id.
2725:             *
2726:             * @param persistentConnectionId the transaction id to look for
2727:             * @return the corresponding VirtualDatabaseWorkerThread or null if none is
2728:             *         found
2729:             */
2730:            public VirtualDatabaseWorkerThread getVirtualDatabaseWorkerThreadForPersistentConnection(
2731:                    long persistentConnectionId) {
2732:                synchronized (activeThreads) {
2733:                    for (Iterator iter = activeThreads.iterator(); iter
2734:                            .hasNext();) {
2735:                        VirtualDatabaseWorkerThread vdbwt = (VirtualDatabaseWorkerThread) iter
2736:                                .next();
2737:                        if (vdbwt.getPersistentConnectionId() == persistentConnectionId)
2738:                            return vdbwt;
2739:                    }
2740:                }
2741:                return null;
2742:            }
2743:
2744:            /**
2745:             * Adds one to currentNbOfThreads. Warning! This method is not synchronized.
2746:             */
2747:            protected void incrementCurrentNbOfThread() {
2748:                currentNbOfThreads++;
2749:            }
2750:
2751:            /**
2752:             * Method add an idle thread. Warning! This method must be called in a
2753:             * synchronized block on activeThreads.
2754:             */
2755:            protected void incrementIdleThreadCount() {
2756:                idleThreads++;
2757:            }
2758:
2759:            /**
2760:             * Returns the poolConnectionThreads.
2761:             *
2762:             * @return boolean true if threads are pooled
2763:             */
2764:            public boolean isPoolConnectionThreads() {
2765:                return poolConnectionThreads;
2766:            }
2767:
2768:            /**
2769:             * Sets the maxThreadIdleTime.
2770:             *
2771:             * @param maxThreadIdleTime The maxThreadIdleTime to set
2772:             */
2773:            public void setMaxThreadIdleTime(long maxThreadIdleTime) {
2774:                this .maxThreadIdleTime = maxThreadIdleTime;
2775:            }
2776:
2777:            /**
2778:             * Sets the minNbOfThreads.
2779:             *
2780:             * @param minNbOfThreads The minNbOfThreads to set
2781:             */
2782:            public void setMinNbOfThreads(int minNbOfThreads) {
2783:                this .minNbOfThreads = minNbOfThreads;
2784:            }
2785:
2786:            /**
2787:             * Sets the poolConnectionThreads.
2788:             *
2789:             * @param poolConnectionThreads The poolConnectionThreads to set
2790:             */
2791:            public void setPoolConnectionThreads(boolean poolConnectionThreads) {
2792:                this .poolConnectionThreads = poolConnectionThreads;
2793:            }
2794:
2795:            //
2796:            // Getter/Setter and tools (equals, ...)
2797:            //
2798:
2799:            /**
2800:             * Returns the activeThreads list.
2801:             *
2802:             * @return ArrayList of <code>VirtualDatabaseWorkerThread</code>
2803:             */
2804:            public ArrayList getActiveThreads() {
2805:                return activeThreads;
2806:            }
2807:
2808:            /**
2809:             * Returns the authentication manager of this virtual database.
2810:             *
2811:             * @return an <code>AuthenticationManager</code> instance
2812:             */
2813:            public AuthenticationManager getAuthenticationManager() {
2814:                return authenticationManager;
2815:            }
2816:
2817:            /**
2818:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getBackendInformation(String)
2819:             */
2820:            public String getBackendInformation(String backendName)
2821:                    throws VirtualDatabaseException {
2822:                try {
2823:                    acquireReadLockBackendLists();
2824:                } catch (InterruptedException e) {
2825:                    String msg = "Unable to acquire read lock on backend list in getBackendInformation ("
2826:                            + e + ")";
2827:                    logger.error(msg);
2828:                    throw new VirtualDatabaseException(msg);
2829:                }
2830:
2831:                // Find the backend
2832:                int size = backends.size();
2833:                DatabaseBackend b = null;
2834:                for (int i = 0; i < size; i++) {
2835:                    b = (DatabaseBackend) backends.get(i);
2836:                    if (b.getName().equals(backendName))
2837:                        break;
2838:                    else
2839:                        b = null;
2840:                }
2841:
2842:                if (b == null) {
2843:                    releaseReadLockBackendLists();
2844:                    String msg = "Backend " + backendName + " does not exists.";
2845:                    logger.warn(msg);
2846:                    throw new VirtualDatabaseException(msg);
2847:                }
2848:
2849:                releaseReadLockBackendLists();
2850:                return b.getXml();
2851:            }
2852:
2853:            /**
2854:             * Return the list of all backends
2855:             *
2856:             * @return <code>ArrayList</code> of <code>DatabaseBackend</code> Objects
2857:             */
2858:            public ArrayList getBackends() {
2859:                return backends;
2860:            }
2861:
2862:            /**
2863:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getBackendSchema(java.lang.String)
2864:             */
2865:            public String getBackendSchema(String backendName)
2866:                    throws VirtualDatabaseException {
2867:                DatabaseBackend backend = getAndCheckBackend(backendName,
2868:                        NO_CHECK_BACKEND);
2869:                // we know the backend is not null, otherwise we have a
2870:                // VirtualDatabaseException ...
2871:                try {
2872:                    return XmlTools.prettyXml(backend.getSchemaXml(true));
2873:                } catch (Exception e) {
2874:                    throw new VirtualDatabaseException(e.getMessage());
2875:                }
2876:            }
2877:
2878:            /**
2879:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getBackendState(java.lang.String)
2880:             */
2881:            public String getBackendState(String backendName)
2882:                    throws VirtualDatabaseException {
2883:                DatabaseBackend backend = getAndCheckBackend(backendName,
2884:                        NO_CHECK_BACKEND);
2885:                return backend.getState();
2886:            }
2887:
2888:            /**
2889:             * Retrieves the warnings for the given connection on the first available
2890:             * backend
2891:             *
2892:             * @param connId the persistent connection id to retrieve warnings from
2893:             * @exception SQLException if a database access error occurs or this method is
2894:             *              called on a closed connection
2895:             * @return connection SQL warnings or null
2896:             */
2897:            public SQLWarning getConnectionWarnings(long connId)
2898:                    throws SQLException {
2899:                DatabaseBackend b = getFirstAvailableBackend();
2900:                return b.getPersistentConnectionWarnings(connId);
2901:            }
2902:
2903:            /**
2904:             * Forwards call to clearWarnings() to the given persistent connections on
2905:             * each backend.
2906:             *
2907:             * @param connId the persistent connection id to clear warnings from
2908:             * @exception SQLException if a database access error occurs
2909:             */
2910:            public void clearConnectionWarnings(long connId)
2911:                    throws SQLException {
2912:                // Loop round the list in a failfast manner
2913:                if (backends == null)
2914:                    return;
2915:                try {
2916:                    for (Iterator iter = backends.iterator(); iter.hasNext();) {
2917:                        DatabaseBackend b = (DatabaseBackend) iter.next();
2918:                        if (b.isWriteEnabled() && b.isJDBCConnected())
2919:                            b.clearPersistentConnectionWarnings(connId);
2920:                    }
2921:                } catch (ConcurrentModificationException e) {
2922:                    // loop until available
2923:                    clearConnectionWarnings(connId);
2924:                }
2925:            }
2926:
2927:            /**
2928:             * Gets the virtual database name to be used by the client (Sequoia driver)
2929:             * This method should be used for local references only (it is faster). For
2930:             * remote RMI calls, use {@link #getVirtualDatabaseName()}.
2931:             *
2932:             * @return the virtual database name
2933:             * @see VirtualDatabase#getVirtualDatabaseName()
2934:             */
2935:            public String getDatabaseName() {
2936:                return name;
2937:            }
2938:
2939:            /**
2940:             * @see org.continuent.sequoia.driver.DatabaseMetaData#getDatabaseProductName()
2941:             */
2942:            public String getDatabaseProductName() {
2943:                return databaseProductNames;
2944:            }
2945:
2946:            /**
2947:             * @see org.continuent.sequoia.driver.DatabaseMetaData
2948:             * @return associated metada for this database
2949:             */
2950:            public VirtualDatabaseDynamicMetaData getDynamicMetaData() {
2951:                if (metadata == null) {
2952:                    metadata = new VirtualDatabaseDynamicMetaData(this );
2953:                }
2954:                return metadata;
2955:            }
2956:
2957:            /**
2958:             * Get the current database schema from merging the schemas of all active
2959:             * backends.
2960:             *
2961:             * @return the current database schema dynamically gathered
2962:             * @throws SQLException if an error occurs
2963:             */
2964:            public DatabaseSchema getDatabaseSchemaFromActiveBackends()
2965:                    throws SQLException {
2966:                boolean isRaidb1 = requestManager.getLoadBalancer()
2967:                        .getRAIDbLevel() == RAIDbLevels.RAIDb1;
2968:
2969:                try {
2970:                    acquireReadLockBackendLists();
2971:                } catch (InterruptedException e) {
2972:                    String msg = "Unable to acquire read lock on backend list in getDatabaseSchemaFromActiveBackends ("
2973:                            + e + ")";
2974:                    logger.error(msg);
2975:                    throw new SQLException(msg);
2976:                }
2977:
2978:                DatabaseSchema schema = null;
2979:                try {
2980:                    // Build the new schema from all active backend's schemas
2981:                    int size = backends.size();
2982:                    DatabaseBackend b = null;
2983:                    for (int i = 0; i < size; i++) {
2984:                        b = (DatabaseBackend) backends.get(i);
2985:                        if (b.isReadEnabled()) {
2986:                            DatabaseSchema backendSchema = b
2987:                                    .getDatabaseSchema();
2988:                            if (backendSchema != null) { // The backend schema might be null during the recovery phase
2989:                                if (schema == null)
2990:                                    schema = new DatabaseSchema(backendSchema);
2991:                                else
2992:                                    schema.mergeSchema(backendSchema);
2993:
2994:                                // In RAIDb-1 all backends are the same so there is no need to merge
2995:                                // and we just take the schema of the first backend
2996:                                if (isRaidb1)
2997:                                    break;
2998:                            }
2999:                        }
3000:                    }
3001:
3002:                    // Note that if the RecoveryLog points to the same database it will appear
3003:                    // in the database schema but this is a normal behavior.
3004:                } finally {
3005:                    releaseReadLockBackendLists();
3006:                }
3007:
3008:                return schema;
3009:            }
3010:
3011:            /**
3012:             * Get the current database schema from merging the schemas of all active
3013:             * backends. This is needed when a backend is disabled.
3014:             *
3015:             * @return the current database schema dynamically gathered
3016:             * @throws SQLException if an error occurs
3017:             */
3018:            public DatabaseSchema getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames()
3019:                    throws SQLException {
3020:                try {
3021:                    acquireReadLockBackendLists();
3022:                } catch (InterruptedException e) {
3023:                    String msg = "Unable to acquire read lock on backend list in getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames ("
3024:                            + e + ")";
3025:                    logger.error(msg);
3026:                    throw new SQLException(msg);
3027:                }
3028:
3029:                DatabaseSchema schema = null;
3030:                String dbProductNames = "Sequoia";
3031:                try {
3032:                    // Build the new schema from all active backend's schemas
3033:                    int size = backends.size();
3034:                    DatabaseBackend b = null;
3035:                    for (int i = 0; i < size; i++) {
3036:                        b = (DatabaseBackend) backends.get(i);
3037:                        if (b.isReadEnabled()) {
3038:                            DatabaseSchema backendSchema = b
3039:                                    .getDatabaseSchema();
3040:                            if (backendSchema != null) { // The backend schema might be null during the recovery phase
3041:                                if (schema == null)
3042:                                    schema = new DatabaseSchema(backendSchema);
3043:                                else
3044:                                    schema.mergeSchema(backendSchema);
3045:                            }
3046:                        }
3047:
3048:                        // Update the list of database product names
3049:                        if (dbProductNames.indexOf(b.getDatabaseProductName()) == -1)
3050:                            dbProductNames += "," + b.getDatabaseProductName();
3051:                    }
3052:                } finally {
3053:                    releaseReadLockBackendLists();
3054:                }
3055:                databaseProductNames = dbProductNames;
3056:
3057:                // Note that if the RecoveryLog points to the same database it will appear
3058:                // in the database schema but this is a normal behavior.
3059:
3060:                return schema;
3061:            }
3062:
3063:            /**
3064:             * Retrieves the first available backend from this virtual database
3065:             *
3066:             * @return the first available backend or null if no backend enabled is found
3067:             */
3068:            DatabaseBackend getFirstAvailableBackend() {
3069:                // Parse the list in a failfast manner
3070:                if (backends == null)
3071:                    return null;
3072:                try {
3073:                    for (Iterator iter = backends.iterator(); iter.hasNext();) {
3074:                        DatabaseBackend b = (DatabaseBackend) iter.next();
3075:                        if (b.isReadEnabled() && b.isJDBCConnected())
3076:                            return b;
3077:                    }
3078:                } catch (ConcurrentModificationException e) {
3079:                    return getFirstAvailableBackend();
3080:                }
3081:
3082:                return null;
3083:            }
3084:
3085:            /**
3086:             * Returns the logger value.
3087:             *
3088:             * @return Returns the logger.
3089:             */
3090:            public final Trace getLogger() {
3091:                return logger;
3092:            }
3093:
3094:            /**
3095:             * Returns the maxNbOfConnections.
3096:             *
3097:             * @return int
3098:             */
3099:            public int getMaxNbOfConnections() {
3100:                return maxNbOfConnections;
3101:            }
3102:
3103:            /**
3104:             * Returns the number of savepoints that are defined for a given transaction
3105:             * by asking to the request manager.
3106:             *
3107:             * @param tId the transaction id
3108:             * @return the number of savepoints that are defined in the transaction whose
3109:             *         id is tId
3110:             */
3111:            public int getNumberOfSavepointsInTransaction(long tId) {
3112:                return requestManager.getNumberOfSavepointsInTransaction(tId);
3113:            }
3114:
3115:            /**
3116:             * Returns the pendingConnections.
3117:             *
3118:             * @return ArrayList
3119:             */
3120:            public ArrayList getPendingConnections() {
3121:                return pendingConnections;
3122:            }
3123:
3124:            /**
3125:             * Gets the request manager associated to this database.
3126:             *
3127:             * @return a <code>RequestManager</code> instance
3128:             */
3129:            public RequestManager getRequestManager() {
3130:                return requestManager;
3131:            }
3132:
3133:            /**
3134:             * Get the whole static metadata for this virtual database. A new empty
3135:             * metadata object is created if there was none yet. It will be filled later
3136:             * by gatherStaticMetadata() when the backend is enabled.
3137:             *
3138:             * @return Virtual database static metadata
3139:             */
3140:            public VirtualDatabaseStaticMetaData getStaticMetaData() {
3141:                return doGetStaticMetaData();
3142:            }
3143:
3144:            /**
3145:             * @see #getStaticMetaData()
3146:             */
3147:            public VirtualDatabaseStaticMetaData doGetStaticMetaData() {
3148:                if (staticMetadata == null) {
3149:                    staticMetadata = new VirtualDatabaseStaticMetaData(this );
3150:                }
3151:                return staticMetadata;
3152:            }
3153:
3154:            /**
3155:             * Gets the virtual database name to be used by the client (Sequoia driver)
3156:             *
3157:             * @return the virtual database name
3158:             */
3159:            public String getVirtualDatabaseName() {
3160:                return name;
3161:            }
3162:
3163:            /**
3164:             * Returns the current SQL monitor
3165:             *
3166:             * @return a <code>SQLMonitoring</code> instance or null if no monitor is
3167:             *         defined
3168:             */
3169:            public SQLMonitoring getSQLMonitor() {
3170:                return sqlMonitor;
3171:            }
3172:
3173:            /**
3174:             * Return the sql short form length to use when reporting an error.
3175:             *
3176:             * @return sql short form length
3177:             * @see org.continuent.sequoia.controller.requests.AbstractRequest#getSqlShortForm(int)
3178:             */
3179:            public int getSqlShortFormLength() {
3180:                return sqlShortFormLength;
3181:            }
3182:
3183:            /**
3184:             * Returns the totalOrderQueue value.
3185:             *
3186:             * @return Returns the totalOrderQueue.
3187:             */
3188:            public LinkedList getTotalOrderQueue() {
3189:                return totalOrderQueue;
3190:            }
3191:
3192:            /**
3193:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#hasRecoveryLog()
3194:             */
3195:            public boolean hasRecoveryLog() {
3196:                RecoveryLog log = requestManager.getRecoveryLog();
3197:                if (log == null)
3198:                    return false;
3199:                else
3200:                    return true;
3201:            }
3202:
3203:            /**
3204:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#hasResultCache()
3205:             */
3206:            public boolean hasResultCache() {
3207:                AbstractResultCache cache = requestManager.getResultCache();
3208:                if (cache == null)
3209:                    return false;
3210:                else
3211:                    return true;
3212:            }
3213:
3214:            /**
3215:             * Sets the authentication manager for this virtual database.
3216:             *
3217:             * @param authenticationManager the <code>AuthenticationManager</code> to
3218:             *          set
3219:             */
3220:            public void setAuthenticationManager(
3221:                    AuthenticationManager authenticationManager) {
3222:                this .authenticationManager = authenticationManager;
3223:            }
3224:
3225:            /**
3226:             * Sets a new static database schema for this database if no one exist or
3227:             * merge the given schema to the existing one. A static schema can only be
3228:             * replaced by another static schema.
3229:             *
3230:             * @param schema the new database shema
3231:             */
3232:            public void setStaticDatabaseSchema(DatabaseSchema schema) {
3233:                if (requestManager != null)
3234:                    requestManager.setDatabaseSchema(schema, true);
3235:                else
3236:                    logger
3237:                            .warn("Unable to set database schema, no request manager has been defined.");
3238:            }
3239:
3240:            /**
3241:             * Sets the maxNbOfConnections.
3242:             *
3243:             * @param maxNbOfConnections The maxNbOfConnections to set
3244:             */
3245:            public void setMaxNbOfConnections(int maxNbOfConnections) {
3246:                this .maxNbOfConnections = maxNbOfConnections;
3247:            }
3248:
3249:            /**
3250:             * Sets the maxNbOfThreads.
3251:             *
3252:             * @param maxNbOfThreads The maxNbOfThreads to set
3253:             */
3254:            public void setMaxNbOfThreads(int maxNbOfThreads) {
3255:                this .maxNbOfThreads = maxNbOfThreads;
3256:            }
3257:
3258:            /**
3259:             * Sets a new request manager for this database.
3260:             *
3261:             * @param requestManager the new request manager.
3262:             */
3263:            public void setRequestManager(RequestManager requestManager) {
3264:                this .requestManager = requestManager;
3265:            }
3266:
3267:            /**
3268:             * Sets a new SQL Monitor
3269:             *
3270:             * @param sqlMonitor the new SQL monitor
3271:             */
3272:            public void setSQLMonitor(SQLMonitoring sqlMonitor) {
3273:                this .sqlMonitor = sqlMonitor;
3274:            }
3275:
3276:            /**
3277:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#setMonitoringToActive(boolean)
3278:             */
3279:            public void setMonitoringToActive(boolean active)
3280:                    throws VirtualDatabaseException {
3281:                if (sqlMonitor == null)
3282:                    throw new VirtualDatabaseException(Translate
3283:                            .get("virtualdatabase.monitoring.not.defined"));
3284:                else
3285:                    sqlMonitor.setActive(active);
3286:            }
3287:
3288:            /**
3289:             * Returns the useStaticResultSetMetaData value.
3290:             *
3291:             * @return Returns the useStaticResultSetMetaData.
3292:             */
3293:            public final boolean useStaticResultSetMetaData() {
3294:                return useStaticResultSetMetaData;
3295:            }
3296:
3297:            /**
3298:             * Two virtual databases are equal if they have the same name and group.
3299:             *
3300:             * @param other the object to compare with
3301:             * @return <code>true</code> if the two virtual databases are equals
3302:             */
3303:            public boolean equals(Object other) {
3304:                if ((other == null) || (!(other instanceof  VirtualDatabase)))
3305:                    return false;
3306:                else {
3307:                    VirtualDatabase db = (VirtualDatabase) other;
3308:                    return name.equals(db.getDatabaseName());
3309:                }
3310:            }
3311:
3312:            // /////////////////////////////////////////
3313:            // JMX
3314:            // ////////////////////////////////////////
3315:
3316:            /**
3317:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#cleanMonitoringData()
3318:             */
3319:            public void cleanMonitoringData() throws VirtualDatabaseException {
3320:                if (sqlMonitor == null)
3321:                    throw new VirtualDatabaseException(Translate
3322:                            .get("virtualdatabase.monitoring.not.defined"));
3323:                else
3324:                    sqlMonitor.cleanStats();
3325:            }
3326:
3327:            /**
3328:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#retrieveBackendsData()
3329:             */
3330:            public String[][] retrieveBackendsData()
3331:                    throws VirtualDatabaseException {
3332:                try {
3333:                    acquireReadLockBackendLists();
3334:                } catch (InterruptedException e) {
3335:                    String msg = Translate.get(
3336:                            "virtualdatabase.fail.read.lock", e);
3337:                    throw new VirtualDatabaseException(msg);
3338:                }
3339:                ArrayList localBackends = this .getBackends();
3340:                int backendListSize = localBackends.size();
3341:                String[][] data = new String[backendListSize][];
3342:                for (int i = 0; i < backendListSize; i++) {
3343:                    data[i] = ((DatabaseBackend) localBackends.get(i))
3344:                            .getBackendData();
3345:                }
3346:                releaseReadLockBackendLists();
3347:                return data;
3348:            }
3349:
3350:            /**
3351:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#getBackendStatistics(java.lang.String)
3352:             */
3353:            public BackendStatistics getBackendStatistics(String backendName)
3354:                    throws VirtualDatabaseException {
3355:                try {
3356:                    acquireReadLockBackendLists();
3357:                } catch (InterruptedException e) {
3358:                    String msg = Translate.get(
3359:                            "virtualdatabase.fail.read.lock", e);
3360:                    throw new VirtualDatabaseException(msg);
3361:                }
3362:                BackendStatistics stat = null;
3363:                ArrayList backendList = this .getBackends();
3364:                for (Iterator iter = backendList.iterator(); iter.hasNext();) {
3365:                    DatabaseBackend backend = (DatabaseBackend) iter.next();
3366:                    if (backend.getName().equals(backendName)) {
3367:                        stat = backend.getBackendStats();
3368:                    }
3369:                }
3370:                releaseReadLockBackendLists();
3371:                return stat;
3372:            }
3373:
3374:            /**
3375:             * Add an admin operation to the list of current admin operations
3376:             *
3377:             * @param operation the operation to add
3378:             */
3379:            protected void addAdminOperation(AbstractAdminOperation operation) {
3380:                synchronized (currentAdminOperations) {
3381:                    currentAdminOperations.add(operation);
3382:                }
3383:            }
3384:
3385:            /**
3386:             * Remove a currently executing admin operation. Returns true if the command
3387:             * was successfully removed from the list.
3388:             *
3389:             * @param operation the admin operation to remove.
3390:             * @return true if operation was found and removed from the list
3391:             */
3392:            protected boolean removeAdminOperation(
3393:                    AbstractAdminOperation operation) {
3394:                synchronized (currentAdminOperations) {
3395:                    currentAdminOperations.notify();
3396:                    return currentAdminOperations.remove(operation);
3397:                }
3398:            }
3399:
3400:            /**
3401:             * Wait for all current admin operations to complete.
3402:             */
3403:            private void waitForAdminOperationsToComplete() {
3404:                synchronized (currentAdminOperations) {
3405:                    while (!currentAdminOperations.isEmpty()) {
3406:                        for (Iterator iter = currentAdminOperations.iterator(); iter
3407:                                .hasNext();) {
3408:                            AbstractAdminOperation op = (AbstractAdminOperation) iter
3409:                                    .next();
3410:                            logger.info("Waiting for command '" + op
3411:                                    + "' to complete");
3412:                        }
3413:                        try {
3414:                            currentAdminOperations.wait();
3415:                        } catch (InterruptedException ignore) {
3416:                        }
3417:                    }
3418:                }
3419:            }
3420:
3421:            //
3422:            // Shutdown
3423:            //
3424:
3425:            /**
3426:             * Return true if this database is shutting down.
3427:             *
3428:             * @return true if this database is shutting down.
3429:             */
3430:            public boolean isShuttingDown() {
3431:                return shuttingDown;
3432:            }
3433:
3434:            /**
3435:             * Set the VDB shutting down state
3436:             *
3437:             * @param shuttingDown TRUE when vdb is shutting down
3438:             */
3439:            public void setShuttingDown(boolean shuttingDown) {
3440:                this .shuttingDown = shuttingDown;
3441:            }
3442:
3443:            public boolean isRejectingNewTransaction() {
3444:                return refusingNewTransaction;
3445:            }
3446:
3447:            public void setRejectingNewTransaction(
3448:                    boolean canAcceptNewTransaction) {
3449:                this .refusingNewTransaction = canAcceptNewTransaction;
3450:            }
3451:
3452:            /**
3453:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#shutdown(int)
3454:             */
3455:            public void shutdown(int level) {
3456:                VirtualDatabaseShutdownThread vdst = null;
3457:                String msg = Translate.get("virtualdatabase.shutting.down",
3458:                        this .getVirtualDatabaseName());
3459:                synchronized (this ) {
3460:                    if (shuttingDown && !(level == Constants.SHUTDOWN_FORCE))
3461:                        return;
3462:                    switch (level) {
3463:                    case Constants.SHUTDOWN_WAIT:
3464:                        vdst = new VirtualDatabaseWaitShutdownThread(this );
3465:                        msg = Translate.get(
3466:                                "virtualdatabase.shutdown.type.wait", this 
3467:                                        .getVirtualDatabaseName());
3468:                        logger.info(msg);
3469:                        endUserLogger.info(msg);
3470:                        break;
3471:                    case Constants.SHUTDOWN_SAFE:
3472:                        shuttingDown = true;
3473:                        vdst = new VirtualDatabaseSafeShutdownThread(this );
3474:                        msg = Translate.get(
3475:                                "virtualdatabase.shutdown.type.safe", this 
3476:                                        .getVirtualDatabaseName());
3477:                        logger.info(msg);
3478:                        endUserLogger.info(msg);
3479:                        break;
3480:                    case Constants.SHUTDOWN_FORCE:
3481:                        shuttingDown = true;
3482:                        vdst = new VirtualDatabaseForceShutdownThread(this );
3483:                        msg = Translate.get(
3484:                                "virtualdatabase.shutdown.type.force", this 
3485:                                        .getVirtualDatabaseName());
3486:                        logger.warn(msg);
3487:                        endUserLogger.info(msg);
3488:                        break;
3489:                    default:
3490:                        msg = Translate.get(
3491:                                "virtualdatabase.shutdown.unknown.level",
3492:                                new Object[] { new Integer(level),
3493:                                        this .getVirtualDatabaseName() });
3494:                        logger.error(msg);
3495:                        endUserLogger.error(msg);
3496:                        throw new RuntimeException(msg);
3497:                    }
3498:                }
3499:
3500:                if (level != Constants.SHUTDOWN_FORCE) {
3501:                    // Wait for all blocking admin operations to complete
3502:                    waitForAdminOperationsToComplete();
3503:                }
3504:
3505:                Thread thread = new Thread(vdst.getShutdownGroup(), vdst,
3506:                        "VirtualDatabase Shutdown Thread");
3507:                thread.start();
3508:                try {
3509:                    logger.info("Waiting for virtual database " + name
3510:                            + " shutdown");
3511:                    thread.join();
3512:                    controller.removeVirtualDatabase(name);
3513:                    msg = Translate.get(
3514:                            "notification.virtualdatabase.shutdown", name);
3515:                    logger.info(msg);
3516:                    endUserLogger.info(msg);
3517:
3518:                    if (MBeanServerManager.isJmxEnabled()) {
3519:                        try {
3520:                            MBeanServerManager.unregister(JmxConstants
3521:                                    .getVirtualDataBaseObjectName(name));
3522:                            if (MBeanServerManager
3523:                                    .getInstance()
3524:                                    .isRegistered(
3525:                                            JmxConstants
3526:                                                    .getRecoveryLogObjectName(name))) {
3527:                                MBeanServerManager.unregister(JmxConstants
3528:                                        .getRecoveryLogObjectName(name));
3529:                            }
3530:                            MBeanServerManager.unregister(JmxConstants
3531:                                    .getAbstractSchedulerObjectName(name));
3532:                            MBeanServerManager.unregister(JmxConstants
3533:                                    .getLoadBalancerObjectName(name));
3534:                            MBeanServerManager.unregister(JmxConstants
3535:                                    .getRequestManagerObjectName(name));
3536:                            ArrayList backendNames = getAllBackendNames();
3537:                            for (int i = 0; i < backendNames.size(); i++) {
3538:                                String backendName = (String) backendNames
3539:                                        .get(i);
3540:                                MBeanServerManager.unregister(JmxConstants
3541:                                        .getDatabaseBackendObjectName(name,
3542:                                                backendName));
3543:                            }
3544:                        } catch (Exception e) {
3545:                            logger.error(Translate.get(
3546:                                    "virtualdatabase.fail.unregister.mbean",
3547:                                    name), e);
3548:                        }
3549:                    }
3550:                } catch (InterruptedException e) {
3551:                    e.printStackTrace();
3552:                }
3553:            }
3554:
3555:            /**
3556:             * Write the checkpoints for all backends on the recovery log
3557:             */
3558:            public void storeBackendsInfo() {
3559:                requestManager.storeBackendsInfo(this .name, getBackends());
3560:            }
3561:
3562:            /**
3563:             * Get all users connected to that database
3564:             *
3565:             * @return an <code>ArrayList</code> of strings containing the clients
3566:             *         username
3567:             */
3568:            public ArrayList viewAllClientNames() {
3569:                ArrayList list = this .getActiveThreads();
3570:                int size = list.size();
3571:                ArrayList clients = new ArrayList(size);
3572:                for (int i = 0; i < list.size(); i++)
3573:                    clients.add(((VirtualDatabaseWorkerThread) list.get(i))
3574:                            .getUser());
3575:                return clients;
3576:            }
3577:
3578:            /**
3579:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#viewBackendInformation(java.lang.String)
3580:             */
3581:            public String[] viewBackendInformation(String backendName)
3582:                    throws VirtualDatabaseException {
3583:                DatabaseBackend backend = getAndCheckBackend(backendName,
3584:                        NO_CHECK_BACKEND);
3585:                return backend.getBackendData();
3586:            }
3587:
3588:            /**
3589:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#viewControllerList()
3590:             */
3591:            public String[] viewControllerList() {
3592:                return new String[] { viewOwningController() };
3593:            }
3594:
3595:            /**
3596:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#viewGroupBackends()
3597:             */
3598:            public Hashtable viewGroupBackends()
3599:                    throws VirtualDatabaseException {
3600:                Hashtable map = new Hashtable();
3601:                try {
3602:                    acquireReadLockBackendLists();
3603:                } catch (InterruptedException e) {
3604:                    String msg = "Unable to acquire read lock on backend list in getAllBackendNames ("
3605:                            + e + ")";
3606:                    logger.error(msg);
3607:                    throw new VirtualDatabaseException(msg);
3608:                }
3609:
3610:                // Create an ArrayList<BackendInfo> from the backend list
3611:                int size = backends.size();
3612:                ArrayList backendInfos = new ArrayList(size);
3613:                for (int i = 0; i < size; i++)
3614:                    backendInfos.add(new BackendInfo(
3615:                            ((DatabaseBackend) backends.get(i))));
3616:
3617:                releaseReadLockBackendLists();
3618:
3619:                // Return a map with the controller JMX name and its ArrayList<BackendInfo>
3620:                map.put(controller.getJmxName(), backendInfos);
3621:                return map;
3622:            }
3623:
3624:            /**
3625:             * @see org.continuent.sequoia.common.jmx.mbeans.VirtualDatabaseMBean#viewOwningController()
3626:             */
3627:            public String viewOwningController() {
3628:                return controller.getJmxName();
3629:            }
3630:
3631:            /**
3632:             * Retrieves this <code>VirtualDatabase</code> object in xml format
3633:             *
3634:             * @return xml formatted string that conforms to sequoia.dtd
3635:             */
3636:            public String getXml() {
3637:                StringBuffer info = new StringBuffer();
3638:                info.append("<" + DatabasesXmlTags.ELT_VirtualDatabase + " "
3639:                        + DatabasesXmlTags.ATT_name + "=\""
3640:                        + this .getVirtualDatabaseName() + "\" "
3641:                        + DatabasesXmlTags.ATT_maxNbOfConnections + "=\""
3642:                        + this .getMaxNbOfConnections() + "\" "
3643:                        + DatabasesXmlTags.ATT_poolThreads + "=\""
3644:                        + this .isPoolConnectionThreads() + "\" "
3645:                        + DatabasesXmlTags.ATT_minNbOfThreads + "=\""
3646:                        + this .getMinNbOfThreads() + "\" "
3647:                        + DatabasesXmlTags.ATT_maxNbOfThreads + "=\""
3648:                        + this .getMaxNbOfThreads() + "\" "
3649:                        + DatabasesXmlTags.ATT_maxThreadIdleTime + "=\""
3650:                        + this .getMaxThreadIdleTime() / 1000 + "\" "
3651:                        + DatabasesXmlTags.ATT_sqlDumpLength + "=\""
3652:                        + this .sqlShortFormLength + "\">");
3653:
3654:                info.append(getDistributionXml());
3655:
3656:                if (this .getSQLMonitor() != null)
3657:                    info.append(sqlMonitor.getXml());
3658:
3659:                info.append(requestManager.getBackupManager().getXml());
3660:
3661:                if (this .getAuthenticationManager() != null)
3662:                    info.append(authenticationManager.getXml());
3663:
3664:                try {
3665:                    acquireReadLockBackendLists();
3666:                    int size = backends.size();
3667:                    for (int i = 0; i < size; i++)
3668:                        info.append(((DatabaseBackend) backends.get(i))
3669:                                .getXml());
3670:                    releaseReadLockBackendLists();
3671:                } catch (InterruptedException e) {
3672:                    logger.error(Translate.get(
3673:                            "virtualdatabase.fail.read.lock", e));
3674:                }
3675:                if (requestManager != null)
3676:                    info.append(requestManager.getXml());
3677:                info.append("</" + DatabasesXmlTags.ELT_VirtualDatabase + ">");
3678:                return info.toString();
3679:            }
3680:
3681:            /**
3682:             * Get the XML dump of the Distribution element if any.
3683:             *
3684:             * @return ""
3685:             */
3686:            protected String getDistributionXml() {
3687:                return "";
3688:            }
3689:
3690:            /**
3691:             * Indicates if the virtual database requires that tables referenced in a
3692:             * query exist into the schema. This concerns only write queries. If true,
3693:             * queries containing references to tables that do not exist in the database
3694:             * schema will be rejected. Otherwise, queries will be executed against the
3695:             * backends using the conflicting queue. This is done to avoid unwanted
3696:             * cross-database queries to be executed on the cluster.
3697:             *
3698:             * @return enforceTableExistenceIntoSchema that is true if tables have to be
3699:             *         found in the database schema to let a query to be executed against
3700:             *         backends
3701:             */
3702:            public boolean enforceTableExistenceIntoSchema() {
3703:                return enforceTableExistenceIntoSchema;
3704:            }
3705:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.