/** * This file is part of Waarp Project. * * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the * COPYRIGHT.txt in the distribution for a full listing of individual contributors. * * All Waarp Project is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along with Waarp . If not, see * <http://www.gnu.org/licenses/>. */ package org.waarp.openr66.commander; import org.waarp.common.database.DbPreparedStatement; import org.waarp.common.database.data.AbstractDbData; import org.waarp.common.database.data.AbstractDbData.UpdatedInfo; import org.waarp.common.database.exception.WaarpDatabaseException; import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException; import org.waarp.common.database.exception.WaarpDatabaseNoDataException; import org.waarp.common.database.exception.WaarpDatabaseSqlException; import org.waarp.common.logging.WaarpLogger; import org.waarp.common.logging.WaarpLoggerFactory; import org.waarp.openr66.database.DbConstant; import org.waarp.openr66.database.data.DbConfiguration; import org.waarp.openr66.database.data.DbHostAuth; import org.waarp.openr66.database.data.DbHostConfiguration; import org.waarp.openr66.database.data.DbMultipleMonitor; import org.waarp.openr66.database.data.DbRule; import org.waarp.openr66.database.data.DbTaskRunner; import org.waarp.openr66.protocol.configuration.Configuration; import org.waarp.openr66.protocol.utils.R66ShutdownHook; /** * Commander is responsible to read from database updated data from time to time in order to achieve * new runner or new configuration updates. * * @author Frederic Bregier * */ public class Commander implements CommanderInterface { /** * Internal Logger */ private static final WaarpLogger logger = WaarpLoggerFactory .getLogger(Commander.class); private static final int LIMITSUBMIT = 100; private InternalRunner internalRunner = null; private DbPreparedStatement preparedStatementLock = null; private DbPreparedStatement preparedStatementConfig = null; private DbPreparedStatement preparedStatementHostConfig = null; private DbPreparedStatement preparedStatementHost = null; private DbPreparedStatement preparedStatementRule = null; private DbPreparedStatement preparedStatementRunner = null; /** * Prepare requests that will be executed from time to time * * @param runner * @throws WaarpDatabaseNoConnectionException * @throws WaarpDatabaseSqlException */ public Commander(InternalRunner runner) throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException { this.internalConstructor(runner); } /** * Prepare requests that will be executed from time to time * * @param runner * @param fromStartup * True if call from startup of the server * @throws WaarpDatabaseNoConnectionException * @throws WaarpDatabaseSqlException */ public Commander(InternalRunner runner, boolean fromStartup) throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException { this.internalConstructor(runner); if (fromStartup) { // Change RUNNING or INTERRUPTED to TOSUBMIT since they should be ready DbTaskRunner.resetToSubmit(DbConstant.admin.getSession()); } } private void internalConstructor(InternalRunner runner) throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException { try { if (Configuration.configuration.getMultipleMonitors() > 1) { preparedStatementLock = DbMultipleMonitor .getUpdatedPrepareStament(DbConstant.noCommitAdmin.getSession()); } else { preparedStatementLock = null; } preparedStatementConfig = DbConfiguration.getUpdatedPrepareStament(DbConstant.admin.getSession()); preparedStatementHostConfig = DbHostConfiguration.getUpdatedPrepareStament(DbConstant.admin.getSession()); preparedStatementHost = DbHostAuth.getUpdatedPrepareStament(DbConstant.admin.getSession()); preparedStatementRule = DbRule.getUpdatedPrepareStament(DbConstant.admin.getSession()); preparedStatementRunner = DbTaskRunner.getSelectFromInfoPrepareStatement(DbConstant.admin.getSession(), UpdatedInfo.TOSUBMIT, false, LIMITSUBMIT); // Clean tasks (CompleteOK and ALLDONE => DONE) DbTaskRunner.changeFinishedToDone(DbConstant.admin.getSession()); internalRunner = runner; } finally { if (internalRunner == null) { // An error occurs if (preparedStatementLock != null) { preparedStatementLock.realClose(); } if (preparedStatementConfig != null) { preparedStatementConfig.realClose(); } if (preparedStatementHostConfig != null) { preparedStatementHostConfig.realClose(); } if (preparedStatementHost != null) { preparedStatementHost.realClose(); } if (preparedStatementRule != null) { preparedStatementRule.realClose(); } if (preparedStatementRunner != null) { preparedStatementRunner.realClose(); } } else { if (preparedStatementLock != null) { DbConstant.noCommitAdmin.getSession() .addLongTermPreparedStatement(preparedStatementLock); } if (preparedStatementConfig != null) { DbConstant.admin.getSession().addLongTermPreparedStatement(preparedStatementConfig); } if (preparedStatementHostConfig != null) { DbConstant.admin.getSession().addLongTermPreparedStatement(preparedStatementHostConfig); } if (preparedStatementHost != null) { DbConstant.admin.getSession().addLongTermPreparedStatement(preparedStatementHost); } if (preparedStatementRule != null) { DbConstant.admin.getSession().addLongTermPreparedStatement(preparedStatementRule); } if (preparedStatementRunner != null) { DbConstant.admin.getSession().addLongTermPreparedStatement(preparedStatementRunner); } } } } /** * Finalize internal data */ public void finalize() { if (preparedStatementLock != null) { try { DbConstant.noCommitAdmin.getSession().commit(); } catch (WaarpDatabaseSqlException e) { } catch (WaarpDatabaseNoConnectionException e) { } preparedStatementLock.realClose(); DbConstant.noCommitAdmin.getSession() .removeLongTermPreparedStatements(preparedStatementLock); // DbConstant.noCommitAdmin.session.removeLongTermPreparedStatements(); } if (preparedStatementConfig != null) { preparedStatementConfig.realClose(); DbConstant.admin.getSession().removeLongTermPreparedStatements(preparedStatementConfig); } if (preparedStatementHostConfig != null) { preparedStatementHostConfig.realClose(); DbConstant.admin.getSession().removeLongTermPreparedStatements(preparedStatementHostConfig); } if (preparedStatementHost != null) { preparedStatementHost.realClose(); DbConstant.admin.getSession().removeLongTermPreparedStatements(preparedStatementHost); } if (preparedStatementRule != null) { preparedStatementRule.realClose(); DbConstant.admin.getSession().removeLongTermPreparedStatements(preparedStatementRule); } if (preparedStatementRunner != null) { preparedStatementRunner.realClose(); DbConstant.admin.getSession().removeLongTermPreparedStatements(preparedStatementRunner); } // DbConstant.admin.session.removeLongTermPreparedStatements(); } public void run() { Thread.currentThread().setName("OpenR66Commander"); if (DbConstant.admin.getSession() != null && DbConstant.admin.getSession().isDisActive()) { DbConstant.admin.getSession().checkConnectionNoException(); } // each time it is runned, it parses all database for updates DbMultipleMonitor multipleMonitor = null; // Open a lock to prevent other "HA" monitors to retrieve access as Commander try { try { if (preparedStatementLock != null) { preparedStatementLock.executeQuery(); preparedStatementLock.getNext(); multipleMonitor = DbMultipleMonitor.getFromStatement(preparedStatementLock); } } catch (WaarpDatabaseNoConnectionException e) { logger.error("Database No Connection Error: Cannot execute Commander", e); try { DbConstant.noCommitAdmin.getDbModel().validConnection(DbConstant.noCommitAdmin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } return; } catch (WaarpDatabaseSqlException e) { logger.error("Database SQL Error: Cannot execute Commander", e); try { DbConstant.noCommitAdmin.getDbModel().validConnection(DbConstant.noCommitAdmin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } return; } logger.debug("Before " + multipleMonitor); // First check Configuration try { preparedStatementConfig.executeQuery(); while (preparedStatementConfig.getNext()) { // should be only one... DbConfiguration configuration = DbConfiguration .getFromStatement(preparedStatementConfig); if (configuration.isOwnConfiguration()) { configuration.updateConfiguration(); } if (multipleMonitor != null) { // update the configuration in HA mode if (multipleMonitor.checkUpdateConfig()) { configuration.changeUpdatedInfo(AbstractDbData.UpdatedInfo.NOTUPDATED); configuration.update(); logger.debug("Config " + multipleMonitor); } else { configuration.update(); logger.debug("Config " + multipleMonitor); } } else { configuration.changeUpdatedInfo(AbstractDbData.UpdatedInfo.NOTUPDATED); configuration.update(); } configuration = null; } preparedStatementConfig.close(); } catch (WaarpDatabaseNoConnectionException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database No Connection Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseSqlException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database SQL Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database Error: Cannot execute Commander", e); return; } finally { preparedStatementConfig.close(); } // check HostConfiguration try { preparedStatementHostConfig.executeQuery(); while (preparedStatementHostConfig.getNext()) { // should be only one... DbHostConfiguration configuration = DbHostConfiguration .getFromStatement(preparedStatementHostConfig); if (configuration.isOwnConfiguration()) { configuration.updateConfiguration(); } if (multipleMonitor != null) { // update the configuration in HA mode if (multipleMonitor.checkUpdateConfig()) { configuration.changeUpdatedInfo(AbstractDbData.UpdatedInfo.NOTUPDATED); configuration.update(); logger.debug("Config " + multipleMonitor); } else { configuration.update(); logger.debug("Config " + multipleMonitor); } } else { configuration.changeUpdatedInfo(AbstractDbData.UpdatedInfo.NOTUPDATED); configuration.update(); } configuration = null; } preparedStatementHostConfig.close(); } catch (WaarpDatabaseNoConnectionException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database No Connection Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseSqlException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database SQL Error: Cannot execute Commander", e); // XXX no return since table might not be initialized return; } catch (WaarpDatabaseException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database Error: Cannot execute Commander", e); // XXX no return since table might not be initialized return; } finally { preparedStatementHostConfig.close(); } // Check HostAuthent try { preparedStatementHost.executeQuery(); boolean mm = false; boolean lastUpdate = false; while (preparedStatementHost.getNext()) { // Maybe multiple DbHostAuth hostAuth = DbHostAuth.getFromStatement(preparedStatementHost); if (multipleMonitor != null) { if (!mm) { // not already set from a previous hostAuth mm = true; lastUpdate = multipleMonitor.checkUpdateHost(); } // else already set so no action on multipleMonitor // Update the Host configuration in HA mode if (lastUpdate) { hostAuth.changeUpdatedInfo(AbstractDbData.UpdatedInfo.NOTUPDATED); hostAuth.update(); logger.debug("Host " + multipleMonitor); } else { // Nothing to do except validate hostAuth.update(); logger.debug("Host " + multipleMonitor); } } else { // Nothing to do except validate hostAuth.changeUpdatedInfo(AbstractDbData.UpdatedInfo.NOTUPDATED); hostAuth.update(); } hostAuth = null; } } catch (WaarpDatabaseNoConnectionException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database No Connection Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseSqlException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database SQL Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database Error: Cannot execute Commander", e); return; } finally { preparedStatementHost.close(); } // Check Rules try { preparedStatementRule.executeQuery(); boolean mm = false; boolean lastUpdate = false; while (preparedStatementRule.getNext()) { DbRule rule = DbRule.getFromStatement(preparedStatementRule); if (multipleMonitor != null) { if (!mm) { // not already set from a previous hostAuth mm = true; lastUpdate = multipleMonitor.checkUpdateRule(); } // else already set so no action on multipleMonitor // Update the Rules in HA mode if (lastUpdate) { rule.changeUpdatedInfo(AbstractDbData.UpdatedInfo.NOTUPDATED); rule.update(); logger.debug("Rule " + multipleMonitor); } else { // Nothing to do except validate rule.update(); logger.debug("Rule " + multipleMonitor); } } else { // Nothing to do except validate rule.changeUpdatedInfo(AbstractDbData.UpdatedInfo.NOTUPDATED); rule.update(); } rule = null; } } catch (WaarpDatabaseNoConnectionException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database No Connection Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseSqlException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database SQL Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseNoDataException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database Error: Cannot execute Commander", e); return; } finally { preparedStatementRule.close(); } if (R66ShutdownHook.isShutdownStarting()) { // no more task to submit return; } logger.debug("start runner"); // Check TaskRunner try { DbTaskRunner.finishSelectOrCountPrepareStatement(preparedStatementRunner); // No specific HA mode since the other servers will wait for the commit on Lock preparedStatementRunner.executeQuery(); while (preparedStatementRunner.getNext()) { if (R66ShutdownHook.isShutdownStarting()) { // no more task to submit return; } DbTaskRunner taskRunner = null; try { taskRunner = DbTaskRunner .getFromStatement(preparedStatementRunner); } catch (WaarpDatabaseSqlException e) { // ignore and continue if NoData if (e.getCause() instanceof WaarpDatabaseNoDataException) { logger.warn("DbTaskRunner cannot be loaded: " + e.getMessage()); continue; } throw e; } logger.debug("get a task: {}", taskRunner); // Launch if possible this task String key = taskRunner.getRequested() + " " + taskRunner.getRequester() + " " + taskRunner.getSpecialId(); if (Configuration.configuration.getLocalTransaction(). getFromRequest(key) != null) { // already running continue; } if (taskRunner.isSelfRequested()) { // cannot schedule a request where the host is the requested host taskRunner.changeUpdatedInfo(UpdatedInfo.INTERRUPTED); taskRunner.update(); continue; } taskRunner.changeUpdatedInfo(UpdatedInfo.RUNNING); taskRunner.forceSaveStatus(); internalRunner.submitTaskRunner(taskRunner); taskRunner = null; } } catch (WaarpDatabaseNoConnectionException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database No Connection Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseSqlException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database SQL Error: Cannot execute Commander", e); return; } catch (WaarpDatabaseException e) { try { DbConstant.admin.getDbModel().validConnection(DbConstant.admin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } logger.error("Database Error: Cannot execute Commander", e); return; } finally { preparedStatementRunner.close(); } logger.debug("end commander"); } finally { if (multipleMonitor != null) { try { // Now update and Commit so releasing the lock logger.debug("Update " + multipleMonitor); multipleMonitor.update(); DbConstant.noCommitAdmin.getSession().commit(); } catch (WaarpDatabaseException e) { try { DbConstant.noCommitAdmin.getDbModel().validConnection(DbConstant.noCommitAdmin.getSession()); } catch (WaarpDatabaseNoConnectionException e1) { } } multipleMonitor = null; } } } }