package org.openlca.app.navigation.actions;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.PlatformUI;
import org.openlca.app.App;
import org.openlca.app.M;
import org.openlca.app.cloud.ui.commits.HistoryView;
import org.openlca.app.components.UpdateManager;
import org.openlca.app.db.Database;
import org.openlca.app.db.IDatabaseConfiguration;
import org.openlca.app.navigation.DatabaseElement;
import org.openlca.app.navigation.INavigationElement;
import org.openlca.app.navigation.Navigator;
import org.openlca.app.rcp.images.Icon;
import org.openlca.app.util.Editors;
import org.openlca.app.util.Question;
import org.openlca.core.database.IDatabase;
import org.openlca.updates.VersionState;
import org.openlca.updates.legacy.Upgrades;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Activates a database with a version check and possible upgrade.
*/
public class DatabaseActivateAction extends Action implements INavigationAction {
private Logger log = LoggerFactory.getLogger(getClass());
private IDatabaseConfiguration config;
public DatabaseActivateAction() {
setText(M.OpenDatabase);
setImageDescriptor(Icon.CONNECT.descriptor());
}
public DatabaseActivateAction(IDatabaseConfiguration config) {
this();
this.config = config;
}
@Override
public boolean accept(INavigationElement<?> element) {
if (!(element instanceof DatabaseElement))
return false;
DatabaseElement e = (DatabaseElement) element;
IDatabaseConfiguration config = e.getContent();
if (Database.isActive(config))
return false;
this.config = config;
return true;
}
@Override
public boolean accept(List<INavigationElement<?>> elements) {
return false;
}
@Override
public void run() {
if (Database.get() != null)
Editors.closeAll();
Activation activation = new Activation();
// App.run does not work as we have to show a modal dialog in the
// callback
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(activation);
ActivationCallback callback = new ActivationCallback(activation);
callback.run();
} catch (Exception e) {
log.error("Database activation failed", e);
}
}
private class Activation implements IRunnableWithProgress {
private VersionState versionState;
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
try {
monitor.beginTask(M.OpenDatabase, IProgressMonitor.UNKNOWN);
Database.close();
IDatabase database = Database.activate(config);
versionState = VersionState.checkVersion(database);
monitor.done();
} catch (Exception e) {
log.error("Failed to activate database", e);
}
}
}
private class ActivationCallback implements Runnable {
private Activation activation;
ActivationCallback(Activation activation) {
this.activation = activation;
}
@Override
public void run() {
if (activation == null)
return;
VersionState state = activation.versionState;
if (state == null || state == VersionState.ERROR) {
error(M.DatabaseVersionCheckFailed);
return;
}
handleVersionState(state);
}
private void handleVersionState(VersionState state) {
switch (state) {
case HIGHER_VERSION:
error(M.DatabaseNeedsUpdate);
break;
case NEEDS_UPGRADE:
askRunUpgrades();
break;
case NEEDS_UPDATE:
if (UpdateManager.openNewAndRequired()) {
refresh();
} else {
closeDatabase();
}
break;
case UP_TO_DATE:
refresh();
break;
default:
break;
}
}
private void refresh() {
Navigator.refresh();
if (Database.get() == null)
return;
INavigationElement<?> dbElem = Navigator.findElement(config);
INavigationElement<?> firstModelType = dbElem.getChildren().get(0);
Navigator.getInstance().getCommonViewer().reveal(firstModelType);
HistoryView.refresh();
}
private void error(String message) {
org.openlca.app.util.Error.showBox(M.CouldNotOpenDatabase, message);
closeDatabase();
}
private void askRunUpgrades() {
IDatabase db = Database.get();
boolean doIt = Question.ask(M.UpdateDatabase, M.UpdateDatabaseQuestion);
if (!doIt) {
closeDatabase();
return;
}
AtomicBoolean failed = new AtomicBoolean(false);
App.run(M.UpdateDatabase,
() -> runUpgrades(db, failed),
() -> {
closeDatabase();
DatabaseActivateAction.this.run();
});
}
private void runUpgrades(IDatabase db, AtomicBoolean failed) {
try {
Upgrades.runUpgrades(db);
db.getEntityFactory().getCache().evictAll();
} catch (Exception e) {
failed.set(true);
log.error("Failed to update database", e);
}
}
private void closeDatabase() {
try {
Database.close();
} catch (Exception e) {
log.error("failed to close the database");
} finally {
Navigator.refresh();
}
}
}
}