1 package org.simantics.db.procore.ui.internal;
4 import java.lang.reflect.InvocationTargetException;
5 import java.nio.file.Files;
6 import java.nio.file.Path;
7 import java.util.ArrayList;
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;
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);
31 final class DefaultHandler extends Handler {
33 boolean start(Shell shell, ProCoreException e) throws ProCoreException {
34 String warning = Util.getMessage(e);
35 MessageDialog.openError(shell, title, warning);
39 final class GuardFileVersionHandler extends Handler {
41 boolean start(Shell shell, ProCoreException e) throws ProCoreException {
42 checkFolderGiven(shell, e);
43 return HandlerUtil.recoverFromGuardFileVersion(shell, e.getDbFolder(), title, e.getMessage());
46 final class DatabaseCorruptedHandler extends Handler {
48 boolean start(Shell shell, ProCoreException e) throws ProCoreException {
49 checkFolderGiven(shell, e);
50 return HandlerUtil.recoverFromJournal(shell, e.getDbFolder(), title, e.getMessage());
53 final class DatabaseLastExitHandler extends Handler {
55 boolean start(Shell shell, ProCoreException e) throws ProCoreException {
56 checkFolderGiven(shell, e);
57 return HandlerUtil.recoverFromDatabaseLastExit(shell, e.getDbFolder(), title, e.getMessage());
61 final class DatabaseProtocolHandler extends Handler {
63 boolean start(Shell shell, ProCoreException e) throws ProCoreException {
64 checkFolderGiven(shell, e);
65 return HandlerUtil.recoverFromProtocol(shell, e.getDbFolder(), title, e.getMessage());
69 final class DatabaseStartHandler extends Handler {
71 boolean start(Shell shell, ProCoreException e) throws ProCoreException {
72 checkFolderGiven(shell, e);
73 String warning = e.getMessage();
74 MessageDialog.openError(shell, title, warning);
78 final class DatabaseVersionHandler extends Handler {
80 boolean start(Shell shell, ProCoreException e) throws ProCoreException {
81 checkFolderGiven(shell, e);
82 return HandlerUtil.recoverFromDatabaseVersion(shell, e.getDbFolder(), title, e.getMessage());
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())
90 MessageDialog.openWarning(shell, title, Messages.Handler_WarningMsgDatabaseFolderNotExists + dbFolder);
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$
98 boolean yes = MessageDialog.openQuestion(shell, title, question);
101 final class SaveDatabase extends ExecutorDatabase {
103 SaveDatabase(File dbFolder) {
105 beginMessage = Messages.Handler_SavingDatabaseBeginMsg;
106 okMessage = Messages.Handler_SavingDatabaseOkMsg;
107 failMessage = Messages.Handler_SavingDatabaseFailMsg;
108 cancelMessage = Messages.Handler_SavingDatabaseCancelledMsg;
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$
117 public String getMessage() {
118 return NLS.bind( Messages.Handler_FolderEquals ,new Object[] { NL , saveFolder});
121 SaveDatabase save = new SaveDatabase(dbFolder);
122 execute(shell, save);
123 save.showDone(shell);
126 static boolean saveWithCheck(final Shell shell, final File dbFolder, String title, String msg) {
127 boolean ok = saveWithQuestion(shell, dbFolder, title, msg);
130 String question = Messages.Handler_SaveContinue;
131 return Util.confirm(shell, title, question);
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);
141 saveWithQuestion(shell, dbFolder, title, null);
142 final class DeleteDatabase extends ExecutorDatabase {
143 DeleteDatabase(File dbFolder) {
145 beginMessage = Messages.Handler_DeletingDatabase;
146 okMessage = Messages.Handler_DatabaseHasBeenDeleted;
147 failMessage = Messages.Handler_FailedDeleteDatabase;
148 cancelMessage = Messages.Handler_DeleteCancelled;
151 public void execute() throws Throwable {
152 Auxiliary.deleteDatabase(dbFolder);
155 DeleteDatabase delete = new DeleteDatabase(dbFolder);
156 execute(shell, delete);
157 delete.showDone(shell);
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.
164 if (Auxiliary.purgeDatabaseDone(dbFolder)) {
165 MessageDialog.openInformation(shell, title, NLS.bind(Messages.Handler_DatabaseAlreadyPurged, new Object[] { NL, dbFolder}));
166 return true; // Already clean.
168 } catch (ProCoreException e) {
169 Logger.defaultLogError("Failed to query database purge state.", e); //$NON-NLS-1$
171 String question = ((null != msg) ? (msg + NL) : "") //$NON-NLS-1$
172 + Messages.Handler_PurgeDatabaseQuestion;
173 boolean yes = MessageDialog.openQuestion(shell, title, question);
176 return purgeWithSave(shell, dbFolder, title);
178 private static boolean purgeWithSave(final Shell shell, final File dbFolder, String title) {
179 boolean ok = saveWithCheck(shell, dbFolder, title, null);
182 final class PurgeDatabase extends ExecutorDatabase {
183 PurgeDatabase(File dbFolder) {
185 beginMessage = Messages.Handler_PurgingDatabase;
186 okMessage = Messages.Handler_DatabaseHasBeenPurged;
187 failMessage = Messages.Handler_FailedToPurgeDatabase;
188 cancelMessage = Messages.Handler_PurgeCancelled;
191 public void execute() throws Throwable {
192 Auxiliary.purgeDatabase(dbFolder);
195 PurgeDatabase purge = new PurgeDatabase(dbFolder);
196 execute(shell, purge);
197 purge.showDone(shell);
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$
204 MessageDialog.openWarning(shell, title, question);
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);
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);
224 public static boolean ignoreExitStatusWithSave(final Shell shell, final File dbFolder, String title) {
225 boolean ok = saveWithCheck(shell, dbFolder, title, null);
228 final class IgnoreExitDatabase extends ExecutorDatabase {
229 IgnoreExitDatabase(File dbFolder) {
231 beginMessage = Messages.Handler_IgnoreExitDatabaseBeginMsg;
232 okMessage = Messages.Handler_IgnoreExitDatabaseOkMsg;
233 failMessage = Messages.Handler_IgnoreExitDatabaseBeginFailMsg;
234 cancelMessage = Messages.Handler_IgnoreExitDatabaseCancelMsg;
237 public void execute() throws Throwable {
238 Auxiliary.ignoreExit(dbFolder);
241 IgnoreExitDatabase recover = new IgnoreExitDatabase(dbFolder);
242 execute(shell, recover);
243 recover.showDone(shell);
246 public static boolean ignoreProtocolVersionWithSave(final Shell shell, final File dbFolder, String title) {
247 boolean ok = saveWithCheck(shell, dbFolder, title, null);
250 final class IgnoreProtocolDatabase extends ExecutorDatabase {
251 IgnoreProtocolDatabase(File dbFolder) {
253 beginMessage = Messages.Handler_IgnoreProtocolDatabaseBeginMsg;
254 okMessage = Messages.Handler_IgnoreProtocolDatabaseOkMsg;
255 failMessage = Messages.Handler_IgnoreProtocolDatabaseFailMsg;
256 cancelMessage = Messages.Handler_IgnoreProtocolDatabaseCancelMsg;
259 public void execute() throws Throwable {
260 Auxiliary.ignoreProtocol(dbFolder);
263 IgnoreProtocolDatabase ignore = new IgnoreProtocolDatabase(dbFolder);
264 execute(shell, ignore);
265 ignore.showDone(shell);
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);
274 return ignoreProtocolVersionWithSave(shell, dbFolder, title);
276 // public static boolean recoverFromProtocolWithSave(final Shell shell, final File dbFolder, String title) {
277 // boolean ok = saveWithCheck(shell, dbFolder, title, null);
280 // return ignoreProtocolVersionWithSave(shell, dbFolder, title);
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);
288 return recoverFromJournalWithSave(shell, dbFolder, title);
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.
298 String question = ((null != msg) ? msg : "") //$NON-NLS-1$
299 + NL + Messages.Handler_RecreateDatabaseFromJournalQuestion;
300 boolean yes = MessageDialog.openQuestion(shell, title, question);
303 return recoverFromJournalWithSave(shell, dbFolder, title);
305 public static boolean recoverFromJournalWithSave(final Shell shell, final File dbFolder, String title) {
306 boolean ok = saveWithCheck(shell, dbFolder, title, null);
309 final class RecoverDatabase extends ExecutorDatabase {
310 RecoverDatabase(File dbFolder) {
312 beginMessage = Messages.Handler_RecoveringDatabaseBeginMsg;
313 okMessage = Messages.Handler_RecoveringDatabaseRecoverdMsg;
314 failMessage = Messages.Handler_RecoveringDatabaseFailedMsg;
315 cancelMessage = Messages.Handler_RecoveringDatabaseCancelledMsg;
318 public void execute() throws Throwable {
319 Auxiliary.replaceFromJournal(dbFolder);
322 RecoverDatabase recover = new RecoverDatabase(dbFolder);
323 execute(shell, recover);
324 recover.showDone(shell);
327 private static void sleep(long millsec) throws InterruptedException {
328 Display display = UI.getDisplay();
329 boolean isUIThread = (null == display) ? false : (Thread.currentThread() == display.getThread());
334 while (++count < 1000 && display.readAndDispatch())
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);
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;
366 } catch (Throwable t) {
373 public String getMessageBegin() {
377 public String getMessageCancel() {
378 return cancelMessage;
381 public String getMessageFail(Throwable throwable) {
382 return failMessage + NL + throwable.getMessage();
385 public String getMessageFail() {
389 public String getMessageOk() {
393 public boolean isDone() {
397 public void setCancelled() {
401 public void setDone() {
405 public boolean isForkable() {
409 public boolean isCancelable() {
413 public void showDone(Shell shell) {
414 if (null != throwable)
415 Util.showError(shell, getMessageFail(throwable));
417 Util.showInfo(shell, getMessageOk());
419 Util.showInfo(shell, getMessageCancel());
421 Util.showWarning(shell, getMessageFail());
424 static abstract class ExecutorDatabase extends ExecutorBase {
425 protected final File dbFolder;
426 ExecutorDatabase(File dbFolder) {
427 this.dbFolder = dbFolder;
429 String getMessage() {
430 return NLS.bind( Messages.Handler_FolderEquals ,new Object[] { NL , dbFolder});
433 public String getMessageBegin() {
434 return super.getMessageBegin() + getMessage();
437 public String getMessageCancel() {
438 return super.getMessageCancel() + getMessage();
441 public String getMessageFail(Throwable t) {
442 return super.getMessageFail(t) + getMessage();
445 public String getMessageOk() {
446 return super.getMessageOk() + getMessage();
449 private static void execute(final Shell shell, final Executor executor) {
450 final Thread thread = new Thread(executor);
452 IRunnableWithProgress progress = new IRunnableWithProgress() {
454 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
456 monitor.beginTask(executor.getMessageBegin(), IProgressMonitor.UNKNOWN);
457 while (!monitor.isCanceled() && !executor.isDone()) {
461 if (executor.isDone())
463 executor.setCancelled();
465 monitor.subTask(Messages.Handler_MonitorWaitingForCancellationToFinish);
466 while (!executor.isDone())
473 boolean fork = executor.isForkable();
474 boolean cancelable = executor.isCancelable();
476 new ProgressMonitorDialog(shell).run(fork, cancelable, progress);
477 } catch (InvocationTargetException e) {
478 } catch (InterruptedException e) {