Skip to content

Commit f7bdfa1

Browse files
committed
NEW: DefaultDbMigration is configurable from properties
1 parent 6d5f740 commit f7bdfa1

File tree

8 files changed

+196
-78
lines changed

8 files changed

+196
-78
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package io.ebeaninternal.dbmigration;
2+
3+
import java.io.IOException;
4+
5+
import io.ebean.plugin.Plugin;
6+
import io.ebean.plugin.SpiServer;
7+
8+
/**
9+
* Plugin to generate db-migration scripts automatically.
10+
* @author Roland Praml, FOCONIS AG
11+
*/
12+
public class DbMigrationPlugin implements Plugin {
13+
14+
private DefaultDbMigration dbMigration;
15+
16+
private static String lastMigration;
17+
private static String lastInit;
18+
19+
@Override
20+
public void configure(SpiServer server) {
21+
dbMigration = new DefaultDbMigration();
22+
dbMigration.setServer(server);
23+
}
24+
25+
@Override
26+
public void online(boolean online) {
27+
try {
28+
lastInit = null;
29+
lastMigration = null;
30+
if (dbMigration.generate) {
31+
String tmp = lastMigration = dbMigration.generateMigration();
32+
if (tmp == null) {
33+
return;
34+
}
35+
}
36+
if (dbMigration.generateInit) {
37+
lastInit = dbMigration.generateInitMigration();
38+
}
39+
} catch (IOException e) {
40+
throw new RuntimeException("Error while generating migration", e);
41+
}
42+
}
43+
44+
@Override
45+
public void shutdown() {
46+
dbMigration = null;
47+
}
48+
49+
public static String getLastInit() {
50+
return lastInit;
51+
}
52+
53+
public static String getLastMigration() {
54+
return lastMigration;
55+
}
56+
}

ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java

Lines changed: 107 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.ebeaninternal.dbmigration;
22

33
import io.avaje.applog.AppLog;
4+
import io.avaje.classpath.scanner.core.Location;
45
import io.ebean.DB;
56
import io.ebean.Database;
67
import io.ebean.DatabaseBuilder;
@@ -10,6 +11,7 @@
1011
import io.ebean.config.dbplatform.DatabasePlatformProvider;
1112
import io.ebean.dbmigration.DbMigration;
1213
import io.ebean.util.IOUtils;
14+
import io.ebean.util.StringHelper;
1315
import io.ebeaninternal.api.DbOffline;
1416
import io.ebeaninternal.api.SpiEbeanServer;
1517
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
@@ -24,10 +26,7 @@
2426
import java.io.File;
2527
import java.io.IOException;
2628
import java.io.Writer;
27-
import java.util.ArrayList;
28-
import java.util.List;
29-
import java.util.Properties;
30-
import java.util.ServiceLoader;
29+
import java.util.*;
3130

