Skip to content

Commit e666277

Browse files
committed
PR ebean-orm#3152 - NEW: DefaultDbMigration is configurable from properties
1 parent e7f157e commit e666277

File tree

8 files changed

+195
-80
lines changed

8 files changed

+195
-80
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: 106 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
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.annotation.Platform;
7-
import io.ebean.config.DatabaseConfig;
8-
import io.ebean.config.DbConstraintNaming;
9-
import io.ebean.config.PlatformConfig;
10-
import io.ebean.config.PropertiesWrapper;
8+
import io.ebean.config.*;
119
import io.ebean.config.dbplatform.DatabasePlatform;
1210
import io.ebean.config.dbplatform.DatabasePlatformProvider;
1311
import io.ebean.dbmigration.DbMigration;
1412
import io.ebean.util.IOUtils;
13+
import io.ebean.util.StringHelper;
1514
import io.ebeaninternal.api.DbOffline;
1615
import io.ebeaninternal.api.SpiEbeanServer;
1716
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
@@ -26,10 +25,7 @@
2625
import java.io.File;
2726
import java.io.IOException;
2827
import java.io.Writer;
29-
import java.util.ArrayList;
30-
import java.util.List;
31-
import java.util.Properties;
32-
import java.util.ServiceLoader;
28+
import java.util.*;
3329

