/**
   * @see net.sf.hajdbc.sql.AbstractChildInvocationHandler#getInvoker(java.lang.Object,
   *     java.lang.reflect.Method, java.lang.Object[])
   */
  @Override
  protected <R> Invoker<Z, D, Connection, R, SQLException> getInvoker(
      Connection connection, Method method, Object... parameters) throws SQLException {
    if (method.equals(releaseSavepointMethod) || method.equals(rollbackSavepointMethod)) {
      return this.getInvoker(Savepoint.class, 0, connection, method, parameters);
    }

    if (prepareStatementMethodSet.contains(method) || prepareCallMethodSet.contains(method)) {
      parameters[0] = this.getProxyFactory().evaluate((String) parameters[0]);
    }

    Invoker<Z, D, Connection, R, SQLException> invoker =
        super.getInvoker(connection, method, parameters);

    if (endTransactionMethodSet.contains(method)) {
      return this.getProxyFactory().getTransactionContext().end(invoker, phaseRegistry.get(method));
    }

    return invoker;
  }
  /**
   * @see net.sf.hajdbc.sql.AbstractChildInvocationHandler#getInvoker(java.lang.Object,
   *     java.lang.reflect.Method, java.lang.Object[])
   */
  @Override
  protected <R> Invoker<Z, D, Connection, R, SQLException> getInvoker(
      Connection connection, Method method, Object[] parameters) throws SQLException {
    if (method.equals(releaseSavepointMethod)) {
      final SQLProxy<Z, D, Savepoint, SQLException> proxy =
          this.getInvocationHandler((Savepoint) parameters[0]);

      return new Invoker<Z, D, Connection, R, SQLException>() {
        @Override
        public R invoke(D database, Connection connection) throws SQLException {
          connection.releaseSavepoint(proxy.getObject(database));

          return null;
        }
      };
    }

    if (method.equals(rollbackSavepointMethod)) {
      final SQLProxy<Z, D, Savepoint, SQLException> proxy =
          this.getInvocationHandler((Savepoint) parameters[0]);

      return new Invoker<Z, D, Connection, R, SQLException>() {
        @Override
        public R invoke(D database, Connection connection) throws SQLException {
          connection.rollback(proxy.getObject(database));

          return null;
        }
      };
    }

    Invoker<Z, D, Connection, R, SQLException> invoker =
        super.getInvoker(connection, method, parameters);

    if (endTransactionMethodSet.contains(method)) {
      return this.transactionContext.end(invoker, phaseRegistry.get(method));
    }

    return invoker;
  }
  /**
   * @throws SQLException
   * @see net.sf.hajdbc.sql.AbstractChildInvocationHandler#getInvocationStrategy(java.lang.Object,
   *     java.lang.reflect.Method, java.lang.Object[])
   */
  @Override
  protected InvocationStrategy getInvocationStrategy(
      Connection connection, Method method, Object... parameters) throws SQLException {
    if (driverReadMethodSet.contains(method)) {
      return InvocationStrategies.INVOKE_ON_ANY;
    }

    if (databaseReadMethodSet.contains(method) || method.equals(getMetaDataMethod)) {
      return InvocationStrategies.INVOKE_ON_NEXT;
    }

    if (driverWriterMethodSet.contains(method)
        || method.equals(closeMethod)
        || createStatementMethodSet.contains(method)) {
      return InvocationStrategies.INVOKE_ON_EXISTING;
    }

    if (prepareStatementMethodSet.contains(method)
        || prepareCallMethodSet.contains(method)
        || createLocatorMethodSet.contains(method)) {
      return InvocationStrategies.INVOKE_ON_ALL;
    }

    if (endTransactionMethodSet.contains(method)) {
      return this.getProxyFactory()
          .getTransactionContext()
          .end(InvocationStrategies.END_TRANSACTION_INVOKE_ON_ALL, phaseRegistry.get(method));
    }

    if (method.equals(rollbackSavepointMethod) || method.equals(releaseSavepointMethod)) {
      return InvocationStrategies.END_TRANSACTION_INVOKE_ON_ALL;
    }

    if (setSavepointMethodSet.contains(method)) {
      return InvocationStrategies.TRANSACTION_INVOKE_ON_ALL;
    }

    return super.getInvocationStrategy(connection, method, parameters);
  }