// BlogBridge -- RSS feed reader, manager, and web based service // Copyright (C) 2002-2006 by R. Pito Salas // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software Foundation; // either version 2 of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with this program; // if not, write to the Free Software Foundation, Inc., 59 Temple Place, // Suite 330, Boston, MA 02111-1307 USA // // Contact: R. Pito Salas // mailto:pitosalas@users.sourceforge.net // More information: about BlogBridge // http://www.blogbridge.com // http://sourceforge.net/projects/blogbridge // // $Id $ // package com.salas.bb.core; import com.jgoodies.uif.application.Application; import com.salas.bb.core.actions.guide.ImportGuidesAction; import com.salas.bb.utils.opml.ImporterAdv; import com.salas.bb.utils.i18n.Strings; import com.salas.bb.service.sync.SyncInAction; import com.salas.bb.service.ServicePreferences; import java.io.File; import java.io.FilenameFilter; import java.net.MalformedURLException; import java.util.logging.Logger; import java.util.logging.Level; import java.util.Date; import java.awt.event.ActionEvent; /** * Database recovery utility. */ final class DatabaseRecoverer { private static final Logger LOG = Logger.getLogger(DatabaseRecoverer.class.getName()); /** Hidden utility constructor. */ private DatabaseRecoverer() { } /** * Performs recovery. * * @param model model. * @param backupsPath backups directory path. */ static void performRecovery(GlobalModel model, String backupsPath) { Date lastSuccessfulSync = getLastSuccessfulSyncDate(model); File[] availableBackups = findAvailableBackups(backupsPath); DataRecoverySelectionDialog.DataRecoveryChoice choice = DataRecoverySelectionDialog.ask( Application.getDefaultParentFrame(), lastSuccessfulSync, availableBackups); switch (choice.getMode()) { case DataRecoverySelectionDialog.DataRecoveryChoice.MODE_FROM_BACKUP: performRecoveryFromBackup(choice.getBackupFile(), model); break; case DataRecoverySelectionDialog.DataRecoveryChoice.MODE_FROM_SERVICE: performRecoveryFromService(model); break; default: break; } } private static void performRecoveryFromBackup(File backupFile, GlobalModel model) { try { ImportGuidesAction.doImport(new ImporterAdv(), backupFile.toURL().toString(), false, false, model, false); } catch (MalformedURLException e) { LOG.log(Level.SEVERE, "Failed to recover from backup.", e); } } private static void performRecoveryFromService(GlobalModel model) { // We create this event to tell the owner -- parent frame ActionEvent event = new ActionEvent(Application.getDefaultParentFrame(), 0, null); SyncInAction.getInstance().doSync(event); } /** * Finds all available and good OPML backup files. * * @param backupsPath backups directory path. * * @return backups. */ static File[] findAvailableBackups(String backupsPath) { File[] backups; File backupsDir = new File(backupsPath); if (backupsDir.exists()) { backups = backupsDir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return name != null && name.matches("^~[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{6}\\.opml$"); } }); } else backups = new File[0]; return backups; } /** * Returns <code>TRUE</code> if service account information is entered. * * @param model model. * * @return <code>TRUE</code> if service info is entered. */ private static boolean isServiceAccountPresent(GlobalModel model) { String success = ServicePreferences.SYNC_STATUS_SUCCESS; ServicePreferences prefs = model.getServicePreferences(); // If account info is added and any synchronization was successful // we report that the account is present and can be used for restoration boolean actInfoEntered = prefs.isAccountInformationEntered(); boolean successfulSync = success.equals(prefs.getLastSyncInStatus()) || success.equals(prefs.getLastSyncOutStatus()); return actInfoEntered && successfulSync; } /** * Returns the date of the last successful synchronization, no matter if it's in or out. * We care about the date being stored on the service and whether it's valid or not, so * if one of the syncs (at least) was successful we return its date. Otherwise (also if * the account isn't registered) the date will be NULL. * * @param model model. * * @return the most recent date of the sync or NULL. */ static Date getLastSuccessfulSyncDate(GlobalModel model) { return model == null ? null : getLastSuccessfulSyncDate(model.getServicePreferences()); } /** * Returns the date of the last successful synchronization, no matter if it's in or out. * We care about the date being stored on the service and whether it's valid or not, so * if one of the syncs (at least) was successful we return its date. Otherwise (also if * the account isn't registered) the date will be NULL. * * @param model model. * * @return the most recent date of the sync or NULL. */ static Date getLastSuccessfulSyncDate(ServicePreferences prefs) { if (prefs == null || !prefs.isAccountInformationEntered()) return null; Date syncInDate = null; if (ServicePreferences.SYNC_STATUS_SUCCESS.equals(prefs.getLastSyncInStatus())) { syncInDate = prefs.getLastSyncInDate(); } Date syncOutDate = null; if (ServicePreferences.SYNC_STATUS_SUCCESS.equals(prefs.getLastSyncOutStatus())) { syncOutDate = prefs.getLastSyncOutDate(); } return syncInDate != null ? (syncOutDate == null || syncInDate.after(syncOutDate)) ? syncInDate : syncOutDate : syncOutDate; } }