001package io.ebean.migration.runner; 002 003import io.ebean.migration.ConfigurationAware; 004import io.ebean.migration.JdbcMigration; 005import io.ebean.migration.MigrationConfig; 006import io.ebean.migration.MigrationVersion; 007import org.avaje.classpath.scanner.Resource; 008import org.avaje.classpath.scanner.ResourceFilter; 009import org.avaje.classpath.scanner.core.Scanner; 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013import java.util.ArrayList; 014import java.util.Collections; 015import java.util.List; 016 017/** 018 * Loads the DB migration resources and sorts them into execution order. 019 */ 020public class LocalMigrationResources { 021 022 private static final Logger logger = LoggerFactory.getLogger(LocalMigrationResources.class); 023 024 private final MigrationConfig migrationConfig; 025 026 private final List<LocalMigrationResource> versions = new ArrayList<>(); 027 028 /** 029 * Construct with configuration options. 030 */ 031 public LocalMigrationResources(MigrationConfig migrationConfig) { 032 this.migrationConfig = migrationConfig; 033 } 034 035 /** 036 * Read all the migration resources (SQL scripts) returning true if there are versions. 037 */ 038 public boolean readResources() { 039 040 String migrationPath = migrationConfig.getMigrationPath(); 041 042 ClassLoader classLoader = migrationConfig.getClassLoader(); 043 044 Scanner scanner = new Scanner(classLoader); 045 List<Resource> resourceList = scanner.scanForResources(migrationPath, new Match(migrationConfig)); 046 047 logger.debug("resources: {}", resourceList); 048 049 for (Resource resource : resourceList) { 050 String filename = resource.getFilename(); 051 if (filename.endsWith(migrationConfig.getApplySuffix())) { 052 versions.add(createScriptMigration(resource, filename)); 053 } else if (migrationConfig.getJdbcMigrationFactory() != null && filename.endsWith(".class")) { 054 versions.add(createJdbcMigration(resource, filename)); 055 } 056 } 057 058 Collections.sort(versions); 059 return !versions.isEmpty(); 060 } 061 062 /** 063 * Return a programmatic JDBC migration. 064 */ 065 private LocalMigrationResource createJdbcMigration(Resource resource, String filename) { 066 int pos = filename.lastIndexOf(".class"); 067 String mainName = filename.substring(0, pos); 068 MigrationVersion migrationVersion = MigrationVersion.parse(mainName); 069 String className = resource.getLocation().replace('/', '.'); 070 className = className.substring(0, className.length()-6); 071 JdbcMigration instance = migrationConfig.getJdbcMigrationFactory().createInstance(className); 072 return new LocalJdbcMigrationResource(migrationVersion, resource.getLocation(), instance); 073 } 074 075 /** 076 * Create a script based migration. 077 */ 078 private LocalMigrationResource createScriptMigration(Resource resource, String filename) { 079 int pos = filename.lastIndexOf(migrationConfig.getApplySuffix()); 080 String mainName = filename.substring(0, pos); 081 MigrationVersion migrationVersion = MigrationVersion.parse(mainName); 082 return new LocalDdlMigrationResource(migrationVersion, resource.getLocation(), resource); 083 } 084 085 /** 086 * Return the list of migration resources in version order. 087 */ 088 public List<LocalMigrationResource> getVersions() { 089 return versions; 090 } 091 092 093 /** 094 * Filter used to find the migration scripts. 095 */ 096 private static class Match implements ResourceFilter { 097 098 private final MigrationConfig migrationConfig; 099 100 Match(MigrationConfig migrationConfig) { 101 this.migrationConfig = migrationConfig; 102 } 103 104 @Override 105 public boolean isMatch(String name) { 106 return name.endsWith(migrationConfig.getApplySuffix()) 107 || migrationConfig.getJdbcMigrationFactory() != null && name.endsWith(".class"); 108 } 109 } 110}