001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package de.softwareforge.testing.postgres.embedded; 015 016import static com.google.common.base.Preconditions.checkNotNull; 017 018import java.io.IOException; 019import java.util.Set; 020import java.util.function.Consumer; 021import javax.sql.DataSource; 022 023import com.google.common.collect.ImmutableList; 024import edu.umd.cs.findbugs.annotations.NonNull; 025import org.flywaydb.core.Flyway; 026import org.flywaydb.core.api.FlywayException; 027import org.flywaydb.core.api.configuration.FluentConfiguration; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * An {@link EmbeddedPostgresPreparer<DataSource>} that uses the <a href="https://flywaydb.org/">Flyway version control for your database</a> framework to 033 * migrate a data source to a known state. 034 */ 035public final class FlywayPreparer implements EmbeddedPostgresPreparer<DataSource> { 036 037 private static final Logger LOG = LoggerFactory.getLogger(FlywayPreparer.class); 038 039 private final ImmutableList.Builder<Consumer<FluentConfiguration>> customizers = ImmutableList.builder(); 040 041 /** 042 * Creates a new instance using one or more classpath locations. 043 * 044 * @param locations One or more locations on the classpath. 045 * @return A {@link FlywayPreparer} instance. 046 */ 047 @NonNull 048 public static FlywayPreparer forClasspathLocation(String... locations) { 049 FlywayPreparer preparer = new FlywayPreparer(); 050 preparer.addCustomizer(c -> c.locations(locations)); 051 return preparer; 052 } 053 054 /** 055 * Create a new, uninitialized preparer instance. Use {@link FlywayPreparer#addCustomizer(Consumer)} to modify the configuration for the {@link 056 * FluentConfiguration} object. 057 */ 058 public FlywayPreparer() { 059 } 060 061 /** 062 * Add a customizer instance. Each customizer is called once with the {@link FluentConfiguration} instance before setting the datasource and calling {@link 063 * FluentConfiguration#load()} and {@link Flyway#migrate()}. 064 * 065 * @param customizer A {@link Consumer<FluentConfiguration>} instance. Must not be null. 066 * @return This object. 067 * @since 3.0 068 */ 069 @NonNull 070 public FlywayPreparer addCustomizer(@NonNull Consumer<FluentConfiguration> customizer) { 071 checkNotNull(customizer, "customizer is null"); 072 customizers.add(customizer); 073 074 return this; 075 } 076 077 /** 078 * Add customizer instances. Each customizer is called once with the {@link FluentConfiguration} instance before setting the datasource and calling {@link 079 * FluentConfiguration#load()} and {@link Flyway#migrate()}. 080 * 081 * @param customizers A set of {@link Consumer<FluentConfiguration>} instances. Must not be null. 082 * @return This object. 083 * @since 3.0 084 */ 085 @NonNull 086 public FlywayPreparer addCustomizers(@NonNull Set<Consumer<FluentConfiguration>> customizers) { 087 checkNotNull(customizers, "customizers is null"); 088 customizers.addAll(customizers); 089 090 return this; 091 } 092 093 @Override 094 public void prepare(@NonNull DataSource dataSource) throws IOException { 095 checkNotNull(dataSource, "dataSource is null"); 096 097 try { 098 final FluentConfiguration config = Flyway.configure(); 099 100 customizers.build().forEach(c -> c.accept(config)); 101 102 config.dataSource(dataSource); 103 Flyway flyway = config.load(); 104 flyway.migrate(); 105 106 } catch (FlywayException e) { 107 throw new IOException(e); 108 } 109 } 110}