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; } }