Package net.sf.hajdbc.sql

Source Code of net.sf.hajdbc.sql.DatabaseClusterImpl

/*
* HA-JDBC: High-Availability JDBC
* Copyright (C) 2012  Paul Ferraro
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.hajdbc.sql;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.locks.Lock;

import javax.management.JMException;

import net.sf.hajdbc.Database;
import net.sf.hajdbc.DatabaseCluster;
import net.sf.hajdbc.DatabaseClusterConfiguration;
import net.sf.hajdbc.DatabaseClusterConfigurationListener;
import net.sf.hajdbc.DatabaseClusterListener;
import net.sf.hajdbc.Messages;
import net.sf.hajdbc.SynchronizationListener;
import net.sf.hajdbc.SynchronizationStrategy;
import net.sf.hajdbc.TransactionMode;
import net.sf.hajdbc.Version;
import net.sf.hajdbc.balancer.Balancer;
import net.sf.hajdbc.cache.DatabaseMetaDataCache;
import net.sf.hajdbc.codec.Decoder;
import net.sf.hajdbc.dialect.Dialect;
import net.sf.hajdbc.distributed.CommandDispatcherFactory;
import net.sf.hajdbc.durability.Durability;
import net.sf.hajdbc.durability.InvocationEvent;
import net.sf.hajdbc.durability.InvokerEvent;
import net.sf.hajdbc.io.InputSinkStrategy;
import net.sf.hajdbc.lock.LockManager;
import net.sf.hajdbc.lock.distributed.DistributedLockManager;
import net.sf.hajdbc.logging.Level;
import net.sf.hajdbc.logging.Logger;
import net.sf.hajdbc.logging.LoggerFactory;
import net.sf.hajdbc.management.Description;
import net.sf.hajdbc.management.MBean;
import net.sf.hajdbc.management.MBeanRegistrar;
import net.sf.hajdbc.management.ManagedAttribute;
import net.sf.hajdbc.management.ManagedOperation;
import net.sf.hajdbc.state.DatabaseEvent;
import net.sf.hajdbc.state.StateManager;
import net.sf.hajdbc.state.distributed.DistributedStateManager;
import net.sf.hajdbc.sync.SynchronizationContext;
import net.sf.hajdbc.sync.SynchronizationContextImpl;
import net.sf.hajdbc.tx.TransactionIdentifierFactory;
import net.sf.hajdbc.util.Resources;
import net.sf.hajdbc.util.concurrent.cron.CronExpression;
import net.sf.hajdbc.util.concurrent.cron.CronThreadPoolExecutor;

/**
* @author paul
*
*/
@MBean
public class DatabaseClusterImpl<Z, D extends Database<Z>> implements DatabaseCluster<Z, D>
{
  static final Logger logger = LoggerFactory.getLogger(DatabaseClusterImpl.class);
 
  private final String id;
 
  final DatabaseClusterConfiguration<Z, D> configuration;
 
  private Balancer<Z, D> balancer;
  private Dialect dialect;
  private Durability<Z, D> durability;
  private DatabaseMetaDataCache<Z, D> databaseMetaDataCache;
  private ExecutorService executor;
  private Decoder decoder;
  private CronThreadPoolExecutor cronExecutor;
  private LockManager lockManager;
  private StateManager stateManager;
  private InputSinkStrategy<? extends Object> sinkSourceFactory;
 
  private boolean active = false;
 
  private final List<DatabaseClusterConfigurationListener<Z, D>> configurationListeners = new CopyOnWriteArrayList<DatabaseClusterConfigurationListener<Z, D>>()
  private final List<DatabaseClusterListener> clusterListeners = new CopyOnWriteArrayList<DatabaseClusterListener>();
  private final List<SynchronizationListener> synchronizationListeners = new CopyOnWriteArrayList<SynchronizationListener>();
 
  public DatabaseClusterImpl(String id, DatabaseClusterConfiguration<Z, D> configuration, DatabaseClusterConfigurationListener<Z, D> listener)
  {
    this.id = id;
    this.configuration = configuration;
   
    if (listener != null)
    {
      this.configurationListeners.add(listener);
    }
  }