3231
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
3332
import static java.lang.System.Logger.Level.*;
@@ -59,8 +58,8 @@ public class DefaultDbMigration implements DbMigration {
5958
private static final String initialVersion = "1.0";
6059
private static final String GENERATED_COMMENT = "THIS IS A GENERATED FILE - DO NOT MODIFY";
6160

62-
private final List<DatabasePlatformProvider> platformProviders = new ArrayList<>();
63-
protected final boolean online;
61+
private List<DatabasePlatformProvider> platformProviders = new ArrayList<>();
62+
protected boolean online;
6463
private boolean logToSystemOut = true;
6564
protected SpiEbeanServer server;
6665
protected String pathToResources = "src/main/resources";
@@ -75,8 +74,10 @@ public class DefaultDbMigration implements DbMigration {
7574
protected List<Pair> platforms = new ArrayList<>();
7675
protected DatabaseBuilder.Settings databaseBuilder;
7776
protected DbConstraintNaming constraintNaming;
77+
@Deprecated
7878
protected Boolean strictMode;
79-
protected Boolean includeGeneratedFileComment;
79+
protected boolean includeGeneratedFileComment;
80+
@Deprecated
8081
protected String header;
8182
protected String applyPrefix = "";
8283
protected String version;
@@ -86,6 +87,9 @@ public class DefaultDbMigration implements DbMigration {
8687
private int lockTimeoutSeconds;
8788
protected boolean includeBuiltInPartitioning = true;
8889
protected boolean includeIndex;
90+
protected boolean generate = false;
91+
protected boolean generateInit = false;
92+
private boolean keepLastInit = true;
8993

9094
/**
9195
* Create for offline migration generation.
@@ -122,12 +126,66 @@ public void setServerConfig(DatabaseBuilder builder) {
122126
if (constraintNaming == null) {
123127
this.constraintNaming = databaseBuilder.getConstraintNaming();
124128
}
129+
if (databasePlatform == null) {
130+
this.databasePlatform = databaseBuilder.getDatabasePlatform();
131+
}
125132
Properties properties = config.getProperties();
126133
if (properties != null) {
127-
PropertiesWrapper props = new PropertiesWrapper("ebean", config.getName(), properties, null);
134+
PropertiesWrapper props = new PropertiesWrapper("ebean", config.getName(), properties, config.getClassLoadConfig());
128135
migrationPath = props.get("migration.migrationPath", migrationPath);
129136
migrationInitPath = props.get("migration.migrationInitPath", migrationInitPath);
130137
pathToResources = props.get("migration.pathToResources", pathToResources);
138+
addForeignKeySkipCheck = props.getBoolean("migration.addForeignKeySkipCheck", addForeignKeySkipCheck);
139+
applyPrefix = props.get("migration.applyPrefix", applyPrefix);
140+
databasePlatform = props.createInstance(DatabasePlatform.class, "migration.databasePlatform", databasePlatform);
141+
generatePendingDrop = props.get("migration.generatePendingDrop", generatePendingDrop);
142+
includeBuiltInPartitioning = props.getBoolean("migration.includeBuiltInPartitioning", includeBuiltInPartitioning);
143+
includeGeneratedFileComment = props.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
144+
includeIndex = props.getBoolean("migration.includeIndex", includeIndex);
145+
lockTimeoutSeconds = props.getInt("migration.lockTimeoutSeconds", lockTimeoutSeconds);
146+
logToSystemOut = props.getBoolean("migration.logToSystemOut", logToSystemOut);
147+
modelPath = props.get("migration.modelPath", modelPath);
148+
modelSuffix = props.get("migration.modelSuffix", modelSuffix);
149+
name = props.get("migration.name", name);
150+
online = props.getBoolean("migration.online", online);
151+
vanillaPlatform = props.getBoolean("migration.vanillaPlatform", vanillaPlatform);
152+
version = props.get("migration.version", version);
153+
generate = props.getBoolean("migration.generate", generate);
154+
generateInit = props.getBoolean("migration.generateInit", generateInit);
155+
// header & strictMode must be configured at DatabaseConfig level
156+
parsePlatforms(props, config);
157+
}
158+
}
159+
160+
protected void parsePlatforms(PropertiesWrapper props, DatabaseBuilder.Settings config) {
161+
String platforms = props.get("migration.platforms");
162+
if (platforms == null || platforms.isEmpty()) {
163+
return;
164+
}
165+
String[] tmp = StringHelper.splitNames(platforms);
166+
for (String plat : tmp) {
167+
DatabasePlatform dbPlatform;
168+
String platformName = plat;
169+
String platformPrefix = null;
170+
int pos = plat.indexOf('=');
171+
if (pos != -1) {
172+
platformName = plat.substring(0, pos);
173+
platformPrefix = plat.substring(pos + 1);
174+
}
175+
176+
if (platformName.indexOf('.') == -1) {
177+
// parse platform as enum value
178+
Platform platform = Enum.valueOf(Platform.class, platformName.toUpperCase());
179+
dbPlatform = platform(platform);
180+
} else {
181+
// parse platform as class
182+
dbPlatform = (DatabasePlatform) config.getClassLoadConfig().newInstance(platformName);
183+
}
184+
if (platformPrefix == null) {
185+
platformPrefix = dbPlatform.platform().name().toLowerCase();
186+
}
187+
188+
addDatabasePlatform(dbPlatform, platformPrefix);
131189
}
132190
}
133191

@@ -318,7 +376,18 @@ private String generateMigrationFor(boolean initMigration) throws IOException {
318376
}
319377

320378
String pendingVersion = generatePendingDrop();
321-
if (pendingVersion != null) {
379+
if ("auto".equals(pendingVersion)) {
380+
StringJoiner sj = new StringJoiner(",");
381+
String diff = generateDiff(request);
382+
if (diff != null) {
383+
sj.add(diff);
384+
request = createRequest(initMigration);
385+
}
386+
for (String pendingDrop : request.getPendingDrops()) {
387+
sj.add(generatePendingDrop(request, pendingDrop));
388+
}
389+
return sj.length() == 0 ? null : sj.toString();
390+
} else if (pendingVersion != null) {
322391
return generatePendingDrop(request, pendingVersion);
323392
} else {
324393
return generateDiff(request);
@@ -553,7 +622,7 @@ private String generateMigration(Request request, Migration dbMigration, String
553622
return null;
554623
} else {
555624
if (!platforms.isEmpty()) {
556-
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
625+
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir, request.initMigration && keepLastInit);
557626

558627
} else if (databasePlatform != null) {
559628
// writer needs the current model to provide table/column details for
@@ -633,12 +702,17 @@ private String toUnderScore(String name) {
633702
/**
634703
* Write any extra platform ddl.
635704
*/
636-
private void writeExtraPlatformDdl(String fullVersion, CurrentModel currentModel, Migration dbMigration, File writePath) throws IOException {
705+
private void writeExtraPlatformDdl(String fullVersion, CurrentModel currentModel, Migration dbMigration, File writePath, boolean clear) throws IOException {
637706
DdlOptions options = new DdlOptions(addForeignKeySkipCheck);
638707
for (Pair pair : platforms) {
639708
DdlWrite writer = new DdlWrite(new MConfiguration(), currentModel.read(), options);
640709
PlatformDdlWriter platformWriter = createDdlWriter(pair.platform);
641710
File subPath = platformWriter.subPath(writePath, pair.prefix);
711+
if (clear) {
712+
for (File existing : subPath.listFiles()) {
713+
existing.delete();
714+
}
715+
}
642716
platformWriter.processMigration(dbMigration, writer, subPath, fullVersion);
643717
}
644718
}
@@ -656,7 +730,7 @@ private boolean writeMigrationXml(Migration dbMigration, File resourcePath, Stri
656730
if (file.exists()) {
657731
return false;
658732
}
659-
String comment = Boolean.TRUE.equals(includeGeneratedFileComment) ? GENERATED_COMMENT : null;
733+
String comment = includeGeneratedFileComment ? GENERATED_COMMENT : null;
660734
MigrationXmlWriter xmlWriter = new MigrationXmlWriter(comment);
661735
xmlWriter.write(dbMigration, file);
662736
return true;
@@ -674,11 +748,14 @@ private void setDefaults() {
674748
databasePlatform = server.databasePlatform();
675749
}
676750
if (databaseBuilder != null) {
751+
// FIXME: StrictMode and header may be defined HERE and in DatabaseConfig.
752+
// We shoild change either DefaultDbMigration or databaseConfig, so that it is only
753+
// defined on one place
677754
if (strictMode != null) {
678-
databaseBuilder.setDdlStrictMode(strictMode);
755+
databaseBuilder.ddlStrictMode(strictMode);
679756
}
680757
if (header != null) {
681-
databaseBuilder.setDdlHeader(header);
758+
databaseBuilder.ddlHeader(header);
682759
}
683760
}
684761
}
@@ -748,15 +825,20 @@ public File migrationDirectory() {
748825
* Return the file path to write the xml and sql to.
749826
*/
750827
File migrationDirectory(boolean initMigration) {
751-
// path to src/main/resources in typical maven project
752-
File resourceRootDir = new File(pathToResources);
753-
if (!resourceRootDir.exists()) {
754-
String msg = String.format("Error - path to resources %s does not exist. Absolute path is %s", pathToResources, resourceRootDir.getAbsolutePath());
755-
throw new UnknownResourcePathException(msg);
756-
}
757-
String resourcePath = migrationPath(initMigration);
828+
Location resourcePath = migrationPath(initMigration);
758829
// expect to be a path to something like - src/main/resources/dbmigration
759-
File path = new File(resourceRootDir, resourcePath);
830+
File path;
831+
if (resourcePath.isClassPath()) {
832+
// path to src/main/resources in typical maven project
833+
File resourceRootDir = new File(pathToResources);
834+
if (!resourceRootDir.exists()) {
835+
String msg = String.format("Error - path to resources %s does not exist. Absolute path is %s", pathToResources, resourceRootDir.getAbsolutePath());
836+
throw new UnknownResourcePathException(msg);
837+
}
838+
path = new File(resourceRootDir, resourcePath.path());
839+
} else {
840+
path = new File(resourcePath.path());
841+
}
760842
if (!path.exists()) {
761843
if (!path.mkdirs()) {
762844
logInfo("Warning - Unable to ensure migration directory exists at %s", path.getAbsolutePath());
@@ -765,8 +847,9 @@ File migrationDirectory(boolean initMigration) {
765847
return path;
766848
}
767849

768-
private String migrationPath(boolean initMigration) {
769-
return initMigration ? migrationInitPath : migrationPath;
850+
private Location migrationPath(boolean initMigration) {
851+
// remove classpath: or filesystem: prefix
852+
return new Location(initMigration ? migrationInitPath : migrationPath);
770853
}
771854

772855
/**

ebean-ddl-generator/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module io.ebean.ddl.generator {
22

3+
uses io.ebean.plugin.Plugin;
34
exports io.ebean.dbmigration;
45

56
provides io.ebean.dbmigration.DbMigration with io.ebeaninternal.dbmigration.DefaultDbMigration;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.ebeaninternal.dbmigration.DbMigrationPlugin

ebean-ddl-generator/src/test/resources/application-test.properties

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,3 @@ datasource.h2.url=jdbc:h2:mem:h2AutoTune
1010
datasource.pg.username=sa
1111
datasource.pg.password=
1212
datasource.pg.url=jdbc:h2:mem:h2AutoTune
13-
14-
# parameters for migration test
15-
datasource.migrationtest.username=SA
16-
datasource.migrationtest.password=SA
17-
datasource.migrationtest.url=jdbc:h2:mem:migration
18-
ebean.migrationtest.applyPrefix=V
19-
ebean.migrationtest.ddl.generate=false
20-
ebean.migrationtest.ddl.run=false
21-
ebean.migrationtest.ddl.header=-- Migrationscripts for ebean unittest
22-
ebean.migrationtest.migration.appName=migrationtest
23-
ebean.migrationtest.migration.migrationPath=dbmigration/migrationtest
24-
ebean.migrationtest.migration.strict=true
25-
26-
# parameters for migration test
27-
datasource.migrationtest-history.username=SA
28-
datasource.migrationtest-history.password=SA
29-
datasource.migrationtest-history.url=jdbc:h2:mem:migration
30-
ebean.migrationtest-history.applyPrefix=V
31-
ebean.migrationtest-history.ddl.generate=false
32-
ebean.migrationtest-history.ddl.run=false
33-
ebean.migrationtest-history.ddl.header=-- Migrationscripts for ebean unittest DbMigrationDropHistoryTest
34-
ebean.migrationtest-history.migration.appName=migrationtest-history
35-
ebean.migrationtest-history.migration.migrationPath=dbmigration/migrationtest-history
36-
ebean.migrationtest-history.migration.strict=true

ebean-test/src/test/java/io/ebean/xtest/dbmigration/DbMigrationDropHistoryTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,11 @@ public static void main(String[] args) throws IOException {
8080
List<String> pendingDrops = migration.getPendingDrops();
8181
assertThat(pendingDrops).contains("1.1");
8282

83-
//System.setProperty("ddl.migration.pendingDropsFor", "1.1");
8483
migration.setGeneratePendingDrop("1.1");
8584
assertThat(migration.generateMigration()).isEqualTo("1.2__dropsFor_1.1");
8685
assertThatThrownBy(()->migration.generateMigration())
8786
.isInstanceOf(IllegalArgumentException.class)
8887
.hasMessageContaining("No 'pendingDrops'"); // subsequent call
89-
System.clearProperty("ddl.migration.pendingDropsFor");
9088

9189
server.shutdown();
9290
logger.info("end");

0 commit comments

Comments
 (0)