package ameba.db.migration; import ameba.core.Application; import ameba.db.DataSourceManager; import ameba.db.migration.flyway.DatabaseMigrationResolver; import ameba.db.migration.resources.MigrationResource; import ameba.i18n.Messages; import com.google.common.collect.Lists; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomUtils; import org.flywaydb.core.Flyway; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.utilities.ServiceLocatorUtilities; import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.ws.rs.NotFoundException; import javax.ws.rs.core.Feature; import javax.ws.rs.core.FeatureContext; import java.util.List; import java.util.Map; /** * <p>MigrationFeature class.</p> * * @author icode */ public class MigrationFeature implements Feature { private static final Logger logger = LoggerFactory.getLogger(MigrationFeature.class); // 随机生成的初始化数据库页面的id private static String MIGRATION_ID; @Inject private ServiceLocator locator; @Inject private Application.Mode mode; /** * <p>checkMigrationId.</p> * * @param uuid a {@link java.lang.String} object. */ public static void checkMigrationId(String uuid) { if (!MIGRATION_ID.equals(uuid)) { throw new NotFoundException(); } } /** * <p>getMigrationId.</p> * * @return a {@link java.lang.String} object. */ public static String getMigrationId() { return MIGRATION_ID; } /** * <p>generateMigrationId.</p> * * @return a {@link java.lang.String} object. */ public static String generateMigrationId() { return MIGRATION_ID = RandomStringUtils.randomAlphanumeric(RandomUtils.nextInt(20, 30)); } /** * {@inheritDoc} */ @Override public boolean configure(FeatureContext context) { generateMigrationId(); Map<String, Object> properties = context.getConfiguration().getProperties(); List<Migration> migrations = Lists.newArrayList(); DataSourceManager.getDataSourceNames() .stream() .filter(dbName -> !"false".equals(properties.get("db." + dbName + ".migration.enabled"))) .forEach(dbName -> { Flyway flyway = new Flyway(); flyway.setDataSource(DataSourceManager.getDataSource(dbName)); flyway.setBaselineOnMigrate(true); bindFlyway(dbName, flyway); Migration migration = locator.getService(Migration.class, dbName); migrations.add(migration); flyway.setResolvers(new DatabaseMigrationResolver(migration)); }); if (!migrations.isEmpty()) { context.register(MigrationFilter.class); } context.register(MigrationResource.class); if (!mode.isDev()) { for (Migration migration : migrations) { if (migration.hasChanged()) { logger.warn(Messages.get("warn.app.database.migration", "@db/migration/" + MIGRATION_ID)); break; } } } return true; } private void bindFlyway(final String name, final Flyway flyway) { ServiceLocatorUtilities.bind(locator, new AbstractBinder() { @Override protected void configure() { bind(flyway).to(Flyway.class).named(name).proxy(false); if (name.equals(DataSourceManager.getDefaultDataSourceName())) { bind(flyway).to(Flyway.class).proxy(false); } } }); } }