]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore.ui/src/org/simantics/db/procore/ui/internal/Handler.java
Switched from Eclipse 4.13 (2019-09) to 4.14 (2019-12).
[simantics/platform.git] / bundles / org.simantics.db.procore.ui / src / org / simantics / db / procore / ui / internal / Handler.java
index 214f53798a09c1916d19b1754a8366b5c0ddf37c..3dd9e4d73fbe65fd8d81ec342be7ff29b18d8434 100644 (file)
-package org.simantics.db.procore.ui.internal;\r
-\r
-import java.io.File;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.nio.file.Files;\r
-import java.nio.file.Path;\r
-import java.util.ArrayList;\r
-\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.jface.dialogs.ProgressMonitorDialog;\r
-import org.eclipse.jface.operation.IRunnableWithProgress;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.simantics.db.common.utils.Logger;\r
-import org.simantics.db.server.Auxiliary;\r
-import org.simantics.db.server.ProCoreException;\r
-\r
-abstract class Handler {\r
-    protected final String title = "Database Server";\r
-    abstract boolean start(Shell shell, ProCoreException e) throws ProCoreException;\r
-    protected void checkFolderGiven(Shell shell, ProCoreException e) throws ProCoreException {\r
-        if (null == e.getDbFolder()) {\r
-            String msg = "No database folder given.";\r
-            MessageDialog.openWarning(shell, title, msg);\r
-            throw new ProCoreException(msg);\r
-        }\r
-    }\r
-}\r
-final class DefaultHandler extends Handler {\r
-    @Override\r
-    boolean start(Shell shell, ProCoreException e) throws ProCoreException {\r
-        String warning = Util.getMessage(e);\r
-        MessageDialog.openError(shell, title, warning);\r
-        return false;\r
-    }\r
-}\r
-final class GuardFileVersionHandler extends Handler {\r
-    @Override\r
-    boolean start(Shell shell, ProCoreException e) throws ProCoreException {\r
-        checkFolderGiven(shell, e);\r
-        return HandlerUtil.recoverFromGuardFileVersion(shell, e.getDbFolder(), title, e.getMessage());\r
-    }\r
-}\r
-final class DatabaseCorruptedHandler extends Handler {\r
-    @Override\r
-    boolean start(Shell shell, ProCoreException e) throws ProCoreException {\r
-        checkFolderGiven(shell, e);\r
-        return HandlerUtil.recoverFromJournal(shell, e.getDbFolder(), title, e.getMessage());\r
-    }\r
-}\r
-final class DatabaseLastExitHandler extends Handler {\r
-    @Override\r
-    boolean start(Shell shell, ProCoreException e) throws ProCoreException {\r
-        checkFolderGiven(shell, e);\r
-        return HandlerUtil.recoverFromDatabaseLastExit(shell, e.getDbFolder(), title, e.getMessage());\r
-\r
-    }\r
-}\r
-final class DatabaseProtocolHandler extends Handler {\r
-    @Override\r
-    boolean start(Shell shell, ProCoreException e) throws ProCoreException {\r
-        checkFolderGiven(shell, e);\r
-        return HandlerUtil.recoverFromProtocol(shell, e.getDbFolder(), title, e.getMessage());\r
-\r
-    }\r
-}\r
-final class DatabaseStartHandler extends Handler {\r
-    @Override\r
-    boolean start(Shell shell, ProCoreException e) throws ProCoreException {\r
-        checkFolderGiven(shell, e);\r
-        String warning =  e.getMessage();\r
-        MessageDialog.openError(shell, title, warning);\r
-        return false;\r
-    }\r
-}\r
-final class DatabaseVersionHandler extends Handler {\r
-    @Override\r
-    boolean start(Shell shell, ProCoreException e) throws ProCoreException {\r
-        checkFolderGiven(shell, e);\r
-        return HandlerUtil.recoverFromDatabaseVersion(shell, e.getDbFolder(), title, e.getMessage());\r
-    }\r
-}\r
-class HandlerUtil {\r
-    private static String NL = System.getProperty("line.separator");\r
-    private static boolean isFolder(final Shell shell, final File dbFolder, String title) {\r
-        if (dbFolder.isDirectory())\r
-            return true;\r
-        MessageDialog.openWarning(shell, title, "Database folder does not exist. folder=" + dbFolder);\r
-        return false;\r
-    }\r
-    public static boolean saveWithQuestion(final Shell shell, final File dbFolder, String title, String msg) {\r
-        if (!isFolder(shell, dbFolder, title))\r
-            return false; // Save not possible.\r
-        String question = ((null != msg) ? (msg + NL) : "")\r
-        + "Do you want to save database?" + NL + "folder=" + dbFolder;\r
-        boolean yes = MessageDialog.openQuestion(shell, title, question);\r
-        if (!yes)\r
-            return true;\r
-        final class SaveDatabase extends ExecutorDatabase {\r
-            Path saveFolder;\r
-            SaveDatabase(File dbFolder) {\r
-                super(dbFolder);\r
-                beginMessage = "Saving database.";\r
-                okMessage = "Database has been saved.";\r
-                failMessage = "Failed to save database.";\r
-                cancelMessage = "Save cancelled.";\r
-            }\r
-            @Override\r
-            public void execute() throws Throwable {\r
-                saveFolder = Auxiliary.saveDatabase(dbFolder);\r
-                if (null == saveFolder || !Files.isDirectory(saveFolder))\r
-                    throw new ProCoreException("Save folder not ok.");\r
-            }\r
-            @Override\r
-            public String getMessage() {\r
-                return NL + "folder=" + saveFolder;\r
-            }\r
-        }\r
-        SaveDatabase save = new SaveDatabase(dbFolder);\r
-        execute(shell, save);\r
-        save.showDone(shell);\r
-        return save.ok;\r
-    }\r
-    static boolean saveWithCheck(final Shell shell, final File dbFolder, String title, String msg) {\r
-        boolean ok = saveWithQuestion(shell, dbFolder, title, msg);\r
-        if (ok)\r
-            return true;\r
-        String question = "Save failed. Do you want me to contine?";\r
-        return Util.confirm(shell, title, question);\r
-    }\r
-\r
-    public static boolean delete(final Shell shell, final File dbFolder, String title, String msg) {\r
-        if (!isFolder(shell, dbFolder, title))\r
-            return false; // Delete not possible.\r
-        String question = ((null != msg) ? (msg + NL) : "")\r
-        + "Do you want to delete database?" + NL + "folder=" + dbFolder;\r
-        boolean yes = MessageDialog.openQuestion(shell, title, question);\r
-        if (!yes)\r
-            return false;\r
-        saveWithQuestion(shell, dbFolder, title,  null);\r
-        final class DeleteDatabase extends ExecutorDatabase {\r
-            DeleteDatabase(File dbFolder) {\r
-                super(dbFolder);\r
-                beginMessage = "Deleting database.";\r
-                okMessage = "Database has been deleted.";\r
-                failMessage = "Failed to delete database.";\r
-                cancelMessage = "Delete cancelled.";\r
-            }\r
-            @Override\r
-            public void execute() throws Throwable {\r
-                Auxiliary.deleteDatabase(dbFolder);\r
-            }\r
-        }\r
-        DeleteDatabase delete = new DeleteDatabase(dbFolder);\r
-        execute(shell, delete);\r
-        delete.showDone(shell);\r
-        return delete.ok;\r
-    }\r
-    public static boolean purge(final Shell shell, final File dbFolder, String title, String msg) {\r
-        if (!isFolder(shell, dbFolder, title))\r
-            return false; // Purge not possible.\r
-        try {\r
-            if (Auxiliary.purgeDatabaseDone(dbFolder)) {\r
-                MessageDialog.openInformation(shell, title, "Database already purged." + NL + "folder=" + dbFolder);\r
-                return true; // Already clean.\r
-            }\r
-        } catch (ProCoreException e) {\r
-            Logger.defaultLogError("Failed to query database purge state.", e);\r
-        }\r
-        String question = ((null != msg) ? (msg + NL) : "")\r
-        + "Do you want to purge database?";\r
-        boolean yes = MessageDialog.openQuestion(shell, title, question);\r
-        if (!yes)\r
-            return false;\r
-        return purgeWithSave(shell, dbFolder, title);\r
-    }\r
-    private static boolean purgeWithSave(final Shell shell, final File dbFolder, String title) {\r
-        boolean ok = saveWithCheck(shell, dbFolder, title, null);\r
-        if (!ok)\r
-            return false;\r
-        final class PurgeDatabase extends ExecutorDatabase {\r
-            PurgeDatabase(File dbFolder) {\r
-                super(dbFolder);\r
-                beginMessage = "Purging database.";\r
-                okMessage = "Database has been purged.";\r
-                failMessage = "Failed to purge database.";\r
-                cancelMessage = "Purge cancelled.";\r
-            }\r
-            @Override\r
-            public void execute() throws Throwable {\r
-                Auxiliary.purgeDatabase(dbFolder);\r
-            }\r
-        }\r
-        PurgeDatabase purge = new PurgeDatabase(dbFolder);\r
-        execute(shell, purge);\r
-        purge.showDone(shell);\r
-        return purge.ok;\r
-    }\r
-    public static boolean recoverFromGuardFileVersion(final Shell shell, final File dbFolder, String title, String msg)\r
-    throws ProCoreException {\r
-        String question = ((null != msg) ? msg : "")\r
-        + NL + "Guard file version mismatch indicates that the database was made with different server version."\r
-        + "It would be best to open the database with the same version it was made.";\r
-        MessageDialog.openWarning(shell, title, question);\r
-        return false;\r
-    }\r
-    public static boolean recoverFromDatabaseLastExit(final Shell shell, final File dbFolder, String title, String msg)\r
-    throws ProCoreException {\r
-        String message = ((null != msg) ? msg : "") + NL + "What should I try to do?";\r
-        ArrayList<Util.Choice> choices = new ArrayList<Util.Choice>();\r
-        choices.add(new Util.Choice("Cancel", "Cancel i.e. do nothing. Choose this if you want to manually analyze and correct the situation. This is the safest choice."));\r
-        choices.add(new Util.Choice("Ignore", "Ignore the exit status. Choose this if you do not know what you are doing. This is fast way to recover and is the safest choice except for cancel."));\r
-        choices.add(new Util.Choice("Remove", "Remove history. Choose this you know what you are doing. This is fast way to recover but can leave tricky semantic errors in the database. Furhermore, depending on the reason for the non clean exit status, this can fail and corrupt data. However, depending on how the client and/or server died, this could be the right choice."));\r
-        choices.add(new Util.Choice("Recover", "Recover using journal. Choose this if you are willing to wait and know that the other choices won't work."));\r
-        Util.Choice[] t = new Util.Choice[choices.size()];\r
-        int choice = Util.select(shell, title, message, choices.toArray(t), 0);\r
-        switch (choice) {\r
-            default: return false;\r
-            case 1: return ignoreExitStatusWithSave(shell, dbFolder, title);\r
-            case 2: return purgeWithSave(shell, dbFolder, title);\r
-            case 3: return recoverFromJournalWithSave(shell, dbFolder, title);\r
-        }\r
-    }\r
-    public static boolean ignoreExitStatusWithSave(final Shell shell, final File dbFolder, String title) {\r
-        boolean ok = saveWithCheck(shell, dbFolder, title, null);\r
-        if (!ok)\r
-            return false;\r
-        final class IgnoreExitDatabase extends ExecutorDatabase {\r
-            IgnoreExitDatabase(File dbFolder) {\r
-                super(dbFolder);\r
-                beginMessage = "Ignoring last exit status.";\r
-                okMessage = "Ignore done.";\r
-                failMessage = "Failed to start.";\r
-                cancelMessage = "Ignore cancelled.";\r
-            }\r
-            @Override\r
-            public void execute() throws Throwable {\r
-                Auxiliary.ignoreExit(dbFolder);\r
-            }\r
-        }\r
-        IgnoreExitDatabase recover = new IgnoreExitDatabase(dbFolder);\r
-        execute(shell, recover);\r
-        recover.showDone(shell);\r
-        return recover.ok;\r
-    }\r
-    public static boolean ignoreProtocolVersionWithSave(final Shell shell, final File dbFolder, String title) {\r
-        boolean ok = saveWithCheck(shell, dbFolder, title, null);\r
-        if (!ok)\r
-            return false;\r
-        final class IgnoreProtocolDatabase extends ExecutorDatabase {\r
-            IgnoreProtocolDatabase(File dbFolder) {\r
-                super(dbFolder);\r
-                beginMessage = "Ignoring protocol version mismatch.";\r
-                okMessage = "Ignore done.";\r
-                failMessage = "Failed to start.";\r
-                cancelMessage = "Ignore cancelled.";\r
-            }\r
-            @Override\r
-            public void execute() throws Throwable {\r
-                Auxiliary.ignoreProtocol(dbFolder);\r
-            }\r
-        }\r
-        IgnoreProtocolDatabase ignore = new IgnoreProtocolDatabase(dbFolder);\r
-        execute(shell, ignore);\r
-        ignore.showDone(shell);\r
-        return ignore.ok;\r
-    }\r
-    public static boolean recoverFromProtocol(final Shell shell, final File dbFolder, String title, String msg)\r
-    throws ProCoreException {\r
-        String question = ((null != msg) ? msg : "")\r
-        + NL + "Protocol version mismatch indicates that server and client versions differ."\r
-        + " It would be best to open the database using the same server and client version."\r
-        + " But if you insist I can ignore the mismatch and try to muddle along."\r
-        + " If this works then you should export the data and get matching client and server versions."\r
-        + " Otherwise there could later be strange errors caused by this version mismatch."\r
-        + " Shoud I try?";\r
-        boolean yes = Util.openDefaultNo(shell, title, question, MessageDialog.QUESTION);\r
-        if (!yes)\r
-            return false;\r
-        return ignoreProtocolVersionWithSave(shell, dbFolder, title);\r
-    }\r
-//    public static boolean recoverFromProtocolWithSave(final Shell shell, final File dbFolder, String title) {\r
-//        boolean ok = saveWithCheck(shell, dbFolder, title, null);\r
-//        if (!ok)\r
-//            return false;\r
-//        return ignoreProtocolVersionWithSave(shell, dbFolder, title);\r
-//    }\r
-    public static boolean recoverFromDatabaseVersion(final Shell shell, final File dbFolder, String title, String msg)\r
-    throws ProCoreException {\r
-        String question = ((null != msg) ? msg : "")\r
-        + NL + "Database version mismatch indicates that the database was made with different server version."\r
-        + " It would be best to open the database with the same version it was made."\r
-        + " But if you insist I can try to recover database from journal.";\r
-        boolean yes = Util.openDefaultNo(shell, title, question, MessageDialog.QUESTION);\r
-        if (!yes)\r
-            return false;\r
-        return recoverFromJournalWithSave(shell, dbFolder, title);\r
-    }\r
-    public static boolean recoverFromJournal(final Shell shell, final File dbFolder, String title, String msg)\r
-    throws ProCoreException {\r
-        if (!isFolder(shell, dbFolder, title))\r
-            return false; // Recovery not possible.\r
-        if (!Auxiliary.canReadJournal(dbFolder)) {\r
-            MessageDialog.openWarning(shell, title, "Journal file does not exist or isn't readable." + NL + "folder=" + dbFolder);\r
-            return false; // Recovery not possible.\r
-        }\r
-        String question = ((null != msg) ? msg : "")\r
-        + NL + "Do you want me to try to recreate the database from journal?";\r
-        boolean yes = MessageDialog.openQuestion(shell, title, question);\r
-        if (!yes)\r
-            return false;\r
-        return recoverFromJournalWithSave(shell, dbFolder, title);\r
-    }\r
-    public static boolean recoverFromJournalWithSave(final Shell shell, final File dbFolder, String title) {\r
-        boolean ok = saveWithCheck(shell, dbFolder, title, null);\r
-        if (!ok)\r
-            return false;\r
-        final class RecoverDatabase extends ExecutorDatabase {\r
-            RecoverDatabase(File dbFolder) {\r
-                super(dbFolder);\r
-                beginMessage = "Recovering database.";\r
-                okMessage = "Database has been recovered.";\r
-                failMessage = "Failed to recover database.";\r
-                cancelMessage = "Recovery cancelled.";\r
-            }\r
-            @Override\r
-            public void execute() throws Throwable {\r
-                Auxiliary.replaceFromJournal(dbFolder);\r
-            }\r
-        }\r
-        RecoverDatabase recover = new RecoverDatabase(dbFolder);\r
-        execute(shell, recover);\r
-        recover.showDone(shell);\r
-        return recover.ok;\r
-    }\r
-    private static void sleep(long millsec) throws InterruptedException {\r
-        Display display = UI.getDisplay();\r
-        boolean isUIThread = (null == display) ? false : (Thread.currentThread() == display.getThread());\r
-        Thread.sleep(100);\r
-        if (!isUIThread)\r
-            return;\r
-        int count = 0;\r
-        while (++count < 1000 && display.readAndDispatch())\r
-            continue;\r
-    }\r
-    interface Executor extends Runnable {\r
-        public String getMessageBegin();\r
-        public String getMessageCancel();\r
-        public String getMessageFail(Throwable throwable);\r
-        public String getMessageFail();\r
-        public String getMessageOk();\r
-        public boolean isDone();\r
-        public boolean isForkable();\r
-        public boolean isCancelable();\r
-        public void execute() throws Throwable;\r
-        public void setCancelled();\r
-        public void setDone();\r
-        public void showDone(Shell shell);\r
-    }\r
-    static abstract class ExecutorBase implements Executor {\r
-        protected String beginMessage = "Task begin.";\r
-        protected String okMessage = "Task ok.";\r
-        protected String failMessage = "Task failed.";\r
-        protected String cancelMessage = "Task cancelled.";\r
-        protected boolean done = false;\r
-        protected boolean ok = false;\r
-        protected boolean cancelled = false;\r
-        protected boolean forkable = true;\r
-        protected boolean cancelable = false;\r
-        protected Throwable throwable = null;\r
-        public void run() {\r
-            try {\r
-                execute();\r
-                ok = true;\r
-            } catch (Throwable t) {\r
-                throwable = t;\r
-            } finally {\r
-                done = true;\r
-           }\r
-        }\r
-        @Override\r
-        public String getMessageBegin() {\r
-            return beginMessage;\r
-        }\r
-        @Override\r
-        public String getMessageCancel() {\r
-            return cancelMessage;\r
-        }\r
-        @Override\r
-        public String getMessageFail(Throwable throwable) {\r
-            return failMessage + NL + throwable.getMessage();\r
-        }\r
-        @Override\r
-        public String getMessageFail() {\r
-            return failMessage;\r
-        }\r
-        @Override\r
-        public String getMessageOk() {\r
-            return okMessage;\r
-        }\r
-        @Override\r
-        public boolean isDone() {\r
-            return done;\r
-        }\r
-        @Override\r
-        public void setCancelled() {\r
-            cancelled = true;\r
-        }\r
-        @Override\r
-        public void setDone() {\r
-            done = true;\r
-        }\r
-        @Override\r
-        public boolean isForkable() {\r
-            return forkable;\r
-        }\r
-        @Override\r
-        public boolean isCancelable() {\r
-            return cancelable;\r
-        }\r
-        @Override\r
-        public void showDone(Shell shell) {\r
-            if (null != throwable)\r
-                Util.showError(shell, getMessageFail(throwable));\r
-            else if (ok)\r
-                Util.showInfo(shell, getMessageOk());\r
-            else if (cancelled)\r
-                Util.showInfo(shell, getMessageCancel());\r
-            else\r
-                Util.showWarning(shell, getMessageFail());\r
-        }\r
-    }\r
-    static abstract class ExecutorDatabase extends ExecutorBase {\r
-        protected final File dbFolder;\r
-        ExecutorDatabase(File dbFolder) {\r
-            this.dbFolder = dbFolder;\r
-        }\r
-        String getMessage() {\r
-            return NL + "folder=" + dbFolder;\r
-        }\r
-        @Override\r
-        public String getMessageBegin() {\r
-            return super.getMessageBegin() + getMessage();\r
-        }\r
-        @Override\r
-        public String getMessageCancel() {\r
-            return super.getMessageCancel() + getMessage();\r
-        }\r
-        @Override\r
-        public String getMessageFail(Throwable t) {\r
-            return super.getMessageFail(t) + getMessage();\r
-        }\r
-        @Override\r
-        public String getMessageOk() {\r
-            return super.getMessageOk() + getMessage();\r
-        }\r
-    }\r
-    private static void execute(final Shell shell, final Executor executor) {\r
-        final Thread thread = new Thread(executor);\r
-        thread.start();\r
-        IRunnableWithProgress progress = new IRunnableWithProgress() {\r
-            @Override\r
-            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r
-                try {\r
-                    monitor.beginTask(executor.getMessageBegin(), IProgressMonitor.UNKNOWN);\r
-                    while (!monitor.isCanceled() && !executor.isDone()) {\r
-                        monitor.worked(1);\r
-                        sleep(100);\r
-                    }\r
-                    if (executor.isDone())\r
-                        return;\r
-                    executor.setCancelled();\r
-                    thread.interrupt();\r
-                    monitor.subTask("Waiting for cancellation to finish.");\r
-                    while (!executor.isDone())\r
-                        sleep(100);\r
-                } finally {\r
-                    monitor.done();\r
-                }\r
-            }\r
-        };\r
-        boolean fork = executor.isForkable();\r
-        boolean cancelable = executor.isCancelable();\r
-        try {\r
-            new ProgressMonitorDialog(shell).run(fork, cancelable, progress);\r
-        } catch (InvocationTargetException e) {\r
-        } catch (InterruptedException e) {\r
-        }\r
-    }\r
+package org.simantics.db.procore.ui.internal;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.server.Auxiliary;
+import org.simantics.db.server.ProCoreException;
+
+abstract class Handler {
+    protected final String title = Messages.Handler_DatabaseServer;
+    abstract boolean start(Shell shell, ProCoreException e) throws ProCoreException;
+    protected void checkFolderGiven(Shell shell, ProCoreException e) throws ProCoreException {
+        if (null == e.getDbFolder()) {
+            String msg = Messages.Handler_NoDatabaseFolderGiven;
+            MessageDialog.openWarning(shell, title, msg);
+            throw new ProCoreException(msg);
+        }
+    }
+}
+final class DefaultHandler extends Handler {
+    @Override
+    boolean start(Shell shell, ProCoreException e) throws ProCoreException {
+        String warning = Util.getMessage(e);
+        MessageDialog.openError(shell, title, warning);
+        return false;
+    }
+}
+final class GuardFileVersionHandler extends Handler {
+    @Override
+    boolean start(Shell shell, ProCoreException e) throws ProCoreException {
+        checkFolderGiven(shell, e);
+        return HandlerUtil.recoverFromGuardFileVersion(shell, e.getDbFolder(), title, e.getMessage());
+    }
+}
+final class DatabaseCorruptedHandler extends Handler {
+    @Override
+    boolean start(Shell shell, ProCoreException e) throws ProCoreException {
+        checkFolderGiven(shell, e);
+        return HandlerUtil.recoverFromJournal(shell, e.getDbFolder(), title, e.getMessage());
+    }
+}
+final class DatabaseLastExitHandler extends Handler {
+    @Override
+    boolean start(Shell shell, ProCoreException e) throws ProCoreException {
+        checkFolderGiven(shell, e);
+        return HandlerUtil.recoverFromDatabaseLastExit(shell, e.getDbFolder(), title, e.getMessage());
+
+    }
+}
+final class DatabaseProtocolHandler extends Handler {
+    @Override
+    boolean start(Shell shell, ProCoreException e) throws ProCoreException {
+        checkFolderGiven(shell, e);
+        return HandlerUtil.recoverFromProtocol(shell, e.getDbFolder(), title, e.getMessage());
+
+    }
+}
+final class DatabaseStartHandler extends Handler {
+    @Override
+    boolean start(Shell shell, ProCoreException e) throws ProCoreException {
+        checkFolderGiven(shell, e);
+        String warning =  e.getMessage();
+        MessageDialog.openError(shell, title, warning);
+        return false;
+    }
+}
+final class DatabaseVersionHandler extends Handler {
+    @Override
+    boolean start(Shell shell, ProCoreException e) throws ProCoreException {
+        checkFolderGiven(shell, e);
+        return HandlerUtil.recoverFromDatabaseVersion(shell, e.getDbFolder(), title, e.getMessage());
+    }
+}
+class HandlerUtil {
+    private static String NL = System.getProperty("line.separator"); //$NON-NLS-1$
+    private static boolean isFolder(final Shell shell, final File dbFolder, String title) {
+        if (dbFolder.isDirectory())
+            return true;
+        MessageDialog.openWarning(shell, title, Messages.Handler_WarningMsgDatabaseFolderNotExists + dbFolder);
+        return false;
+    }
+    public static boolean saveWithQuestion(final Shell shell, final File dbFolder, String title, String msg) {
+        if (!isFolder(shell, dbFolder, title))
+            return false; // Save not possible.
+        String question = NLS.bind(Messages.Handler_SaveDatabase,new Object[] {((null != msg) ? (msg + NL) : ""),  //$NON-NLS-1$
+        NL , dbFolder}); 
+        boolean yes = MessageDialog.openQuestion(shell, title, question);
+        if (!yes)
+            return true;
+        final class SaveDatabase extends ExecutorDatabase {
+            Path saveFolder;
+            SaveDatabase(File dbFolder) {
+                super(dbFolder);
+                beginMessage = Messages.Handler_SavingDatabaseBeginMsg;
+                okMessage = Messages.Handler_SavingDatabaseOkMsg;
+                failMessage = Messages.Handler_SavingDatabaseFailMsg;
+                cancelMessage = Messages.Handler_SavingDatabaseCancelledMsg;
+            }
+            @Override
+            public void execute() throws Throwable {
+                saveFolder = Auxiliary.saveDatabase(dbFolder);
+                if (null == saveFolder || !Files.isDirectory(saveFolder))
+                    throw new ProCoreException("Save folder not ok."); //$NON-NLS-1$
+            }
+            @Override
+            public String getMessage() {
+                return NLS.bind( Messages.Handler_FolderEquals ,new Object[] { NL , saveFolder});
+            }
+        }
+        SaveDatabase save = new SaveDatabase(dbFolder);
+        execute(shell, save);
+        save.showDone(shell);
+        return save.ok;
+    }
+    static boolean saveWithCheck(final Shell shell, final File dbFolder, String title, String msg) {
+        boolean ok = saveWithQuestion(shell, dbFolder, title, msg);
+        if (ok)
+            return true;
+        String question = Messages.Handler_SaveContinue;
+        return Util.confirm(shell, title, question);
+    }
+
+    public static boolean delete(final Shell shell, final File dbFolder, String title, String msg) {
+        if (!isFolder(shell, dbFolder, title))
+            return false; // Delete not possible.
+        String question = NLS.bind(Messages.Handler_DeleteDatabase, new Object[] {((null != msg) ? (msg + NL) : ""), NL , dbFolder}); //$NON-NLS-1$
+        boolean yes = MessageDialog.openQuestion(shell, title, question);
+        if (!yes)
+            return false;
+        saveWithQuestion(shell, dbFolder, title,  null);
+        final class DeleteDatabase extends ExecutorDatabase {
+            DeleteDatabase(File dbFolder) {
+                super(dbFolder);
+                beginMessage = Messages.Handler_DeletingDatabase;
+                okMessage = Messages.Handler_DatabaseHasBeenDeleted;
+                failMessage = Messages.Handler_FailedDeleteDatabase;
+                cancelMessage = Messages.Handler_DeleteCancelled;
+            }
+            @Override
+            public void execute() throws Throwable {
+                Auxiliary.deleteDatabase(dbFolder);
+            }
+        }
+        DeleteDatabase delete = new DeleteDatabase(dbFolder);
+        execute(shell, delete);
+        delete.showDone(shell);
+        return delete.ok;
+    }
+    public static boolean purge(final Shell shell, final File dbFolder, String title, String msg) {
+        if (!isFolder(shell, dbFolder, title))
+            return false; // Purge not possible.
+        try {
+            if (Auxiliary.purgeDatabaseDone(dbFolder)) {
+                MessageDialog.openInformation(shell, title, NLS.bind(Messages.Handler_DatabaseAlreadyPurged, new Object[] { NL, dbFolder}));
+                return true; // Already clean.
+            }
+        } catch (ProCoreException e) {
+            Logger.defaultLogError("Failed to query database purge state.", e); //$NON-NLS-1$
+        }
+        String question = ((null != msg) ? (msg + NL) : "") //$NON-NLS-1$
+        + Messages.Handler_PurgeDatabaseQuestion;
+        boolean yes = MessageDialog.openQuestion(shell, title, question);
+        if (!yes)
+            return false;
+        return purgeWithSave(shell, dbFolder, title);
+    }
+    private static boolean purgeWithSave(final Shell shell, final File dbFolder, String title) {
+        boolean ok = saveWithCheck(shell, dbFolder, title, null);
+        if (!ok)
+            return false;
+        final class PurgeDatabase extends ExecutorDatabase {
+            PurgeDatabase(File dbFolder) {
+                super(dbFolder);
+                beginMessage = Messages.Handler_PurgingDatabase;
+                okMessage = Messages.Handler_DatabaseHasBeenPurged;
+                failMessage = Messages.Handler_FailedToPurgeDatabase;
+                cancelMessage = Messages.Handler_PurgeCancelled;
+            }
+            @Override
+            public void execute() throws Throwable {
+                Auxiliary.purgeDatabase(dbFolder);
+            }
+        }
+        PurgeDatabase purge = new PurgeDatabase(dbFolder);
+        execute(shell, purge);
+        purge.showDone(shell);
+        return purge.ok;
+    }
+    public static boolean recoverFromGuardFileVersion(final Shell shell, final File dbFolder, String title, String msg)
+    throws ProCoreException {
+        String question = NLS.bind(Messages.Handler_GuardFileMisMatchQuestion, new Object[] { ((null != msg) ? msg : ""),  //$NON-NLS-1$
+        NL}); 
+        MessageDialog.openWarning(shell, title, question);
+        return false;
+    }
+    public static boolean recoverFromDatabaseLastExit(final Shell shell, final File dbFolder, String title, String msg)
+    throws ProCoreException {
+        String message = NLS.bind(Messages.Handler_MessageWhatToDo, new Object[] {((null != msg) ? msg : "") , NL }) ;  //$NON-NLS-1$
+        ArrayList<Util.Choice> choices = new ArrayList<Util.Choice>();
+        choices.add(new Util.Choice(Messages.Handler_Cancel, Messages.Handler_CancelDescription));
+        choices.add(new Util.Choice(Messages.Handler_Ignore, Messages.Handler_IgnoreDescription));
+        choices.add(new Util.Choice(Messages.Handler_Remove, Messages.Handler_RemoveDescription));
+        choices.add(new Util.Choice(Messages.Handler_Recover, Messages.Handler_RecoverDescription));
+        Util.Choice[] t = new Util.Choice[choices.size()];
+        int choice = Util.select(shell, title, message, choices.toArray(t), 0);
+        switch (choice) {
+            default: return false;
+            case 1: return ignoreExitStatusWithSave(shell, dbFolder, title);
+            case 2: return purgeWithSave(shell, dbFolder, title);
+            case 3: return recoverFromJournalWithSave(shell, dbFolder, title);
+        }
+    }
+    public static boolean ignoreExitStatusWithSave(final Shell shell, final File dbFolder, String title) {
+        boolean ok = saveWithCheck(shell, dbFolder, title, null);
+        if (!ok)
+            return false;
+        final class IgnoreExitDatabase extends ExecutorDatabase {
+            IgnoreExitDatabase(File dbFolder) {
+                super(dbFolder);
+                beginMessage = Messages.Handler_IgnoreExitDatabaseBeginMsg;
+                okMessage = Messages.Handler_IgnoreExitDatabaseOkMsg;
+                failMessage = Messages.Handler_IgnoreExitDatabaseBeginFailMsg;
+                cancelMessage = Messages.Handler_IgnoreExitDatabaseCancelMsg;
+            }
+            @Override
+            public void execute() throws Throwable {
+                Auxiliary.ignoreExit(dbFolder);
+            }
+        }
+        IgnoreExitDatabase recover = new IgnoreExitDatabase(dbFolder);
+        execute(shell, recover);
+        recover.showDone(shell);
+        return recover.ok;
+    }
+    public static boolean ignoreProtocolVersionWithSave(final Shell shell, final File dbFolder, String title) {
+        boolean ok = saveWithCheck(shell, dbFolder, title, null);
+        if (!ok)
+            return false;
+        final class IgnoreProtocolDatabase extends ExecutorDatabase {
+            IgnoreProtocolDatabase(File dbFolder) {
+                super(dbFolder);
+                beginMessage = Messages.Handler_IgnoreProtocolDatabaseBeginMsg;
+                okMessage = Messages.Handler_IgnoreProtocolDatabaseOkMsg;
+                failMessage = Messages.Handler_IgnoreProtocolDatabaseFailMsg;
+                cancelMessage = Messages.Handler_IgnoreProtocolDatabaseCancelMsg;
+            }
+            @Override
+            public void execute() throws Throwable {
+                Auxiliary.ignoreProtocol(dbFolder);
+            }
+        }
+        IgnoreProtocolDatabase ignore = new IgnoreProtocolDatabase(dbFolder);
+        execute(shell, ignore);
+        ignore.showDone(shell);
+        return ignore.ok;
+    }
+    public static boolean recoverFromProtocol(final Shell shell, final File dbFolder, String title, String msg)
+    throws ProCoreException {
+        String question = ((null != msg) ? msg : "") + NL + Messages.Handler_ProCoreExceptionQuestion; //$NON-NLS-1$
+        boolean yes = Util.openDefaultNo(shell, title, question, MessageDialog.QUESTION);
+        if (!yes)
+            return false;
+        return ignoreProtocolVersionWithSave(shell, dbFolder, title);
+    }
+//    public static boolean recoverFromProtocolWithSave(final Shell shell, final File dbFolder, String title) {
+//        boolean ok = saveWithCheck(shell, dbFolder, title, null);
+//        if (!ok)
+//            return false;
+//        return ignoreProtocolVersionWithSave(shell, dbFolder, title);
+//    }
+    public static boolean recoverFromDatabaseVersion(final Shell shell, final File dbFolder, String title, String msg)
+    throws ProCoreException {
+        String question = ((null != msg) ? msg : "") + NL + Messages.Handler_ProCoreException2; //$NON-NLS-1$
+        boolean yes = Util.openDefaultNo(shell, title, question, MessageDialog.QUESTION);
+        if (!yes)
+            return false;
+        return recoverFromJournalWithSave(shell, dbFolder, title);
+    }
+    public static boolean recoverFromJournal(final Shell shell, final File dbFolder, String title, String msg)
+    throws ProCoreException {
+        if (!isFolder(shell, dbFolder, title))
+            return false; // Recovery not possible.
+        if (!Auxiliary.canReadJournal(dbFolder)) {
+            MessageDialog.openWarning(shell, title, NLS.bind(Messages.Handler_JournalFileNotExists ,new Object[] { NL , dbFolder})); 
+            return false; // Recovery not possible.
+        }
+        String question = ((null != msg) ? msg : "") //$NON-NLS-1$
+        + NL + Messages.Handler_RecreateDatabaseFromJournalQuestion;
+        boolean yes = MessageDialog.openQuestion(shell, title, question);
+        if (!yes)
+            return false;
+        return recoverFromJournalWithSave(shell, dbFolder, title);
+    }
+    public static boolean recoverFromJournalWithSave(final Shell shell, final File dbFolder, String title) {
+        boolean ok = saveWithCheck(shell, dbFolder, title, null);
+        if (!ok)
+            return false;
+        final class RecoverDatabase extends ExecutorDatabase {
+            RecoverDatabase(File dbFolder) {
+                super(dbFolder);
+                beginMessage = Messages.Handler_RecoveringDatabaseBeginMsg;
+                okMessage = Messages.Handler_RecoveringDatabaseRecoverdMsg;
+                failMessage = Messages.Handler_RecoveringDatabaseFailedMsg;
+                cancelMessage = Messages.Handler_RecoveringDatabaseCancelledMsg;
+            }
+            @Override
+            public void execute() throws Throwable {
+                Auxiliary.replaceFromJournal(dbFolder);
+            }
+        }
+        RecoverDatabase recover = new RecoverDatabase(dbFolder);
+        execute(shell, recover);
+        recover.showDone(shell);
+        return recover.ok;
+    }
+    private static void sleep(long millsec) throws InterruptedException {
+        Display display = UI.getDisplay();
+        boolean isUIThread = (null == display) ? false : (Thread.currentThread() == display.getThread());
+        Thread.sleep(100);
+        if (!isUIThread)
+            return;
+        int count = 0;
+        while (++count < 1000 && display.readAndDispatch())
+            continue;
+    }
+    interface Executor extends Runnable {
+        public String getMessageBegin();
+        public String getMessageCancel();
+        public String getMessageFail(Throwable throwable);
+        public String getMessageFail();
+        public String getMessageOk();
+        public boolean isDone();
+        public boolean isForkable();
+        public boolean isCancelable();
+        public void execute() throws Throwable;
+        public void setCancelled();
+        public void setDone();
+        public void showDone(Shell shell);
+    }
+    static abstract class ExecutorBase implements Executor {
+        protected String beginMessage = Messages.Handler_ExecutorBaseBeginMsg;
+        protected String okMessage = Messages.Handler_ExecutorBaseOkMsg;
+        protected String failMessage = Messages.Handler_ExecutorBaseFailedMsg;
+        protected String cancelMessage = Messages.Handler_ExecutorBaseCancelledMsg;
+        protected boolean done = false;
+        protected boolean ok = false;
+        protected boolean cancelled = false;
+        protected boolean forkable = true;
+        protected boolean cancelable = false;
+        protected Throwable throwable = null;
+        public void run() {
+            try {
+                execute();
+                ok = true;
+            } catch (Throwable t) {
+                throwable = t;
+            } finally {
+                done = true;
+           }
+        }
+        @Override
+        public String getMessageBegin() {
+            return beginMessage;
+        }
+        @Override
+        public String getMessageCancel() {
+            return cancelMessage;
+        }
+        @Override
+        public String getMessageFail(Throwable throwable) {
+            return failMessage + NL + throwable.getMessage();
+        }
+        @Override
+        public String getMessageFail() {
+            return failMessage;
+        }
+        @Override
+        public String getMessageOk() {
+            return okMessage;
+        }
+        @Override
+        public boolean isDone() {
+            return done;
+        }
+        @Override
+        public void setCancelled() {
+            cancelled = true;
+        }
+        @Override
+        public void setDone() {
+            done = true;
+        }
+        @Override
+        public boolean isForkable() {
+            return forkable;
+        }
+        @Override
+        public boolean isCancelable() {
+            return cancelable;
+        }
+        @Override
+        public void showDone(Shell shell) {
+            if (null != throwable)
+                Util.showError(shell, getMessageFail(throwable));
+            else if (ok)
+                Util.showInfo(shell, getMessageOk());
+            else if (cancelled)
+                Util.showInfo(shell, getMessageCancel());
+            else
+                Util.showWarning(shell, getMessageFail());
+        }
+    }
+    static abstract class ExecutorDatabase extends ExecutorBase {
+        protected final File dbFolder;
+        ExecutorDatabase(File dbFolder) {
+            this.dbFolder = dbFolder;
+        }
+        String getMessage() {
+            return NLS.bind( Messages.Handler_FolderEquals ,new Object[] { NL , dbFolder});
+        }
+        @Override
+        public String getMessageBegin() {
+            return super.getMessageBegin() + getMessage();
+        }
+        @Override
+        public String getMessageCancel() {
+            return super.getMessageCancel() + getMessage();
+        }
+        @Override
+        public String getMessageFail(Throwable t) {
+            return super.getMessageFail(t) + getMessage();
+        }
+        @Override
+        public String getMessageOk() {
+            return super.getMessageOk() + getMessage();
+        }
+    }
+    private static void execute(final Shell shell, final Executor executor) {
+        final Thread thread = new Thread(executor);
+        thread.start();
+        IRunnableWithProgress progress = new IRunnableWithProgress() {
+            @Override
+            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+                try {
+                    monitor.beginTask(executor.getMessageBegin(), IProgressMonitor.UNKNOWN);
+                    while (!monitor.isCanceled() && !executor.isDone()) {
+                        monitor.worked(1);
+                        sleep(100);
+                    }
+                    if (executor.isDone())
+                        return;
+                    executor.setCancelled();
+                    thread.interrupt();
+                    monitor.subTask(Messages.Handler_MonitorWaitingForCancellationToFinish);
+                    while (!executor.isDone())
+                        sleep(100);
+                } finally {
+                    monitor.done();
+                }
+            }
+        };
+        boolean fork = executor.isForkable();
+        boolean cancelable = executor.isCancelable();
+        try {
+            new ProgressMonitorDialog(shell).run(fork, cancelable, progress);
+        } catch (InvocationTargetException e) {
+        } catch (InterruptedException e) {
+        }
+    }
 }
\ No newline at end of file