package ameba.db.ebean.migration;
import ameba.db.migration.models.ScriptInfo;
import io.ebean.dbmigration.DbMigration;
import io.ebean.dbmigration.DbOffline;
import io.ebean.dbmigration.ddlgeneration.DdlWrite;
import io.ebean.dbmigration.migration.Migration;
import io.ebean.dbmigration.model.CurrentModel;
import io.ebean.dbmigration.model.MConfiguration;
import io.ebean.dbmigration.model.ModelContainer;
import io.ebean.dbmigration.model.ModelDiff;
import io.ebean.plugin.SpiServer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
/**
* <p>ModelMigration class.</p>
*
* @author icode
*/
public class ModelMigration extends DbMigration {
private static final String initialVersion = "1.0";
private ModelDiff diff;
private MigrationModel migrationModel;
private CurrentModel currentModel;
private ScriptInfo scriptInfo;
/**
* <p>diff.</p>
*
* @return a {@link io.ebean.dbmigration.model.ModelDiff} object.
*/
public ModelDiff diff() {
if (diff != null) return diff;
setOffline();
setDefaults();
try {
migrationModel = new MigrationModel(server);
ModelContainer migrated = migrationModel.read();
currentModel = new CurrentModel(server, constraintNaming);
ModelContainer current = currentModel.read();
diff = new ModelDiff(migrated);
diff.compareTo(current);
} finally {
if (!online) {
DbOffline.reset();
}
}
return diff;
}
private void setOffline() {
if (!online) {
DbOffline.setGenerateMigration();
if (databasePlatform == null && !platforms.isEmpty()) {
// for multiple platform generation set the general platform
// to H2 so that it runs offline without DB connection
setPlatform(platforms.get(0).platform);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void generateMigration() throws IOException {
if (scriptInfo != null) {
return;
}
if (diff == null) {
diff();
}
setOffline();
try {
if (diff.isEmpty()) {
logger.info("no changes detected - no migration written");
return;
}
// there were actually changes to write
Migration dbMigration = diff.getMigration();
String version = getVersion(migrationModel);
logger.info("generating migration:{}", version);
if (!writeMigration(dbMigration, version)) {
logger.warn("migration already exists, not generating DDL");
} else {
if (databasePlatform != null) {
// writer needs the current model to provide table/column details for
// history ddl generation (triggers, history tables etc)
DdlWrite write = new DdlWrite(new MConfiguration(), currentModel.read());
PlatformDdlWriter writer = createDdlWriter();
writer.processMigration(dbMigration, write);
}
}
} finally {
if (!online) {
DbOffline.reset();
}
}
}
/**
* {@inheritDoc}
*/
@Override
protected void writeExtraPlatformDdl(String fullVersion, CurrentModel currentModel,
Migration dbMigration, File writePath) throws IOException {
throw new UnsupportedOperationException("writeExtraPlatformDdl Unsupported");
}
/**
* {@inheritDoc}
*/
protected boolean writeMigrationXml(Migration dbMigration, File resourcePath, String fullVersion) {
throw new UnsupportedOperationException("writeExtraPlatformDdl Unsupported");
}
/**
* <p>writeMigration.</p>
*
* @param dbMigration a {@link io.ebean.dbmigration.migration.Migration} object.
* @param version a {@link java.lang.String} object.
* @return a boolean.
*/
protected boolean writeMigration(Migration dbMigration, String version) {
if (migrationModel.isMigrationTableExist()) {
scriptInfo = server.find(ScriptInfo.class, version);
if (scriptInfo != null) {
return false;
}
}
scriptInfo = new ScriptInfo();
scriptInfo.setRevision(version);
try (StringWriter writer = new StringWriter()) {
JAXBContext jaxbContext = JAXBContext.newInstance(Migration.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(dbMigration, writer);
writer.flush();
scriptInfo.setModelDiff(writer.toString());
} catch (JAXBException | IOException e) {
throw new RuntimeException(e);
}
return true;
}
/**
* <p>createDdlWriter.</p>
*
* @return a {@link ameba.db.ebean.migration.PlatformDdlWriter} object.
*/
protected PlatformDdlWriter createDdlWriter() {
return new PlatformDdlWriter(scriptInfo, (SpiServer) server);
}
/**
* Return the full version for the migration being generated.
*/
private String getVersion(MigrationModel migrationModel) {
String version = migrationConfig.getVersion();
if (version == null) {
version = migrationModel.getNextVersion(initialVersion);
}
return version;
}
/**
* <p>rest.</p>
*
* @return a {@link io.ebean.dbmigration.model.ModelDiff} object.
*/
public ModelDiff rest() {
ModelDiff old = diff;
diff = null;
migrationModel = null;
currentModel = null;
scriptInfo = null;
return old;
}
/**
* <p>Getter for the field <code>scriptInfo</code>.</p>
*
* @return a {@link ameba.db.migration.models.ScriptInfo} object.
*/
public ScriptInfo getScriptInfo() {
return scriptInfo;
}
}