  /**
   * Deactivates the specified database.
   * @param databaseId a database identifier
   * @throws IllegalArgumentException if no database exists with the specified identifier.
   */
  @ManagedOperation
  public void deactivate(String databaseId)
  {
    this.deactivate(this.getDatabase(databaseId), this.stateManager);
  }

  /**
   * Synchronizes, using the default strategy, and reactivates the specified database.
   * @param databaseId a database identifier
   * @throws IllegalArgumentException if no database exists with the specified identifier.
   * @throws IllegalStateException if synchronization fails.
   */
  @ManagedOperation
  public void activate(String databaseId)
  {
    this.activate(databaseId, this.configuration.getDefaultSynchronizationStrategy());
  }

  /**
   * Synchronizes, using the specified strategy, and reactivates the specified database.
   * @param databaseId a database identifier
   * @param strategyId the identifer of a synchronization strategy
   * @throws IllegalArgumentException if no database exists with the specified identifier, or no synchronization strategy exists with the specified identifier.
   * @throws IllegalStateException if synchronization fails.
   */
  @ManagedOperation
  public void activate(String databaseId, String strategyId)
  {
    SynchronizationStrategy strategy = this.configuration.getSynchronizationStrategyMap().get(strategyId);
   
    if (strategy == null)
    {
      throw new IllegalArgumentException(Messages.INVALID_SYNC_STRATEGY.getMessage(strategyId));
    }
   
    try
    {
      if (this.activate(this.getDatabase(databaseId), strategy))
      {
        logger.log(Level.INFO, Messages.DATABASE_ACTIVATED.getMessage(this, databaseId));
      }
    }
    catch (SQLException e)
    {
      logger.log(Level.WARN, e, Messages.DATABASE_ACTIVATE_FAILED.getMessage(this, databaseId));
     
      SQLException exception = e.getNextException();
     
      while (exception != null)
      {
        logger.log(Level.ERROR, exception);
       
        exception = exception.getNextException();
      }

      throw new IllegalStateException(e.toString());
    }
    catch (InterruptedException e)
    {
      logger.log(Level.WARN, e);
     
      Thread.currentThread().interrupt();
    }
  }
 
  /**
   * Determines whether or not the specified database is responsive
   * @param databaseId a database identifier
   * @return true, if the database is alive, false otherwise
   * @throws IllegalArgumentException if no database exists with the specified identifier.
   */
  @ManagedOperation
  public boolean isAlive(String databaseId)
  {
    return this.isAlive(this.getDatabase(databaseId), Level.WARN);
  }
 
  /**
   * Returns a collection of active databases in this cluster.
   * @return a list of database identifiers
   */
  @ManagedAttribute
  public Set<String> getActiveDatabases()
  {
    Set<String> databases = new TreeSet<String>();
   
    for (D database: this.balancer)
    {
      databases.add(database.getId());
    }
   
    return databases;
  }
 
  /**
   * Returns a collection of inactive databases in this cluster.
   * @return a collection of database identifiers
   */
  @ManagedAttribute
  public Set<String> getInactiveDatabases()
  {
    Set<String> databases = new TreeSet<String>(this.configuration.getDatabaseMap().keySet());
   
    for (D database: this.balancer)
    {
      databases.remove(database.getId());
    }
   
    return databases;
  }
 
  /**
   * Return the current HA-JDBC version
   * @return the current version
   */
  @ManagedAttribute
  public String getVersion()
  {
    return Version.CURRENT.toString();
  }

  /**
   * Removes the specified database from the cluster.
   * @param databaseId a database identifier
   * @throws JMException
   * @throws IllegalArgumentException if database already exists.
   */
  @ManagedOperation
  public void add(String databaseId) throws JMException
  {
    D database = this.configuration.getDatabaseFactory().createDatabase(databaseId);
   
    if (this.configuration.getDatabaseMap().putIfAbsent(databaseId, database) != null)
    {
      throw new IllegalArgumentException(Messages.DATABASE_ALREADY_EXISTS.getMessage(databaseId, this));
    }
   
    this.configuration.getMBeanRegistrar().register(this, database);
   
    for (DatabaseClusterConfigurationListener<Z, D> listener: this.configurationListeners)
    {
      listener.added(database, this.configuration);
    }
  }
 
