Skip to content

Commit

Permalink
database evolutions
Browse files Browse the repository at this point in the history
  • Loading branch information
lichnost committed Mar 18, 2019
1 parent 0b46c47 commit ed2af5d
Show file tree
Hide file tree
Showing 47 changed files with 348 additions and 549 deletions.
4 changes: 2 additions & 2 deletions whirl-app/whirl-app-server/pom.xml
Expand Up @@ -190,8 +190,8 @@

<!-- Databases VCS -->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<groupId>io.github.gitbucket</groupId>
<artifactId>solidbase</artifactId>
</dependency>

<!-- Database -->
Expand Down
6 changes: 6 additions & 0 deletions whirl-app/whirl-app-server/src/conf/tomcat/context.xml
Expand Up @@ -26,6 +26,12 @@
value="${context.db.metadata.conectionWrapperClass}"
type="java.lang.String"
override="false"/>
<!-- Whirl apply evolutions -->
<Environment
name="Whirl/ds/metadata/evolutions/enabled"
value="true"
type="java.lang.Boolean"
override="false"/>
<!-- End Metadata datasource configuration-->


Expand Down
Expand Up @@ -6,6 +6,8 @@
import org.whirlplatform.server.db.TomcatConnectionProvider;
import org.whirlplatform.server.driver.Connector;
import org.whirlplatform.server.driver.multibase.MultibaseConnector;
import org.whirlplatform.server.evolution.EvolutionManager;
import org.whirlplatform.server.evolution.LiquibaseEvolutionManager;
import org.whirlplatform.server.login.AccountAuthenticator;
import org.whirlplatform.server.login.impl.DBAccountAuthenticator;
import org.whirlplatform.server.metadata.MetadataConfig;
Expand Down Expand Up @@ -44,6 +46,8 @@ protected void configure() {

bind(AccountAuthenticator.class).to(DBAccountAuthenticator.class); //TODO configuration.<String>lookup("Whirl/config/authenticator")

bind(EvolutionManager.class).to(LiquibaseEvolutionManager.class);

bind(Connector.class).to(MultibaseConnector.class);
}

Expand Down
@@ -0,0 +1,9 @@
package org.whirlplatform.server.evolution;

public class EvolutionException extends Exception {

public EvolutionException(Throwable cause) {
super(cause);
}

}
@@ -0,0 +1,9 @@
package org.whirlplatform.server.evolution;

public interface EvolutionManager {

void applyApplicationEvolution(String alias, String scriptPath) throws EvolutionException;

void applyMetadataEvolution(String alias, String scriptPath) throws EvolutionException;

}
@@ -0,0 +1,67 @@
package org.whirlplatform.server.evolution;

import liquibase.Contexts;
import liquibase.LabelExpression;
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.LiquibaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.resource.FileSystemResourceAccessor;
import liquibase.resource.ResourceAccessor;
import org.whirlplatform.server.config.Configuration;
import org.whirlplatform.server.db.ConnectException;
import org.whirlplatform.server.db.ConnectionProvider;
import org.whirlplatform.server.db.ConnectionWrapper;
import org.whirlplatform.server.log.Logger;
import org.whirlplatform.server.log.LoggerFactory;

import javax.inject.Inject;
import java.sql.SQLException;

public class LiquibaseEvolutionManager implements EvolutionManager {

private static Logger _log = LoggerFactory.getLogger(LiquibaseEvolutionManager.class);

private ConnectionProvider connectionProvider;
private Configuration configuration;

@Inject
public LiquibaseEvolutionManager(ConnectionProvider connectionProvider, Configuration configuration) {
this.connectionProvider = connectionProvider;
this.configuration = configuration;
}

@Override
public void applyApplicationEvolution(String alias, String scriptPath) throws EvolutionException {
applyEvolution(alias, scriptPath, new FileSystemResourceAccessor());
}

@Override
public void applyMetadataEvolution(String alias, String scriptPath) throws EvolutionException {
applyEvolution(alias, scriptPath, new ClassLoaderResourceAccessor());
}

private void applyEvolution(String alias, String scriptPath, ResourceAccessor resourceAccessor) throws EvolutionException {
Boolean applyEvolutions = configuration.<Boolean>lookup("Whirl/ds/" + alias
+ "/evolutions/enabled");
if (applyEvolutions == null || !applyEvolutions) {
return;
}

try (ConnectionWrapper connection = connectionProvider.getConnection(alias)) {
Database database = DatabaseFactory.getInstance()
.findCorrectDatabaseImplementation(new JdbcConnection(connection));

Liquibase liquibase = new liquibase.Liquibase(scriptPath, resourceAccessor,
database);

liquibase.update(new Contexts(), new LabelExpression());
} catch (LiquibaseException | SQLException | ConnectException e) {
_log.error(e);
throw new EvolutionException(e);
}
}

}
@@ -1,21 +1,16 @@
package org.whirlplatform.server.metadata;