3430
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
3531
import static java.lang.System.Logger.Level.*;
@@ -61,8 +57,8 @@ public class DefaultDbMigration implements DbMigration {
6157
private static final String initialVersion = "1.0";
6258
private static final String GENERATED_COMMENT = "THIS IS A GENERATED FILE - DO NOT MODIFY";
6359

64-
private final List<DatabasePlatformProvider> platformProviders = new ArrayList<>();
65-
protected final boolean online;
60+
private List<DatabasePlatformProvider> platformProviders = new ArrayList<>();
61+
protected boolean online;
6662
private boolean logToSystemOut = true;
6763
protected SpiEbeanServer server;
6864
protected String pathToResources = "src/main/resources";
@@ -77,8 +73,10 @@ public class DefaultDbMigration implements DbMigration {
7773
protected List<Pair> platforms = new ArrayList<>();
7874
protected DatabaseConfig databaseConfig;
7975
protected DbConstraintNaming constraintNaming;
76+
@Deprecated
8077
protected Boolean strictMode;
81-
protected Boolean includeGeneratedFileComment;
78+
protected boolean includeGeneratedFileComment;
79+
@Deprecated
8280
protected String header;
8381
protected String applyPrefix = "";
8482
protected String version;
@@ -88,6 +86,9 @@ public class DefaultDbMigration implements DbMigration {
8886
private int lockTimeoutSeconds;
8987
protected boolean includeBuiltInPartitioning = true;
9088
protected boolean includeIndex;
89+
protected boolean generate = false;
90+
protected boolean generateInit = false;
91+
private boolean keepLastInit = true;
9192

9293
/**
9394
* Create for offline migration generation.
@@ -123,12 +124,66 @@ public void setServerConfig(DatabaseConfig config) {
123124
if (constraintNaming == null) {
124125
this.constraintNaming = databaseConfig.getConstraintNaming();
125126
}
127+
if (databasePlatform == null) {
128+
this.databasePlatform = databaseConfig.getDatabasePlatform();
129+
}
126130
Properties properties = config.getProperties();
127131
if (properties != null) {
128-
PropertiesWrapper props = new PropertiesWrapper("ebean", config.getName(), properties, null);
132+
PropertiesWrapper props = new PropertiesWrapper("ebean", config.getName(), properties, config.getClassLoadConfig());
129133
migrationPath = props.get("migration.migrationPath", migrationPath);
130134
migrationInitPath = props.get("migration.migrationInitPath", migrationInitPath);
131135
pathToResources = props.get("migration.pathToResources", pathToResources);
136+
addForeignKeySkipCheck = props.getBoolean("migration.addForeignKeySkipCheck", addForeignKeySkipCheck);
137+
applyPrefix = props.get("migration.applyPrefix", applyPrefix);
138+
databasePlatform = props.createInstance(DatabasePlatform.class, "migration.databasePlatform", databasePlatform);
139+
generatePendingDrop = props.get("migration.generatePendingDrop", generatePendingDrop);
140+
includeBuiltInPartitioning = props.getBoolean("migration.includeBuiltInPartitioning", includeBuiltInPartitioning);
141+
includeGeneratedFileComment = props.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
142+
includeIndex = props.getBoolean("migration.includeIndex", includeIndex);
143+
lockTimeoutSeconds = props.getInt("migration.lockTimeoutSeconds", lockTimeoutSeconds);
144+
logToSystemOut = props.getBoolean("migration.logToSystemOut", logToSystemOut);
145+
modelPath = props.get("migration.modelPath", modelPath);
146+
modelSuffix = props.get("migration.modelSuffix", modelSuffix);
147+
name = props.get("migration.name", name);
148+
online = props.getBoolean("migration.online", online);
149+
vanillaPlatform = props.getBoolean("migration.vanillaPlatform", vanillaPlatform);
150+
version = props.get("migration.version", version);
151+
generate = props.getBoolean("migration.generate", generate);
152+
generateInit = props.getBoolean("migration.generateInit", generateInit);
153+
// header & strictMode must be configured at DatabaseConfig level
154+
parsePlatforms(props, config);
155+
}
156+
}
157+
158+
protected void parsePlatforms(PropertiesWrapper props, DatabaseConfig config) {
159+
String platforms = props.get("migration.platforms");
160+
if (platforms == null || platforms.isEmpty()) {
161+
return;
162+
}
163+
String[] tmp = StringHelper.splitNames(platforms);
164+
for (String plat : tmp) {
165+
DatabasePlatform dbPlatform;
166+
String platformName = plat;
167+
String platformPrefix = null;
168+
int pos = plat.indexOf('=');
169+
if (pos != -1) {
170+
platformName = plat.substring(0, pos);
171+
platformPrefix = plat.substring(pos + 1);
172+
}
173+
174+
if (platformName.indexOf('.') == -1) {
175+
// parse platform as enum value
176+
Platform platform = Enum.valueOf(Platform.class, platformName.toUpperCase());
177+
dbPlatform = platform(platform);
178+
} else {
179+
// parse platform as class
180+
dbPlatform = (DatabasePlatform) config.getClassLoadConfig().newInstance(platformName);
181+
}
182+
if (platformPrefix == null) {
183+
platformPrefix = dbPlatform.platform().name().toLowerCase();
184+
}
185+
186+
addDatabasePlatform(dbPlatform, platformPrefix);
132187
}
133188
}
134189

@@ -319,7 +374,18 @@ private String generateMigrationFor(boolean initMigration) throws IOException {
319374
}
320375

321376
String pendingVersion = generatePendingDrop();
322-
if (pendingVersion != null) {
377+
if ("auto".equals(pendingVersion)) {
378+
StringJoiner sj = new StringJoiner(",");
379+
String diff = generateDiff(request);
380+
if (diff != null) {
381+
sj.add(diff);
382+
request = createRequest(initMigration);
383+
}
384+
for (String pendingDrop : request.getPendingDrops()) {
385+
sj.add(generatePendingDrop(request, pendingDrop));
386+
}
387+
return sj.length() == 0 ? null : sj.toString();
388+
} else if (pendingVersion != null) {
323389
return generatePendingDrop(request, pendingVersion);
324390
} else {
325391
return generateDiff(request);
@@ -554,7 +620,7 @@ private String generateMigration(Request request, Migration dbMigration, String
554620
return null;
555621
} else {
556622
if (!platforms.isEmpty()) {
557-
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
623+
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir, request.initMigration && keepLastInit);
558624

559625
} else if (databasePlatform != null) {
560626
// writer needs the current model to provide table/column details for
@@ -634,12 +700,17 @@ private String toUnderScore(String name) {
634700
/**
635701
* Write any extra platform ddl.
636702
*/
637-
private void writeExtraPlatformDdl(String fullVersion, CurrentModel currentModel, Migration dbMigration, File writePath) throws IOException {
703+
private void writeExtraPlatformDdl(String fullVersion, CurrentModel currentModel, Migration dbMigration, File writePath, boolean clear) throws IOException {
638704
DdlOptions options = new DdlOptions(addForeignKeySkipCheck);
639705
for (Pair pair : platforms) {
640706
DdlWrite writer = new DdlWrite(new MConfiguration(), currentModel.read(), options);
641707
PlatformDdlWriter platformWriter = createDdlWriter(pair.platform);
642708
File subPath = platformWriter.subPath(writePath, pair.prefix);
709+
if (clear) {
710+
for (File existing : subPath.listFiles()) {
711+
existing.delete();
712+
}
713+
}
643714
platformWriter.processMigration(dbMigration, writer, subPath, fullVersion);
644715
}
645716
}
@@ -657,7 +728,7 @@ private boolean writeMigrationXml(Migration dbMigration, File resourcePath, Stri
657728
if (file.exists()) {
658729
return false;
659730
}
660-
String comment = Boolean.TRUE.equals(includeGeneratedFileComment) ? GENERATED_COMMENT : null;
731+
String comment = includeGeneratedFileComment ? GENERATED_COMMENT : null;
661732
MigrationXmlWriter xmlWriter = new MigrationXmlWriter(comment);
662733
xmlWriter.write(dbMigration, file);
663734
return true;
@@ -675,6 +746,9 @@ private void setDefaults() {
675746
databasePlatform = server.databasePlatform();
676747
}
677748
if (databaseConfig != null) {
749+
// FIXME: StrictMode and header may be defined HERE and in DatabaseConfig.
750+
// We shoild change either DefaultDbMigration or databaseConfig, so that it is only
751+
// defined on one place
678752
if (strictMode != null) {
679753
databaseConfig.setDdlStrictMode(strictMode);
680754
}
@@ -749,15 +823,20 @@ public File migrationDirectory() {
749823
* Return the file path to write the xml and sql to.
750824
*/
751825
File migrationDirectory(boolean initMigration) {
752-
// path to src/main/resources in typical maven project
753-
File resourceRootDir = new File(pathToResources);
754-
if (!resourceRootDir.exists()) {
755-
String msg = String.format("Error - path to resources %s does not exist. Absolute path is %s", pathToResources, resourceRootDir.getAbsolutePath());
756-
throw new UnknownResourcePathException(msg);
757-
}
758-
String resourcePath = migrationPath(initMigration);
826+
Location resourcePath = migrationPath(initMigration);
759827
// expect to be a path to something like - src/main/resources/dbmigration
760-
File path = new File(resourceRootDir, resourcePath);
828+
File path;
829+
if (resourcePath.isClassPath()) {
830+
// path to src/main/resources in typical maven project
831+
File resourceRootDir = new File(pathToResources);
832+
if (!resourceRootDir.exists()) {
833+
String msg = String.format("Error - path to resources %s does not exist. Absolute path is %s", pathToResources, resourceRootDir.getAbsolutePath());
834+
throw new UnknownResourcePathException(msg);
835+
}
836+
path = new File(resourceRootDir, resourcePath.path());
837+
} else {
838+
path = new File(resourcePath.path());
839+
}
761840
if (!path.exists()) {
762841
if (!path.mkdirs()) {
763842
logInfo("Warning - Unable to ensure migration directory exists at %s", path.getAbsolutePath());
@@ -766,8 +845,9 @@ File migrationDirectory(boolean initMigration) {
766845
return path;
767846
}
768847

769-
private String migrationPath(boolean initMigration) {
770-
return initMigration ? migrationInitPath : migrationPath;
848+
private Location migrationPath(boolean initMigration) {
849+
// remove classpath: or filesystem: prefix
850+
return new Location(initMigration ? migrationInitPath : migrationPath);
771851
}
772852

773853
/**

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
@@ -79,13 +79,11 @@ public static void main(String[] args) throws IOException {
7979
List<String> pendingDrops = migration.getPendingDrops();
8080
assertThat(pendingDrops).contains("1.1");
8181

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

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

0 commit comments

Comments
 (0)