  /**
   * Removes the specified database from the cluster.
   * @param databaseId a database identifier
   * @throws IllegalStateException if database is still active.
   */
  @ManagedOperation
  public void remove(String databaseId)
  {
    D database = this.getDatabase(databaseId);
   
    if (this.balancer.contains(database))
    {
      throw new IllegalStateException(Messages.DATABASE_STILL_ACTIVE.getMessage(this, databaseId));
    }

    this.configuration.getMBeanRegistrar().unregister(this, database);
   
    this.configuration.getDatabaseMap().remove(databaseId);

    for (DatabaseClusterConfigurationListener<Z, D> listener: this.configurationListeners)
    {
      listener.removed(database, this.configuration);
    }
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getId()
   */
  @ManagedAttribute
  @Override
  public String getId()
  {
    return this.id;
  }

  @Override
  public String toString()
  {
    return this.id;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#isActive()
   */
  @ManagedAttribute
  @Override
  public boolean isActive()
  {
    return this.active;
  }
 
  /**
   * Returns the set of synchronization strategies available to this cluster.
   * @return a set of synchronization strategy identifiers
   */
  @ManagedAttribute
  public Set<String> getSynchronizationStrategies()
  {
    return new TreeSet<String>(this.configuration.getSynchronizationStrategyMap().keySet());
  }
 
  /**
   * Returns the default synchronization strategy used by this cluster.
   * @return a synchronization strategy identifier
   */
  @ManagedAttribute
  public String getDefaultSynchronizationStrategy()
  {
    return this.configuration.getDefaultSynchronizationStrategy();
  }

  /**
   * Flushes this cluster's cache of DatabaseMetaData.
   */
  @ManagedOperation
  @Description("Flushes this cluster's cache of database meta data")
  public void flushMetaDataCache()
  {
    try
    {
      this.databaseMetaDataCache.flush();
    }
    catch (SQLException e)
    {
      throw new IllegalStateException(e.toString(), e);
    }
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#addConfigurationListener(net.sf.hajdbc.DatabaseClusterConfigurationListener)
   */
  @ManagedOperation
  @Override
  public void addConfigurationListener(DatabaseClusterConfigurationListener<Z, D> listener)
  {
    this.configurationListeners.add(listener);
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#addListener(net.sf.hajdbc.DatabaseClusterListener)
   */
  @ManagedOperation
  @Override
  public void addListener(DatabaseClusterListener listener)
  {
    this.clusterListeners.add(listener);
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#addSynchronizationListener(net.sf.hajdbc.SynchronizationListener)
   */
  @ManagedOperation
  @Override
  public void addSynchronizationListener(SynchronizationListener listener)
  {
    this.synchronizationListeners.add(listener);
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#removeConfigurationListener(net.sf.hajdbc.DatabaseClusterConfigurationListener)
   */
  @ManagedOperation
  @Override
  public void removeConfigurationListener(DatabaseClusterConfigurationListener<Z, D> listener)
  {
    this.configurationListeners.remove(listener);
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#removeListener(net.sf.hajdbc.DatabaseClusterListener)
   */
  @ManagedOperation
  @Override
  public void removeListener(DatabaseClusterListener listener)
  {
    this.clusterListeners.remove(listener);
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#removeSynchronizationListener(net.sf.hajdbc.SynchronizationListener)
   */
  @ManagedOperation
  @Override
  public void removeSynchronizationListener(SynchronizationListener listener)
  {
    this.synchronizationListeners.remove(listener);
  }
 
  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#activate(net.sf.hajdbc.Database, net.sf.hajdbc.state.StateManager)
   */
  @Override
  public boolean activate(D database, StateManager manager)
  {
    boolean added = this.balancer.add(database);
   
    if (added)
    {
      database.setActive(true);
     
      if (database.isDirty())
      {
        database.clean();
      }
     
      DatabaseEvent event = new DatabaseEvent(database);

      manager.activated(event);
     
      for (DatabaseClusterListener listener: this.clusterListeners)
      {
        listener.activated(event);
      }
    }
   
    return added;
  }
 
  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#deactivate(net.sf.hajdbc.Database, net.sf.hajdbc.state.StateManager)
   */
  @Override
  public boolean deactivate(D database, StateManager manager)
  {
    boolean removed = this.balancer.remove(database);
   
    if (removed)
    {
      database.setActive(false);
     
      DatabaseEvent event = new DatabaseEvent(database);

      manager.deactivated(event);
     
      for (DatabaseClusterListener listener: this.clusterListeners)
      {
        listener.deactivated(event);
      }
    }
   
    return removed;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getBalancer()
   */
  @Override
  public Balancer<Z, D> getBalancer()
  {
    return this.balancer;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getDatabase(java.lang.String)
   */
  @Override
  public D getDatabase(String id)
  {
    D database = this.configuration.getDatabaseMap().get(id);
   
    if (database == null)
    {
      throw new IllegalArgumentException(Messages.INVALID_DATABASE.getMessage(this, id));
    }
   
    return database;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getDatabaseMetaDataCache()
   */
  @Override
  public DatabaseMetaDataCache<Z, D> getDatabaseMetaDataCache()
  {
    return this.databaseMetaDataCache;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getDialect()
   */
  @Override
  public Dialect getDialect()
  {
    return this.dialect;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getDurability()
   */
  @Override
  public Durability<Z, D> getDurability()
  {
    return this.durability;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getLockManager()
   */
  @Override
  public LockManager getLockManager()
  {
    return this.lockManager;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getExecutor()
   */
  @Override
  public ExecutorService getExecutor()
  {
    return this.executor;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getTransactionMode()
   */
  @Override
  public TransactionMode getTransactionMode()
  {
    return this.configuration.getTransactionMode();
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getStateManager()
   */
  @Override
  public StateManager getStateManager()
  {
    return this.stateManager;
  }

  @Override
  public ThreadFactory getThreadFactory()
  {
    return this.configuration.getThreadFactory();
  }

  @Override
  public Decoder getDecoder()
  {
    return this.decoder;
  }

  @Override
  public InputSinkStrategy<? extends Object> getInputSinkStrategy()
  {
    return this.sinkSourceFactory;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#getTransactionIdentifierFactory()
   */
  @Override
  public TransactionIdentifierFactory<? extends Object> getTransactionIdentifierFactory()
  {
    return this.configuration.getTransactionIdentifierFactory();
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#isCurrentDateEvaluationEnabled()
   */
  @Override
  public boolean isCurrentDateEvaluationEnabled()
  {
    return this.configuration.isCurrentDateEvaluationEnabled();
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#isCurrentTimeEvaluationEnabled()
   */
  @Override
  public boolean isCurrentTimeEvaluationEnabled()
  {
    return this.configuration.isCurrentTimeEvaluationEnabled();
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#isCurrentTimestampEvaluationEnabled()
   */
  @Override
  public boolean isCurrentTimestampEvaluationEnabled()
  {
    return this.configuration.isCurrentTimestampEvaluationEnabled();
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#isIdentityColumnDetectionEnabled()
   */
  @Override
  public boolean isIdentityColumnDetectionEnabled()
  {
    return this.configuration.isIdentityColumnDetectionEnabled();
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#isRandEvaluationEnabled()
   */
  @Override
  public boolean isRandEvaluationEnabled()
  {
    return this.configuration.isRandEvaluationEnabled();
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.DatabaseCluster#isSequenceDetectionEnabled()
   */
  @Override
  public boolean isSequenceDetectionEnabled()
  {
    return this.configuration.isSequenceDetectionEnabled();
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.Lifecycle#start()
   */
  @Override
  public synchronized void start() throws Exception
  {
    if (this.active) return;
   
    this.decoder = this.configuration.getDecoderFactory().createDecoder(this.id);
    this.lockManager = this.configuration.getLockManagerFactory().createLockManager();
    this.stateManager = this.configuration.getStateManagerFactory().createStateManager(this);
   
    CommandDispatcherFactory dispatcherFactory = this.configuration.getDispatcherFactory();
   
    if (dispatcherFactory != null)
    {
      this.lockManager = new DistributedLockManager(this, dispatcherFactory);
      this.stateManager = new DistributedStateManager<Z, D>(this, dispatcherFactory);
    }
   
    this.balancer = this.configuration.getBalancerFactory().createBalancer(new TreeSet<D>());
    this.dialect = this.configuration.getDialectFactory().createDialect();
    this.durability = this.configuration.getDurabilityFactory().createDurability(this);
    this.executor = this.configuration.getExecutorProvider().getExecutor(this.configuration.getThreadFactory());
    this.sinkSourceFactory = this.configuration.getInputSinkProvider().createInputSinkStrategy();
   
    this.lockManager.start();
    this.stateManager.start();
   
    Set<String> databases = this.stateManager.getActiveDatabases();
   
    if (!databases.isEmpty())
    {
      for (String databaseId: databases)
      {
        D database = this.getDatabase(databaseId);
       
        if (database != null)
        {
          this.balancer.add(database);
          database.setActive(true);
        }
        else
        {
          logger.log(Level.WARN, Messages.DATABASE_IGNORED.getMessage(), this, databaseId);
        }
      }
    }
    else
    {
      for (D database: this.configuration.getDatabaseMap().values())
      {
        if (this.isAlive(database, Level.WARN))
        {
          this.activate(database, this.stateManager);
        }
      }
    }

    Map<InvocationEvent, Map<String, InvokerEvent>> invokers = this.stateManager.recover();
    if (!invokers.isEmpty())
    {
      this.durability.recover(invokers);
    }
   
    this.databaseMetaDataCache = this.configuration.getDatabaseMetaDataCacheFactory().createCache(this);
   
    try
    {
      this.flushMetaDataCache();
    }
    catch (IllegalStateException e)
    {
      // Ignore - cache will initialize lazily.
    }
   
    CronExpression failureDetectionExpression = this.configuration.getFailureDetectionExpression();
    CronExpression autoActivationExpression = this.configuration.getAutoActivationExpression();
    int threads = requiredThreads(failureDetectionExpression) + requiredThreads(autoActivationExpression);
   
    if (threads > 0)
    {
      this.cronExecutor = new CronThreadPoolExecutor(threads, this.configuration.getThreadFactory());
     
      if (failureDetectionExpression != null)
      {
        this.cronExecutor.schedule(new FailureDetectionTask(), failureDetectionExpression);
      }
           
      if (autoActivationExpression != null)
      {
        this.cronExecutor.schedule(new AutoActivationTask(), autoActivationExpression);
      }
    }
   
    MBeanRegistrar<Z, D> registrar = this.configuration.getMBeanRegistrar();

    if (registrar != null)
    {
      registrar.register(this);
     
      for (D database: this.configuration.getDatabaseMap().values())
      {
        registrar.register(this, database);
      }
    }
   
    this.active = true;
  }

  private static int requiredThreads(CronExpression expression)
  {
    return (expression != null) ? 1 : 0;
  }
 
  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.Lifecycle#stop()
   */
  @Override
  public synchronized void stop()
  {
    this.active = false;
   
    if (this.balancer != null)
    {
      // Proactively deactivate any local databases
      for (D database: this.balancer)
      {
        if (database.isLocal())
        {
          this.deactivate(database, this.stateManager);
        }
      }
    }
   
    MBeanRegistrar<Z, D> registrar = this.configuration.getMBeanRegistrar();

    if (registrar != null)
    {
      registrar.unregister(this);
     
      for (D database: this.configuration.getDatabaseMap().values())
      {
        registrar.unregister(this, database);
      }
    }
   
    if (this.cronExecutor != null)
    {
      this.cronExecutor.shutdownNow();
    }
   
    if (this.stateManager != null)
    {
      this.stateManager.stop();
    }
   
    if (this.lockManager != null)
    {
      this.lockManager.stop();
    }

    if (this.executor != null)
    {
      this.executor.shutdownNow();
    }

    if (this.balancer != null)
    {
      this.balancer.clear();
    }
  }

  boolean isAlive(D database, Level level)
  {
    try
    {
      Connection connection = database.connect(database.getConnectionSource(), database.decodePassword(this.decoder));
      try
      {
        return this.dialect.isValid(connection);
      }
      finally
      {
        Resources.close(connection);
      }
    }
    catch (SQLException e)
    {
      logger.log(level, e);
      return false;
    }
  }

  boolean activate(D database, SynchronizationStrategy strategy) throws SQLException, InterruptedException
  {
    if (!this.isAlive(database, Level.DEBUG)) return false;
   
    Lock lock = this.lockManager.writeLock(null);
   
    lock.lockInterruptibly();
   
    try
    {
      if (this.balancer.contains(database)) return false;
     
      if (!this.balancer.isEmpty())
      {
        SynchronizationContext<Z, D> context = new SynchronizationContextImpl<Z, D>(this, database);
       
        try
        {
          DatabaseEvent event = new DatabaseEvent(database);
         
          logger.log(Level.INFO, Messages.DATABASE_SYNC_START.getMessage(this, database));
         
          for (SynchronizationListener listener: this.synchronizationListeners)
          {
            listener.beforeSynchronization(event);
          }
         
          strategy.synchronize(context);
 
          logger.log(Level.INFO, Messages.DATABASE_SYNC_END.getMessage(this, database));
         
          for (SynchronizationListener listener: this.synchronizationListeners)
          {
            listener.afterSynchronization(event);
          }
        }
        finally
        {
          context.close();
        }
      }
     
      return this.activate(database, this.stateManager);
    }
    finally
    {
      lock.unlock();
    }
  }

  class FailureDetectionTask implements Runnable
  {
    @Override
    public void run()
    {
      if (!DatabaseClusterImpl.this.getStateManager().isEnabled()) return;
     
      Set<D> databases = DatabaseClusterImpl.this.getBalancer();
     
      int size = databases.size();
     
      if ((size > 1) || DatabaseClusterImpl.this.configuration.isEmptyClusterAllowed())
      {
        List<D> deadList = new ArrayList<D>(size);
       
        for (D database: databases)
        {
          if (!DatabaseClusterImpl.this.isAlive(database, Level.WARN))
          {
            deadList.add(database);
          }
        }

        if ((deadList.size() < size) || DatabaseClusterImpl.this.configuration.isEmptyClusterAllowed())
        {
          for (D database: deadList)
          {
            if (DatabaseClusterImpl.this.deactivate(database, DatabaseClusterImpl.this.getStateManager()))
            {
              logger.log(Level.ERROR, Messages.DATABASE_DEACTIVATED.getMessage(), database, DatabaseClusterImpl.this);
            }
          }
        }
      }
    }
  } 
 
  class AutoActivationTask implements Runnable
  {
    @Override
    public void run()
    {
      if (!DatabaseClusterImpl.this.getStateManager().isEnabled()) return;
     
      try
      {
        Set<D> activeDatabases = DatabaseClusterImpl.this.getBalancer();
       
        if (!activeDatabases.isEmpty())
        {
          for (D database: DatabaseClusterImpl.this.configuration.getDatabaseMap().values())
          {
            if (!activeDatabases.contains(database))
            {
              try
              {
                if (DatabaseClusterImpl.this.activate(database, DatabaseClusterImpl.this.configuration.getSynchronizationStrategyMap().get(DatabaseClusterImpl.this.configuration.getDefaultSynchronizationStrategy())))
                {
                  logger.log(Level.INFO, Messages.DATABASE_ACTIVATED.getMessage(), database, DatabaseClusterImpl.this);
                }
              }
              catch (SQLException e)
              {
                logger.log(Level.DEBUG, e);
              }
            }
          }
        }
      }
      catch (InterruptedException e)
      {
        Thread.currentThread().interrupt();
      }
    }
  }
}
TOP

Related Classes of net.sf.hajdbc.sql.DatabaseClusterImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.