public DistributedStateManager(
     DatabaseCluster<Z, D> cluster, CommandDispatcherFactory dispatcherFactory) throws Exception {
   this.cluster = cluster;
   this.stateManager = cluster.getStateManager();
   StateCommandContext<Z, D> context = this;
   this.dispatcher =
       dispatcherFactory.createCommandDispatcher(cluster.getId() + ".state", context, this, this);
 }
  /**
   * {@inheritDoc}
   *
   * @see net.sf.hajdbc.state.StateManagerFactory#createStateManager(net.sf.hajdbc.DatabaseCluster)
   */
  @Override
  public <Z, D extends Database<Z>> StateManager createStateManager(DatabaseCluster<Z, D> cluster) {
    if (this.urlPattern == null) {
      throw new IllegalArgumentException(
          "No embedded database driver was detected on the classpath.");
    }

    String url = MessageFormat.format(this.urlPattern, cluster.getId(), Strings.HA_JDBC_HOME);
    DriverDatabase database = new DriverDatabase();
    database.setLocation(url);
    database.setUser(this.user);
    database.setPassword(this.password);

    this.logger.log(
        Level.INFO, "State for database cluster {0} will be persisted to {1}", cluster, url);

    return new SQLStateManager<Z, D>(cluster, database, new GenericObjectPoolFactory(this));
  }
  /**
   * @see net.sf.hajdbc.invocation.InvocationStrategy#invoke(net.sf.hajdbc.sql.SQLProxy,
   *     net.sf.hajdbc.invocation.Invoker)
   */
  @Override
  public <Z, D extends Database<Z>, T, R, E extends Exception> SortedMap<D, R> invoke(
      SQLProxy<Z, D, T, E> proxy, Invoker<Z, D, T, R, E> invoker) throws E {
    Map.Entry<SortedMap<D, R>, SortedMap<D, E>> results = this.collectResults(proxy, invoker);

    SortedMap<D, R> resultMap = results.getKey();
    SortedMap<D, E> exceptionMap = results.getValue();

    if (!exceptionMap.isEmpty()) {
      ExceptionFactory<E> exceptionFactory = proxy.getExceptionFactory();
      DatabaseCluster<Z, D> cluster = proxy.getDatabaseCluster();
      Dialect dialect = cluster.getDialect();

      List<D> failedDatabases = new ArrayList<D>(exceptionMap.size());

      // Determine which exceptions are due to failures
      for (Map.Entry<D, E> entry : exceptionMap.entrySet()) {
        if (exceptionFactory.indicatesFailure(entry.getValue(), dialect)) {
          failedDatabases.add(entry.getKey());
        }
      }

      StateManager stateManager = cluster.getStateManager();

      // Deactivate failed databases, unless all failed
      if (!resultMap.isEmpty() || (failedDatabases.size() < exceptionMap.size())) {
        for (D failedDatabase : failedDatabases) {
          E exception = exceptionMap.remove(failedDatabase);

          if (cluster.deactivate(failedDatabase, stateManager)) {
            logger.error(
                "" + exception + "" + Messages.DATABASE_DEACTIVATED.getMessage(),
                failedDatabase,
                cluster);
          }
        }
      }

      if (!exceptionMap.isEmpty()) {
        // If primary database threw exception
        if (resultMap.isEmpty() || !exceptionMap.headMap(resultMap.firstKey()).isEmpty()) {
          D primaryDatabase = exceptionMap.firstKey();
          E primaryException = exceptionMap.get(primaryDatabase);

          // Deactivate databases with non-matching exceptions
          for (Map.Entry<D, E> entry : exceptionMap.tailMap(primaryDatabase).entrySet()) {
            E exception = entry.getValue();

            if (!exceptionFactory.equals(exception, primaryException)) {
              D database = entry.getKey();

              if (cluster.deactivate(database, stateManager)) {
                logger.error("" + exception + " " + Messages.DATABASE_INCONSISTENT.getMessage());
              }
            }
          }

          // Deactivate databases with results
          for (Map.Entry<D, R> entry : resultMap.entrySet()) {
            D database = entry.getKey();

            if (cluster.deactivate(database, stateManager)) {
              logger.error(Messages.DATABASE_INCONSISTENT.getMessage());
            }
          }

          throw primaryException;
        }
      }
      // Else primary was successful
      // Deactivate databases with exceptions
      for (Map.Entry<D, E> entry : exceptionMap.entrySet()) {
        D database = entry.getKey();
        E exception = entry.getValue();

        if (cluster.deactivate(database, stateManager)) {
          logger.error(Messages.DATABASE_DEACTIVATED.getMessage(), database, cluster);
        }
      }
    }

    return resultMap;
  }