/* ********************************************************************** ** ** Copyright notice ** ** ** ** (c) 2005-2009 RSSOwl Development Team ** ** http://www.rssowl.org/ ** ** ** ** All rights reserved ** ** ** ** This program and the accompanying materials are made available under ** ** the terms of the Eclipse Public License v1.0 which accompanies this ** ** distribution, and is available at: ** ** http://www.rssowl.org/legal/epl-v10.html ** ** ** ** A copy is found in the file epl-v10.html and important notices to the ** ** license from the team is found in the textfile LICENSE.txt distributed ** ** in this package. ** ** ** ** This copyright notice MUST APPEAR in all copies of the file! ** ** ** ** Contributors: ** ** RSSOwl Development Team - initial API and implementation ** ** ** ** ********************************************************************** */ package org.rssowl.ui.internal.dialogs.fatal; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.equinox.app.IApplication; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.wizard.Wizard; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.custom.BusyIndicator; import org.rssowl.core.Owl; import org.rssowl.core.Owl.StartLevel; import org.rssowl.core.internal.InternalOwl; import org.rssowl.core.persist.IEntity; import org.rssowl.core.persist.service.PersistenceException; import org.rssowl.core.persist.service.ProfileLockedException; import org.rssowl.core.util.StringUtils; import org.rssowl.ui.internal.Activator; import org.rssowl.ui.internal.Application; import org.rssowl.ui.internal.Controller; import org.rssowl.ui.internal.OwlUI; import org.rssowl.ui.internal.util.ImportUtils; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.List; /** * The {@link FatalErrorWizard} shows up when RSSOwl crashed during startup in a * fatal, unrecoverable way. * * @author bpasero */ public class FatalErrorWizard extends Wizard { private ErrorInfoPage fErrorInfoPage; private RestoreBackupPage fRestoreBackupPage; private CleanProfilePage fCleanProfilePage; private RecreateSearchIndexPage fReindexSearchPage; private final IStatus fErrorStatus; private int fReturnCode = IApplication.EXIT_OK; private final List<File> fProfileBackups = new ArrayList<File>(); private final List<File> fOPMLBackups = new ArrayList<File>(); private boolean fOfferRestorePages; public FatalErrorWizard(IStatus errorStatus) { this(errorStatus, false); } public FatalErrorWizard(IStatus errorStatus, boolean forceAllowRestore) { fErrorStatus = errorStatus; boolean isOOMError = (fErrorStatus.getException() instanceof OutOfMemoryError); boolean isProfileLockedError = (fErrorStatus.getException() instanceof ProfileLockedException); boolean canUsePersistenceService = (InternalOwl.getDefault().getPersistenceService() != null); StartLevel startLevel = InternalOwl.getDefault().getStartLevel(); fOfferRestorePages = !isOOMError && !isProfileLockedError && canUsePersistenceService && startLevel != StartLevel.STARTED && startLevel != StartLevel.SEARCH_INDEX_OPENED; /* Log State */ if (forceAllowRestore) Activator.safeLogInfo("Opening Fatal Error Wizard (forced by user)"); //$NON-NLS-1$ else if (!isOOMError && !isProfileLockedError) Activator.safeLogInfo(fOfferRestorePages ? "Opening Fatal Error Wizard (offering restore options)" : "Opening Fatal Error Wizard (without restore options)"); //$NON-NLS-1$ //$NON-NLS-2$ /* Check if caller wants to force profile restore pages */ if (!fOfferRestorePages && forceAllowRestore && canUsePersistenceService) fOfferRestorePages = true; /* Search for backups as necessary */ if (fOfferRestorePages) findBackups(); } private void findBackups() { /* Collect Profile Backups */ fProfileBackups.addAll(InternalOwl.getDefault().getProfileBackups()); /* Collect OPML Backups if no profile backups can be found */ if (fProfileBackups.isEmpty()) { IPath backPath = Platform.getLocation(); File backupDir = backPath.toFile(); if (backupDir.exists()) { /* Daily OPML Backup */ File dailyBackupFile = backPath.append(Controller.DAILY_BACKUP).toFile(); if (dailyBackupFile.exists()) fOPMLBackups.add(dailyBackupFile); /* Weekly OPML Backup */ File weeklyBackupFile = backPath.append(Controller.WEEKLY_BACKUP).toFile(); if (weeklyBackupFile.exists()) fOPMLBackups.add(weeklyBackupFile); } } } /* * @see org.eclipse.jface.wizard.Wizard#addPages() */ @Override public void addPages() { setWindowTitle(fErrorStatus.isOK() ? Messages.FatalErrorWizard_PROFILE_RECOVERY : Messages.FatalErrorWizard_CRASH_REPORTER); setHelpAvailable(false); /* Error Info (not if wizard was forced to open by user) */ if (!fErrorStatus.isOK() || !fOfferRestorePages) { fErrorInfoPage = new ErrorInfoPage(Messages.FatalErrorWizard_WE_ARE_SORRY, fErrorStatus, fOfferRestorePages); addPage(fErrorInfoPage); } /* Add Restore Pages as necessary */ if (fOfferRestorePages) { /* Not an actual issue with the DB, rather search, so provide reindex page */ if (Owl.getStartLevel() == StartLevel.DB_OPENED) { fReindexSearchPage = new RecreateSearchIndexPage(Messages.FatalErrorWizard_RECREATE_SEARCH_INDEX); addPage(fReindexSearchPage); } /* Restore Profile Backup (if profile backups are present) */ else if (!fProfileBackups.isEmpty()) { fRestoreBackupPage = new RestoreBackupPage(Messages.FatalErrorWizard_RESTORE_BACKUP, fErrorStatus, fProfileBackups); addPage(fRestoreBackupPage); } /* Otherwise allow to restore from OPML Backup or clean start */ else { fCleanProfilePage = new CleanProfilePage(fOPMLBackups.isEmpty() ? Messages.FatalErrorWizard_START_OVER : Messages.FatalErrorWizard_RESTORE_SUBSCRIPTIONS_SETTINGS, fErrorStatus, !fOPMLBackups.isEmpty()); addPage(fCleanProfilePage); } } } /* * @see org.eclipse.jface.wizard.Wizard#performFinish() */ @Override public boolean performFinish() { /* Finish */ try { BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() { public void run() { internalPerformFinish(); } }); } catch (Throwable e) { Activator.getDefault().logError(e.getMessage(), e); /* Show Error to the User */ String msg; if (StringUtils.isSet(e.getMessage())) msg = NLS.bind(Messages.FatalErrorWizard_RESTORE_ERROR_N, e.getMessage()); else msg = Messages.FatalErrorWizard_RESTORE_ERROR; ((WizardPage) getContainer().getCurrentPage()).setMessage(msg, IMessageProvider.ERROR); return false; } /* Windows: Support to restart from dialog */ if (Application.IS_WINDOWS && !fErrorStatus.isOK()) //Status only OK if user forced dialog, quit in this case fReturnCode = IApplication.EXIT_RESTART; return true; } private void internalPerformFinish() throws PersistenceException { /* Recreate Search Index */ if (fReindexSearchPage != null) { InternalOwl.getDefault().getPersistenceService().getModelSearch().reIndexOnNextStartup(); } /* Restore Profile from Backup */ else if (fRestoreBackupPage != null && fRestoreBackupPage.getSelectedBackup() != null) { InternalOwl.getDefault().restoreProfile(fRestoreBackupPage.getSelectedBackup()); } /* Clean Profile */ else if (fCleanProfilePage != null && fCleanProfilePage.doCleanProfile()) { /* Recreate the Profile */ boolean needsEmergencyStartup = !fOPMLBackups.isEmpty(); InternalOwl.getDefault().recreateProfile(needsEmergencyStartup); /* Try to Import from OPML backups if present */ if (!fOPMLBackups.isEmpty()) { List<? extends IEntity> types = null; /* First Try Daily Backup */ File recentBackup = fOPMLBackups.get(0); try { types = Owl.getInterpreter().importFrom(new FileInputStream(recentBackup)); } catch (Exception e) { if (fOPMLBackups.size() == 1) throw new PersistenceException(e.getMessage(), e); } /* Second Try Weekly Backup */ if (types == null && fOPMLBackups.size() == 2) { File weeklyBackup = fOPMLBackups.get(1); try { types = Owl.getInterpreter().importFrom(new FileInputStream(weeklyBackup)); } catch (Exception e) { throw new PersistenceException(e.getMessage(), e); } } /* Do Import */ if (types != null) ImportUtils.doImport(null, types, false); } /* Clear Stored Favicons (since Ids change after import) */ OwlUI.clearFavicons(); } } /* * @see org.eclipse.jface.wizard.Wizard#canFinish() */ @Override public boolean canFinish() { /* Make sure user is on last page to Finish */ if (fRestoreBackupPage != null && getContainer().getCurrentPage() != fRestoreBackupPage) return false; else if (fCleanProfilePage != null && getContainer().getCurrentPage() != fCleanProfilePage) return false; else if (fReindexSearchPage != null && getContainer().getCurrentPage() != fReindexSearchPage) return false; /* Other Pages decide on their own */ return super.canFinish(); } /* * @see org.eclipse.jface.wizard.Wizard#needsProgressMonitor() */ @Override public boolean needsProgressMonitor() { return false; } /** * @return one of the {@link IApplication} return codes. */ public int getReturnCode() { return fReturnCode; } }