import liquibase.Contexts;
import liquibase.LabelExpression;
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.LiquibaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.apache.empire.db.DBCmpType;
import org.apache.empire.db.DBCommand;
import org.apache.empire.db.DBReader;
import org.whirlplatform.rpc.shared.CustomException;
import org.whirlplatform.server.config.Configuration;
import org.whirlplatform.server.db.ConnectException;
import org.whirlplatform.server.db.ConnectionProvider;
import org.whirlplatform.server.db.ConnectionWrapper;
import org.whirlplatform.server.driver.db.MetadataDatabase;
import org.whirlplatform.server.evolution.EvolutionException;
import org.whirlplatform.server.evolution.EvolutionManager;
import org.whirlplatform.server.log.Logger;
import org.whirlplatform.server.log.LoggerFactory;
import org.whirlplatform.server.login.ApplicationUser;
Expand All @@ -29,22 +24,29 @@ public class MetadataProviderImpl implements MetadataProvider {

private static Logger _log = LoggerFactory.getLogger(MetadataProviderImpl.class);

private MetadataConfig config;
private MetadataConfig metadataConfig;

private MetadataDatabase database;

private ConnectionProvider connectionProvider;

private Configuration configuration;

private EvolutionManager evolutionManager;

@Inject
public MetadataProviderImpl(MetadataConfig config, ConnectionProvider connectionProvider) {
this.config = config;
public MetadataProviderImpl(MetadataConfig metadataConfig, ConnectionProvider connectionProvider,
Configuration configuration, EvolutionManager evolutionManager) {
this.metadataConfig = metadataConfig;
this.connectionProvider = connectionProvider;
this.configuration = configuration;
this.evolutionManager = evolutionManager;
database = MetadataDatabase.get();
}

protected ConnectionWrapper metadataConnection(ApplicationUser user) {
try {
return connectionProvider.getConnection(config.getMetadataAlias(), user);
return connectionProvider.getConnection(metadataConfig.getMetadataAlias(), user);
} catch (ConnectException e) {
_log.error(e);
throw new CustomException(e.getMessage());
Expand Down Expand Up @@ -116,7 +118,7 @@ public List<String> getUserGroups(ApplicationUser user) {

// @Override
// public void createDatabaseStructure() {
// String locationBase = "sql/";
// String locationBase = "org.whirlplatform.sql/";
// List<String> locations = new ArrayList<>();
// locations.add(locationBase + "common");
// try(ConnectionWrapper conn = metadataConnection()) {
Expand All @@ -132,7 +134,7 @@ public List<String> getUserGroups(ApplicationUser user) {
//
// try {
// Flyway flyway = new Flyway();
// flyway.setDataSource(connectionProvider.getDataSource(config.getMetadataAlias()));
// flyway.setDataSource(connectionProvider.getDataSource(metadataConfig.getMetadataAlias()));
// flyway.setLocations(locations.toArray(new String[0]));
// flyway.migrate();
// } catch (ConnectException e) {
Expand All @@ -157,18 +159,13 @@ public List<String> getUserGroups(ApplicationUser user) {

@Override
public void createDatabaseStructure() {
try (ConnectionWrapper connection = metadataConnection()) {
Database database = DatabaseFactory.getInstance()
.findCorrectDatabaseImplementation(new JdbcConnection(connection));

Liquibase liquibase = new liquibase.Liquibase("sql/changelog.xml", new ClassLoaderResourceAccessor(),
database);

liquibase.update(new Contexts(), new LabelExpression());
} catch (LiquibaseException | SQLException e) {
try {
evolutionManager.applyMetadataEvolution(metadataConfig.getMetadataAlias(), "org/whirlplatform/sql/changelog.xml");
} catch (EvolutionException e) {
_log.error(e);
throw new CustomException(e.getMessage());
}

}


}
Expand Up @@ -11,8 +11,11 @@
import org.whirlplatform.meta.shared.Version;
import org.whirlplatform.meta.shared.editor.ApplicationElement;
import org.whirlplatform.meta.shared.editor.FileElement;
import org.whirlplatform.meta.shared.editor.db.DataSourceElement;
import org.whirlplatform.server.compiler.CompilationData;
import org.whirlplatform.server.config.Configuration;
import org.whirlplatform.server.evolution.EvolutionException;
import org.whirlplatform.server.evolution.EvolutionManager;
import org.whirlplatform.server.log.Logger;
import org.whirlplatform.server.log.LoggerFactory;
import org.whirlplatform.server.metadata.store.MetadataModifiedHandler;
Expand Down Expand Up @@ -49,12 +52,15 @@ public class DefaultMetadataContainer implements MetadataContainer {
private Table<String, Version, Date> lastAccessTime = HashBasedTable.create();

private ExecutorService executorService;
private EvolutionManager evolutionManager;

@Inject
public DefaultMetadataContainer(Configuration configuration, MetadataStore metadataStore) {
public DefaultMetadataContainer(Configuration configuration, MetadataStore metadataStore,
EvolutionManager evolutionManager) {
this.metadataStore = metadataStore;
Integer timeout = configuration.<Integer>lookup("Whirl/cachetimeout");
this.cacheTimeout = (timeout == null) ? DEFAULT_CACHE_TIMEOUT_SECONDS : timeout;
this.evolutionManager = evolutionManager;
initTimerReload();
}

Expand Down Expand Up @@ -165,48 +171,74 @@ private void initApplicationReloadHandler(final String code, final Version versi
watchableStore.addModifiedHandler(code, version, new MetadataModifiedHandler() {
@Override
public void loaded(ApplicationElement app) {
_log.info(String.format("Reloading the application %s[%s], id=%s", app.getCode(), app.getVersion(),
app.getId()));
ApplicationReference reference = new ApplicationReference(app, initCompilationData(app));
_log.info(String.format("Updating the application cache: code=%s, version=%s", code,
version));
getCache(code, version).set(reference);
try {
reloadApplication(app, code, version);
} catch (EvolutionException e) {
_log.error(e.getMessage(), e);
}
}
});
} else {
_log.info("Current MetadataStore is not WatchableStore");
}
}

private AtomicReference<ApplicationReference> initialLoadApplication(String code, Version version) throws MetadataStoreException, EvolutionException {
ApplicationElement application = metadataStore.loadApplication(code, version);
CompilationData compilation = initCompilationData(application);
AtomicReference<ApplicationReference> result = new AtomicReference<>(new ApplicationReference(application, compilation));
applyDatabaseEvolutions(application, code, version);
putCache(code, version, result);
return result;
}

private void reloadApplication(ApplicationElement app, String code, Version version) throws EvolutionException {
_log.info(String.format("Reloading the application %s[%s], id=%s", app.getCode(), app.getVersion(),
app.getId()));
ApplicationReference reference = new ApplicationReference(app, initCompilationData(app));
_log.info(String.format("Updating the application cache: code=%s, version=%s", code,
version));
applyDatabaseEvolutions(app, code, version);
getCache(code, version).set(reference);
}

private void applyDatabaseEvolutions(ApplicationElement application, String code, Version version) throws EvolutionException {
if (metadataStore.getLastVersion(code).compareTo(version) == 0) {
for (DataSourceElement dataSource : application.getDataSources()) {
if (dataSource.getEvolution() == null) {
continue;
}
evolutionManager.applyApplicationEvolution(dataSource.getAlias(), dataSource.getEvolution().getInputStreamProvider().path());
}
}
}

@Override
public AtomicReference<ApplicationReference> getApplication(String code, Version version)
public AtomicReference<ApplicationReference> getApplication(String code, Version originalVersion)
throws ContainerException {
try {
Version lastVersion = version;
if (lastVersion == null) {
lastVersion = metadataStore.getLastVersion(code);
Version version = originalVersion;
if (version == null) {
version = metadataStore.getLastVersion(code);
}
final String strVersion = (lastVersion == null) ? "null" : lastVersion.toString();
final String strVersion = (version == null) ? "null" : version.toString();
_log.info(String.format("The last version of '%s' is [%s]", code, strVersion));
AtomicReference<ApplicationReference> result = getCache(code, lastVersion);
AtomicReference<ApplicationReference> result = getCache(code, version);
if (result == null) {
_log.info(String.format("The application %s[%s] was not cached", code, strVersion));
synchronized (cache) {
result = getCache(code, lastVersion);
result = getCache(code, version);
if (result == null) {
ApplicationElement application = metadataStore.loadApplication(code, lastVersion);
CompilationData compilation = initCompilationData(application);
result = new AtomicReference<>(new ApplicationReference(application, compilation));
putCache(code, lastVersion, result);
initApplicationReloadHandler(code, lastVersion);
initialLoadApplication(code, version);
initApplicationReloadHandler(code, version);
}
}
} else {
_log.info(String.format("The application %s[%s] was loaded from the cache", code, strVersion));
}
lastAccessTime.put(code, assureNotNull(lastVersion), new Date());
lastAccessTime.put(code, assureNotNull(version), new Date());
return result;
} catch (MetadataStoreException e) {
} catch (MetadataStoreException | EvolutionException e) {
final String message = String.format("Cannot load the application '%s' from container", code);
_log.error(message, e);
throw new ContainerException(message, e);
Expand Down

0 comments on commit ed2af5d

Please sign in to comment.