]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore.ui/src/org/simantics/db/procore/ui/internal/Handler.java
3dd9e4d73fbe65fd8d81ec342be7ff29b18d8434
[simantics/platform.git] / bundles / org.simantics.db.procore.ui / src / org / simantics / db / procore / ui / internal / Handler.java
1 package org.simantics.db.procore.ui.internal;
2
3 import java.io.File;
4 import java.lang.reflect.InvocationTargetException;
5 import java.nio.file.Files;
6 import java.nio.file.Path;
7 import java.util.ArrayList;
8
9 import org.eclipse.core.runtime.IProgressMonitor;
10 import org.eclipse.jface.dialogs.MessageDialog;
11 import org.eclipse.jface.dialogs.ProgressMonitorDialog;
12 import org.eclipse.jface.operation.IRunnableWithProgress;
13 import org.eclipse.osgi.util.NLS;
14 import org.eclipse.swt.widgets.Display;
15 import org.eclipse.swt.widgets.Shell;
16 import org.simantics.db.common.utils.Logger;
17 import org.simantics.db.server.Auxiliary;
18 import org.simantics.db.server.ProCoreException;
19
20 abstract class Handler {
21     protected final String title = Messages.Handler_DatabaseServer;
22     abstract boolean start(Shell shell, ProCoreException e) throws ProCoreException;
23     protected void checkFolderGiven(Shell shell, ProCoreException e) throws ProCoreException {
24         if (null == e.getDbFolder()) {
25             String msg = Messages.Handler_NoDatabaseFolderGiven;
26             MessageDialog.openWarning(shell, title, msg);
27             throw new ProCoreException(msg);
28         }
29     }
30 }
31 final class DefaultHandler extends Handler {
32     @Override
33     boolean start(Shell shell, ProCoreException e) throws ProCoreException {
34         String warning = Util.getMessage(e);
35         MessageDialog.openError(shell, title, warning);
36         return false;
37     }
38 }
39 final class GuardFileVersionHandler extends Handler {
40     @Override
41     boolean start(Shell shell, ProCoreException e) throws ProCoreException {
42         checkFolderGiven(shell, e);
43         return HandlerUtil.recoverFromGuardFileVersion(shell, e.getDbFolder(), title, e.getMessage());
44     }
45 }
46 final class DatabaseCorruptedHandler extends Handler {
47     @Override
48     boolean start(Shell shell, ProCoreException e) throws ProCoreException {
49         checkFolderGiven(shell, e);
50         return HandlerUtil.recoverFromJournal(shell, e.getDbFolder(), title, e.getMessage());
51     }
52 }
53 final class DatabaseLastExitHandler extends Handler {
54     @Override
55     boolean start(Shell shell, ProCoreException e) throws ProCoreException {
56         checkFolderGiven(shell, e);
57         return HandlerUtil.recoverFromDatabaseLastExit(shell, e.getDbFolder(), title, e.getMessage());
58
59     }
60 }
61 final class DatabaseProtocolHandler extends Handler {
62     @Override
63     boolean start(Shell shell, ProCoreException e) throws ProCoreException {
64         checkFolderGiven(shell, e);
65         return HandlerUtil.recoverFromProtocol(shell, e.getDbFolder(), title, e.getMessage());
66
67     }
68 }
69 final class DatabaseStartHandler extends Handler {
70     @Override
71     boolean start(Shell shell, ProCoreException e) throws ProCoreException {
72         checkFolderGiven(shell, e);
73         String warning =  e.getMessage();
74         MessageDialog.openError(shell, title, warning);
75         return false;
76     }
77 }
78 final class DatabaseVersionHandler extends Handler {
79     @Override
80     boolean start(Shell shell, ProCoreException e) throws ProCoreException {
81         checkFolderGiven(shell, e);
82         return HandlerUtil.recoverFromDatabaseVersion(shell, e.getDbFolder(), title, e.getMessage());
83     }
84 }
85 class HandlerUtil {
86     private static String NL = System.getProperty("line.separator"); //$NON-NLS-1$
87     private static boolean isFolder(final Shell shell, final File dbFolder, String title) {
88         if (dbFolder.isDirectory())
89             return true;
90         MessageDialog.openWarning(shell, title, Messages.Handler_WarningMsgDatabaseFolderNotExists + dbFolder);
91         return false;
92     }
93     public static boolean saveWithQuestion(final Shell shell, final File dbFolder, String title, String msg) {
94         if (!isFolder(shell, dbFolder, title))
95             return false; // Save not possible.
96         String question = NLS.bind(Messages.Handler_SaveDatabase,new Object[] {((null != msg) ? (msg + NL) : ""),  //$NON-NLS-1$
97         NL , dbFolder}); 
98         boolean yes = MessageDialog.openQuestion(shell, title, question);
99         if (!yes)
100             return true;
101         final class SaveDatabase extends ExecutorDatabase {
102             Path saveFolder;
103             SaveDatabase(File dbFolder) {
104                 super(dbFolder);
105                 beginMessage = Messages.Handler_SavingDatabaseBeginMsg;
106                 okMessage = Messages.Handler_SavingDatabaseOkMsg;
107                 failMessage = Messages.Handler_SavingDatabaseFailMsg;
108                 cancelMessage = Messages.Handler_SavingDatabaseCancelledMsg;
109             }
110             @Override
111             public void execute() throws Throwable {
112                 saveFolder = Auxiliary.saveDatabase(dbFolder);
113                 if (null == saveFolder || !Files.isDirectory(saveFolder))
114                     throw new ProCoreException("Save folder not ok."); //$NON-NLS-1$
115             }
116             @Override
117             public String getMessage() {
118                 return NLS.bind( Messages.Handler_FolderEquals ,new Object[] { NL , saveFolder});
119             }
120         }
121         SaveDatabase save = new SaveDatabase(dbFolder);
122         execute(shell, save);
123         save.showDone(shell);
124         return save.ok;
125     }
126     static boolean saveWithCheck(final Shell shell, final File dbFolder, String title, String msg) {
127         boolean ok = saveWithQuestion(shell, dbFolder, title, msg);
128         if (ok)
129             return true;
130         String question = Messages.Handler_SaveContinue;
131         return Util.confirm(shell, title, question);
132     }
133
134     public static boolean delete(final Shell shell, final File dbFolder, String title, String msg) {
135         if (!isFolder(shell, dbFolder, title))
136             return false; // Delete not possible.
137         String question = NLS.bind(Messages.Handler_DeleteDatabase, new Object[] {((null != msg) ? (msg + NL) : ""), NL , dbFolder}); //$NON-NLS-1$
138         boolean yes = MessageDialog.openQuestion(shell, title, question);
139         if (!yes)
140             return false;
141         saveWithQuestion(shell, dbFolder, title,  null);
142         final class DeleteDatabase extends ExecutorDatabase {
143             DeleteDatabase(File dbFolder) {
144                 super(dbFolder);
145                 beginMessage = Messages.Handler_DeletingDatabase;
146                 okMessage = Messages.Handler_DatabaseHasBeenDeleted;
147                 failMessage = Messages.Handler_FailedDeleteDatabase;
148                 cancelMessage = Messages.Handler_DeleteCancelled;
149             }
150             @Override
151             public void execute() throws Throwable {
152                 Auxiliary.deleteDatabase(dbFolder);
153             }
154         }
155         DeleteDatabase delete = new DeleteDatabase(dbFolder);
156         execute(shell, delete);
157         delete.showDone(shell);
158         return delete.ok;
159     }
160     public static boolean purge(final Shell shell, final File dbFolder, String title, String msg) {
161         if (!isFolder(shell, dbFolder, title))
162             return false; // Purge not possible.
163         try {
164             if (Auxiliary.purgeDatabaseDone(dbFolder)) {
165                 MessageDialog.openInformation(shell, title, NLS.bind(Messages.Handler_DatabaseAlreadyPurged, new Object[] { NL, dbFolder}));
166                 return true; // Already clean.
167             }
168         } catch (ProCoreException e) {
169             Logger.defaultLogError("Failed to query database purge state.", e); //$NON-NLS-1$
170         }
171         String question = ((null != msg) ? (msg + NL) : "") //$NON-NLS-1$
172         + Messages.Handler_PurgeDatabaseQuestion;
173         boolean yes = MessageDialog.openQuestion(shell, title, question);
174         if (!yes)
175             return false;
176         return purgeWithSave(shell, dbFolder, title);
177     }
178     private static boolean purgeWithSave(final Shell shell, final File dbFolder, String title) {
179         boolean ok = saveWithCheck(shell, dbFolder, title, null);
180         if (!ok)
181             return false;
182         final class PurgeDatabase extends ExecutorDatabase {
183             PurgeDatabase(File dbFolder) {
184                 super(dbFolder);
185                 beginMessage = Messages.Handler_PurgingDatabase;
186                 okMessage = Messages.Handler_DatabaseHasBeenPurged;
187                 failMessage = Messages.Handler_FailedToPurgeDatabase;
188                 cancelMessage = Messages.Handler_PurgeCancelled;
189             }
190             @Override
191             public void execute() throws Throwable {
192                 Auxiliary.purgeDatabase(dbFolder);
193             }
194         }
195         PurgeDatabase purge = new PurgeDatabase(dbFolder);
196         execute(shell, purge);
197         purge.showDone(shell);
198         return purge.ok;
199     }
200     public static boolean recoverFromGuardFileVersion(final Shell shell, final File dbFolder, String title, String msg)
201     throws ProCoreException {
202         String question = NLS.bind(Messages.Handler_GuardFileMisMatchQuestion, new Object[] { ((null != msg) ? msg : ""),  //$NON-NLS-1$
203         NL}); 
204         MessageDialog.openWarning(shell, title, question);
205         return false;
206     }
207     public static boolean recoverFromDatabaseLastExit(final Shell shell, final File dbFolder, String title, String msg)
208     throws ProCoreException {
209         String message = NLS.bind(Messages.Handler_MessageWhatToDo, new Object[] {((null != msg) ? msg : "") , NL }) ;  //$NON-NLS-1$
210         ArrayList<Util.Choice> choices = new ArrayList<Util.Choice>();
211         choices.add(new Util.Choice(Messages.Handler_Cancel, Messages.Handler_CancelDescription));
212         choices.add(new Util.Choice(Messages.Handler_Ignore, Messages.Handler_IgnoreDescription));
213         choices.add(new Util.Choice(Messages.Handler_Remove, Messages.Handler_RemoveDescription));
214         choices.add(new Util.Choice(Messages.Handler_Recover, Messages.Handler_RecoverDescription));
215         Util.Choice[] t = new Util.Choice[choices.size()];
216         int choice = Util.select(shell, title, message, choices.toArray(t), 0);
217         switch (choice) {
218             default: return false;
219             case 1: return ignoreExitStatusWithSave(shell, dbFolder, title);
220             case 2: return purgeWithSave(shell, dbFolder, title);
221             case 3: return recoverFromJournalWithSave(shell, dbFolder, title);
222         }
223     }
224     public static boolean ignoreExitStatusWithSave(final Shell shell, final File dbFolder, String title) {
225         boolean ok = saveWithCheck(shell, dbFolder, title, null);
226         if (!ok)
227             return false;
228         final class IgnoreExitDatabase extends ExecutorDatabase {
229             IgnoreExitDatabase(File dbFolder) {
230                 super(dbFolder);
231                 beginMessage = Messages.Handler_IgnoreExitDatabaseBeginMsg;
232                 okMessage = Messages.Handler_IgnoreExitDatabaseOkMsg;
233                 failMessage = Messages.Handler_IgnoreExitDatabaseBeginFailMsg;
234                 cancelMessage = Messages.Handler_IgnoreExitDatabaseCancelMsg;
235             }
236             @Override
237             public void execute() throws Throwable {
238                 Auxiliary.ignoreExit(dbFolder);
239             }
240         }
241         IgnoreExitDatabase recover = new IgnoreExitDatabase(dbFolder);
242         execute(shell, recover);
243         recover.showDone(shell);
244         return recover.ok;
245     }
246     public static boolean ignoreProtocolVersionWithSave(final Shell shell, final File dbFolder, String title) {
247         boolean ok = saveWithCheck(shell, dbFolder, title, null);
248         if (!ok)
249             return false;
250         final class IgnoreProtocolDatabase extends ExecutorDatabase {
251             IgnoreProtocolDatabase(File dbFolder) {
252                 super(dbFolder);
253                 beginMessage = Messages.Handler_IgnoreProtocolDatabaseBeginMsg;
254                 okMessage = Messages.Handler_IgnoreProtocolDatabaseOkMsg;
255                 failMessage = Messages.Handler_IgnoreProtocolDatabaseFailMsg;
256                 cancelMessage = Messages.Handler_IgnoreProtocolDatabaseCancelMsg;
257             }
258             @Override
259             public void execute() throws Throwable {
260                 Auxiliary.ignoreProtocol(dbFolder);
261             }
262         }
263         IgnoreProtocolDatabase ignore = new IgnoreProtocolDatabase(dbFolder);
264         execute(shell, ignore);
265         ignore.showDone(shell);
266         return ignore.ok;
267     }
268     public static boolean recoverFromProtocol(final Shell shell, final File dbFolder, String title, String msg)
269     throws ProCoreException {
270         String question = ((null != msg) ? msg : "") + NL + Messages.Handler_ProCoreExceptionQuestion; //$NON-NLS-1$
271         boolean yes = Util.openDefaultNo(shell, title, question, MessageDialog.QUESTION);
272         if (!yes)
273             return false;
274         return ignoreProtocolVersionWithSave(shell, dbFolder, title);
275     }
276 //    public static boolean recoverFromProtocolWithSave(final Shell shell, final File dbFolder, String title) {
277 //        boolean ok = saveWithCheck(shell, dbFolder, title, null);
278 //        if (!ok)
279 //            return false;
280 //        return ignoreProtocolVersionWithSave(shell, dbFolder, title);
281 //    }
282     public static boolean recoverFromDatabaseVersion(final Shell shell, final File dbFolder, String title, String msg)
283     throws ProCoreException {
284         String question = ((null != msg) ? msg : "") + NL + Messages.Handler_ProCoreException2; //$NON-NLS-1$
285         boolean yes = Util.openDefaultNo(shell, title, question, MessageDialog.QUESTION);
286         if (!yes)
287             return false;
288         return recoverFromJournalWithSave(shell, dbFolder, title);
289     }
290     public static boolean recoverFromJournal(final Shell shell, final File dbFolder, String title, String msg)
291     throws ProCoreException {
292         if (!isFolder(shell, dbFolder, title))
293             return false; // Recovery not possible.
294         if (!Auxiliary.canReadJournal(dbFolder)) {
295             MessageDialog.openWarning(shell, title, NLS.bind(Messages.Handler_JournalFileNotExists ,new Object[] { NL , dbFolder})); 
296             return false; // Recovery not possible.
297         }
298         String question = ((null != msg) ? msg : "") //$NON-NLS-1$
299         + NL + Messages.Handler_RecreateDatabaseFromJournalQuestion;
300         boolean yes = MessageDialog.openQuestion(shell, title, question);
301         if (!yes)
302             return false;
303         return recoverFromJournalWithSave(shell, dbFolder, title);
304     }
305     public static boolean recoverFromJournalWithSave(final Shell shell, final File dbFolder, String title) {
306         boolean ok = saveWithCheck(shell, dbFolder, title, null);
307         if (!ok)
308             return false;
309         final class RecoverDatabase extends ExecutorDatabase {
310             RecoverDatabase(File dbFolder) {
311                 super(dbFolder);
312                 beginMessage = Messages.Handler_RecoveringDatabaseBeginMsg;
313                 okMessage = Messages.Handler_RecoveringDatabaseRecoverdMsg;
314                 failMessage = Messages.Handler_RecoveringDatabaseFailedMsg;
315                 cancelMessage = Messages.Handler_RecoveringDatabaseCancelledMsg;
316             }
317             @Override
318             public void execute() throws Throwable {
319                 Auxiliary.replaceFromJournal(dbFolder);
320             }
321         }
322         RecoverDatabase recover = new RecoverDatabase(dbFolder);
323         execute(shell, recover);
324         recover.showDone(shell);
325         return recover.ok;
326     }
327     private static void sleep(long millsec) throws InterruptedException {
328         Display display = UI.getDisplay();
329         boolean isUIThread = (null == display) ? false : (Thread.currentThread() == display.getThread());
330         Thread.sleep(100);
331         if (!isUIThread)
332             return;
333         int count = 0;
334         while (++count < 1000 && display.readAndDispatch())
335             continue;
336     }
337     interface Executor extends Runnable {
338         public String getMessageBegin();
339         public String getMessageCancel();
340         public String getMessageFail(Throwable throwable);
341         public String getMessageFail();
342         public String getMessageOk();
343         public boolean isDone();
344         public boolean isForkable();
345         public boolean isCancelable();
346         public void execute() throws Throwable;
347         public void setCancelled();
348         public void setDone();
349         public void showDone(Shell shell);
350     }
351     static abstract class ExecutorBase implements Executor {
352         protected String beginMessage = Messages.Handler_ExecutorBaseBeginMsg;
353         protected String okMessage = Messages.Handler_ExecutorBaseOkMsg;
354         protected String failMessage = Messages.Handler_ExecutorBaseFailedMsg;
355         protected String cancelMessage = Messages.Handler_ExecutorBaseCancelledMsg;
356         protected boolean done = false;
357         protected boolean ok = false;
358         protected boolean cancelled = false;
359         protected boolean forkable = true;
360         protected boolean cancelable = false;
361         protected Throwable throwable = null;
362         public void run() {
363             try {
364                 execute();
365                 ok = true;
366             } catch (Throwable t) {
367                 throwable = t;
368             } finally {
369                 done = true;
370            }
371         }
372         @Override
373         public String getMessageBegin() {
374             return beginMessage;
375         }
376         @Override
377         public String getMessageCancel() {
378             return cancelMessage;
379         }
380         @Override
381         public String getMessageFail(Throwable throwable) {
382             return failMessage + NL + throwable.getMessage();
383         }
384         @Override
385         public String getMessageFail() {
386             return failMessage;
387         }
388         @Override
389         public String getMessageOk() {
390             return okMessage;
391         }
392         @Override
393         public boolean isDone() {
394             return done;
395         }
396         @Override
397         public void setCancelled() {
398             cancelled = true;
399         }
400         @Override
401         public void setDone() {
402             done = true;
403         }
404         @Override
405         public boolean isForkable() {
406             return forkable;
407         }
408         @Override
409         public boolean isCancelable() {
410             return cancelable;
411         }
412         @Override
413         public void showDone(Shell shell) {
414             if (null != throwable)
415                 Util.showError(shell, getMessageFail(throwable));
416             else if (ok)
417                 Util.showInfo(shell, getMessageOk());
418             else if (cancelled)
419                 Util.showInfo(shell, getMessageCancel());
420             else
421                 Util.showWarning(shell, getMessageFail());
422         }
423     }
424     static abstract class ExecutorDatabase extends ExecutorBase {
425         protected final File dbFolder;
426         ExecutorDatabase(File dbFolder) {
427             this.dbFolder = dbFolder;
428         }
429         String getMessage() {
430             return NLS.bind( Messages.Handler_FolderEquals ,new Object[] { NL , dbFolder});
431         }
432         @Override
433         public String getMessageBegin() {
434             return super.getMessageBegin() + getMessage();
435         }
436         @Override
437         public String getMessageCancel() {
438             return super.getMessageCancel() + getMessage();
439         }
440         @Override
441         public String getMessageFail(Throwable t) {
442             return super.getMessageFail(t) + getMessage();
443         }
444         @Override
445         public String getMessageOk() {
446             return super.getMessageOk() + getMessage();
447         }
448     }
449     private static void execute(final Shell shell, final Executor executor) {
450         final Thread thread = new Thread(executor);
451         thread.start();
452         IRunnableWithProgress progress = new IRunnableWithProgress() {
453             @Override
454             public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
455                 try {
456                     monitor.beginTask(executor.getMessageBegin(), IProgressMonitor.UNKNOWN);
457                     while (!monitor.isCanceled() && !executor.isDone()) {
458                         monitor.worked(1);
459                         sleep(100);
460                     }
461                     if (executor.isDone())
462                         return;
463                     executor.setCancelled();
464                     thread.interrupt();
465                     monitor.subTask(Messages.Handler_MonitorWaitingForCancellationToFinish);
466                     while (!executor.isDone())
467                         sleep(100);
468                 } finally {
469                     monitor.done();
470                 }
471             }
472         };
473         boolean fork = executor.isForkable();
474         boolean cancelable = executor.isCancelable();
475         try {
476             new ProgressMonitorDialog(shell).run(fork, cancelable, progress);
477         } catch (InvocationTargetException e) {
478         } catch (InterruptedException e) {
479         }
480     }
481 }