public void onApplicationEvent()

in app/src/main/java/com/amazon/aws/partners/saasfactory/pgrls/configuration/DatabaseInit.java [40:82]


    public void onApplicationEvent(ApplicationContextInitializedEvent event) {
        Environment env = event.getApplicationContext().getEnvironment();

        String dbAppUser = env.getRequiredProperty("spring.datasource.username");
        String dbAppPassword = env.getRequiredProperty("spring.datasource.password");
        String dbHost = env.getRequiredProperty("DB_HOST");
        String dbDatabase = env.getRequiredProperty("DB_NAME");
        String jdbcUrl = "jdbc:postgresql://" + dbHost + ":5432/" + dbDatabase;

        Properties masterConnectionProperties = new Properties();
        masterConnectionProperties.put("user", env.getRequiredProperty("admin.datasource.username"));
        masterConnectionProperties.put("password", env.getRequiredProperty("admin.datasource.password"));

        // Bootstrap the database objects. The SQL is written to be idempotent so it can run each time Spring Boot
        // launches. This bootstrapping creates the tables and RLS policies. The RDS master user will be the owner
        // of these tables and by default will bypass RLS which is what we need for new tenant on-boarding where
        // INSERT statements would otherwise fail.
        //
        // This also will create a non root user with full read/write privileges for our application code to connect
        // as. This user will not be the owner of tables or other objects and will be bound by the RLS policies.
        try (Connection connection = DriverManager.getConnection(jdbcUrl, masterConnectionProperties); Statement sql = connection.createStatement()) {
            connection.setAutoCommit(false);
            LOGGER.info("Executing bootstrap database");
            try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("bootstrap.sql")) {
                Scanner scanner = new Scanner(is, "UTF-8");
                // Break on blank newline so we can send the DO...END statements as a single statement
                scanner.useDelimiter("\n\n");
                while (scanner.hasNext()) {
                    String stmt = scanner.next()
                            .replace("{{DB_APP_USER}}", dbAppUser)
                            .replace("{{DB_APP_PASS}}", dbAppPassword)
                            .trim();
                    sql.addBatch(stmt);
                }
                int[] count = sql.executeBatch();
                connection.commit();
            } catch (IOException ioe) {
                throw new RuntimeException(ioe);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }