@After
 public void tearDown() throws Exception {
   dbi.withHandle(
       new HandleCallback<Object>() {
         public Object withHandle(Handle handle) throws Exception {
           handle.execute("drop table something");
           handle.execute("drop sequence something_id_sequence");
           return null;
         }
       });
 }
 @Override
 public Service addService(final Service service) {
   return dbi.withHandle(
       new HandleCallback<Service>() {
         @Override
         public Service withHandle(Handle handle) throws Exception {
           log.debug("inserting service '{}'", service.id().value());
           insertRecordWithoutKey(SERVICES_TABLE, service.record(), handle);
           return new Service(getRecord(SERVICES_TABLE, service.id().value(), handle));
         }
       });
 }
 @Override
 public Agreement add(final Agreement agreement) {
   return dbi.withHandle(
       new HandleCallback<Agreement>() {
         @Override
         public Agreement withHandle(Handle handle) throws Exception {
           log.debug("inserting agreement '{}'", agreement.id().value());
           insertRecordWithoutKey(AGREEMENTS_TABLE, agreement.record(), handle);
           return new Agreement(getRecord(AGREEMENTS_TABLE, agreement.id().value(), handle));
         }
       });
 }
 @Before
 public void setUp() throws Exception {
   dbi = new DBI("jdbc:oracle:thin:@localhost:test", "oracle", "oracle");
   dbi.withHandle(
       new HandleCallback<Object>() {
         public Object withHandle(Handle handle) throws Exception {
           handle.execute("create sequence something_id_sequence INCREMENT BY 1 START WITH 100");
           handle.execute(
               "create table something (name varchar(200), id int, constraint something_id primary key (id))");
           return null;
         }
       });
 }
 private boolean detectSchema(final DBI dbi, final String schemaName) {
   return dbi.withHandle(
       new HandleCallback<Boolean>() {
         @Override
         public Boolean withHandle(final Handle handle) {
           return handle
                   .createQuery("#mojo:detect_schema")
                   .bind("schema_name", schemaName)
                   .map(IntegerMapper.FIRST)
                   .first()
               != 0;
         }
       });
 }
 @Override
 public Customer addCustomer(final Customer customer) {
   return dbi.withHandle(
       new HandleCallback<Customer>() {
         @Override
         public Customer withHandle(Handle handle) throws Exception {
           log.debug("inserting service '{}'", customer.id().value());
           final Map<String, Object> record = Maps.newHashMap(customer.record());
           final DateTime now = DateTime.now();
           record.put("inserted_on", now);
           record.put("updated", now);
           record.put("history_id", lastValueOf(AUDIT_TABLE, "history_id", handle) + 1);
           // TODO: insert audit item on history
           insertRecordWithoutKey(CUSTOMERS_TABLE, record, handle);
           return new Customer(getRecord(CUSTOMERS_TABLE, customer.id().value(), handle));
         }
       });
 }
  public static void createTable(final DBI dbi, final String tableName, final String sql) {
    try {
      dbi.withHandle(
          new HandleCallback<Void>() {
            @Override
            public Void withHandle(Handle handle) throws Exception {
              List<Map<String, Object>> table =
                  handle.select(String.format("SHOW tables LIKE '%s'", tableName));

              if (table.isEmpty()) {
                log.info("Creating table[%s]", tableName);
                handle.createStatement(sql).execute();
              } else {
                log.info("Table[%s] existed: [%s]", tableName, table);
              }

              return null;
            }
          });
    } catch (Exception e) {
      log.warn(e, "Exception creating table");
    }
  }
  @Override
  protected void doExecute() throws Exception {
    final List<String> databaseList = expandDatabaseList(databases);

    final boolean permission = config.getBoolean(getPropertyName("permission.create-db"), false);
    if (!permission) {
      throw new MojoExecutionException("No permission to run this task!");
    }

    final DBI rootDbi = getDBIFor(rootDBIConfig);

    final StatementLocator statementLocator =
        new TemplatingStatementLocator("/sql/", loaderManager);
    rootDbi.setStatementLocator(statementLocator);

    for (final String database : databaseList) {
      final DBIConfig databaseConfig = getDBIConfigFor(database);
      final String user = databaseConfig.getDBUser();

      // Language and schema creation runs as root user, but connected to the actual database.
      final DBI rootDbDbi =
          new DBI(
              databaseConfig.getDBUrl(), rootDBIConfig.getDBUser(), rootDBIConfig.getDBPassword());
      rootDbDbi.setStatementLocator(statementLocator);

      if (MigratoryOption.containsOption(MigratoryOption.DRY_RUN, optionList)) {
        CONSOLE.info("Dry run for database {} activated!", database);
      } else {
        // User and Database creation runs as root user connected to the root db
        try {
          boolean userExists =
              rootDbi.withHandle(
                  new HandleCallback<Boolean>() {
                    @Override
                    public Boolean withHandle(final Handle handle) {
                      return handle
                              .createQuery("#mojo:detect_user")
                              .bind("user", user)
                              .map(IntegerMapper.FIRST)
                              .first()
                          != 0;
                    }
                  });

          if (userExists) {
            CONSOLE.info("... User {} already exists ...", user);
          } else {
            CONSOLE.info("... creating User {} ...", user);

            rootDbi.withHandle(
                new HandleCallback<Void>() {
                  @Override
                  public Void withHandle(final Handle handle) {
                    handle
                        .createStatement("#mojo:create_user")
                        .define("user", user)
                        .define("password", databaseConfig.getDBPassword())
                        .execute();
                    return null;
                  }
                });
          }

          boolean databaseExists =
              rootDbi.withHandle(
                  new HandleCallback<Boolean>() {
                    @Override
                    public Boolean withHandle(final Handle handle) {
                      return handle
                              .createQuery("#mojo:detect_database")
                              .bind("database", database)
                              .map(IntegerMapper.FIRST)
                              .first()
                          != 0;
                    }
                  });

          if (databaseExists) {
            CONSOLE.info("... Database {} already exists ...", database);
          } else {
            CONSOLE.info("... creating Database {}...", database);

            final String tablespace;

            if (databaseConfig.getDBTablespace() != null) {
              boolean tablespaceExists =
                  rootDbi.withHandle(
                      new HandleCallback<Boolean>() {
                        @Override
                        public Boolean withHandle(final Handle handle) {
                          return handle
                                  .createQuery("#mojo:detect_tablespace")
                                  .bind("table_space", databaseConfig.getDBTablespace())
                                  .map(IntegerMapper.FIRST)
                                  .first()
                              != 0;
                        }
                      });

              if (tablespaceExists) {
                tablespace = databaseConfig.getDBTablespace();
              } else {
                CONSOLE.warn(
                    "Tablespace '{}' does not exist, falling back to default!",
                    databaseConfig.getDBTablespace());
                tablespace = null;
              }
            } else {
              tablespace = null;
            }

            rootDbi.withHandle(
                new HandleCallback<Void>() {
                  @Override
                  public Void withHandle(final Handle handle) {
                    handle
                        .createStatement("#mojo:create_database")
                        .define("database", database)
                        .define("owner", databaseConfig.getDBUser())
                        .define("tablespace", tablespace)
                        .execute();
                    return null;
                  }
                });
          }

        } catch (DBIException de) {
          throw new MojoExecutionException(String.format("While creating %s", database), de);
        }

        try {
          boolean languageExists =
              rootDbDbi.withHandle(
                  new HandleCallback<Boolean>() {
                    @Override
                    public Boolean withHandle(final Handle handle) {
                      return handle
                              .createQuery("#mojo:detect_language")
                              .map(IntegerMapper.FIRST)
                              .first()
                          != 0;
                    }
                  });

          if (languageExists) {
            CONSOLE.trace("Language plpgsql exists");
          } else {
            CONSOLE.info("... creating plpgsql language...");

            rootDbDbi.withHandle(
                new HandleCallback<Void>() {
                  @Override
                  public Void withHandle(final Handle handle) {
                    handle.createStatement("#mojo:create_language").execute();
                    return null;
                  }
                });
          }
        } catch (DBIException de) {
          throw new MojoExecutionException(String.format("While creating %s", database), de);
        }

        final boolean createSchema = config.getBoolean(getPropertyName("schema.create"), false);

        if (createSchema) {
          final String schemaName = databaseConfig.getDBUser();
          try {
            if (detectSchema(rootDbDbi, schemaName)) {
              CONSOLE.trace("Schema {} exists", schemaName);
            } else {
              CONSOLE.info("... creating Schema {} ...", schemaName);

              rootDbDbi.withHandle(
                  new HandleCallback<Void>() {
                    @Override
                    public Void withHandle(final Handle handle) {
                      handle
                          .createStatement("#mojo:create_schema")
                          .define("schema_name", schemaName)
                          .execute();
                      return null;
                    }
                  });
            }
          } catch (DBIException de) {
            throw new MojoExecutionException(
                String.format("While creating schema %s", schemaName), de);
          }

          final boolean enforceSchema = config.getBoolean(getPropertyName("schema.enforce"), false);

          if (enforceSchema) {
            try {
              if (!detectSchema(rootDbDbi, "public")) {
                CONSOLE.trace("public schema does not exist");
              } else {
                CONSOLE.info("... dropping public schema ...");

                rootDbDbi.withHandle(
                    new HandleCallback<Void>() {
                      @Override
                      public Void withHandle(final Handle handle) {
                        handle
                            .createStatement("#mojo:drop_schema")
                            .define("schema_name", "public")
                            .execute();
                        return null;
                      }
                    });
              }
            } catch (DBIException de) {
              throw new MojoExecutionException(
                  String.format("While dropping public schema: %s", schemaName), de);
            }
          }
        } else {
          CONSOLE.info("... not creating schema ...");
        }

        try {
          // Finally metadata is created as the database owner connected to the database.
          final DBI dbi = getDBIFor(database);

          Migratory migratory = new Migratory(migratoryConfig, dbi);
          final List<MetadataInfo> result = migratory.dbInit();
          if (result != null) {
            final MigrationState state = MetadataInfo.determineMigrationState(result);
            if (state != MigrationState.OK) {
              throw new MojoExecutionException(
                  String.format("Could not initialize metadata, returned status %s", state));
            }
            CONSOLE.info("... initialized metadata ...");
          } else {
            CONSOLE.info("... metadata already exists...");
          }
        } catch (DBIException de) {
          throw new MojoExecutionException(String.format("While creating %s", database), de);
        } catch (MigratoryException me) {
          throw new MojoExecutionException(String.format("While creating %s", database), me);
        }
      }
      CONSOLE.info("... done");
    }
  }