com.runwaysdk.dataaccess.io.Restore.java Source code

Java tutorial

Introduction

Here is the source code for com.runwaysdk.dataaccess.io.Restore.java

Source

/**
 * Copyright (c) 2015 TerraFrame, Inc. All rights reserved.
 *
 * This file is part of Runway SDK(tm).
 *
 * Runway SDK(tm) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Runway SDK(tm) 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Runway SDK(tm).  If not, see <http://www.gnu.org/licenses/>.
 */
package com.runwaysdk.dataaccess.io;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.runwaysdk.ServerExceptionMessageLocalizer;
import com.runwaysdk.business.Business;
import com.runwaysdk.business.BusinessQuery;
import com.runwaysdk.constants.CommonProperties;
import com.runwaysdk.constants.DeployProperties;
import com.runwaysdk.constants.ServerProperties;
import com.runwaysdk.constants.VaultInfo;
import com.runwaysdk.constants.VaultProperties;
import com.runwaysdk.dataaccess.ProgrammingErrorException;
import com.runwaysdk.dataaccess.cache.globalcache.ehcache.CacheShutdown;
import com.runwaysdk.dataaccess.database.Database;
import com.runwaysdk.query.OIterator;
import com.runwaysdk.query.QueryFactory;
import com.runwaysdk.session.Request;
import com.runwaysdk.session.Session;
import com.runwaysdk.system.metadata.BackupReadException;
import com.runwaysdk.system.metadata.CorruptBackupException;
import com.runwaysdk.system.metadata.RestoreAppnameException;
import com.runwaysdk.util.FileIO;

public class Restore {
    private PrintStream logPrintStream;

    private String zipFileLocation;

    private File restoreDirectory;

    private List<RestoreAgent> agents;

    private String cacheDir;

    private Log log;

    private String cacheName;

    public Restore(PrintStream logPrintStream, String zipFileLocation) {
        log = LogFactory.getLog(this.getClass());

        this.logPrintStream = logPrintStream;

        this.zipFileLocation = zipFileLocation;

        File zipFile = new File(zipFileLocation);

        String zipFileName = zipFile.getName();

        if (zipFileName.indexOf(".zip") == -1) {
            CorruptBackupException cbe = new CorruptBackupException();
            cbe.setBackupName(zipFileLocation);
            throw cbe;
        }

        String rootZipFileName = zipFileName.substring(0, zipFileName.indexOf(".zip"));

        String restoreDirectoryString = zipFile.getParent() + File.separator + rootZipFileName;

        this.restoreDirectory = new File(restoreDirectoryString);
        this.restoreDirectory.mkdir();

        this.cacheDir = ServerProperties.getGlobalCacheFileLocation();
        this.cacheName = ServerProperties.getGlobalCacheName();

        this.agents = new LinkedList<RestoreAgent>();
    }

    public void restore() {
        this.logPrintStream
                .println(ServerExceptionMessageLocalizer.restoringApplicationMessage(Session.getCurrentLocale()));
        this.logPrintStream.println("-----------------------------------------------");

        this.log.debug("Starting restore from [" + this.zipFileLocation + "]");

        for (RestoreAgent agent : agents) {
            agent.preRestore();
        }

        this.unzipFile();

        this.validateRestore();

        this.logPrintStream
                .println("\n" + ServerExceptionMessageLocalizer.droppingTablesMessage(Session.getCurrentLocale()));
        this.dropApplicationTabels();

        this.logPrintStream.println(
                "\n" + ServerExceptionMessageLocalizer.importingDatabaseRecords(Session.getCurrentLocale()));
        this.importSQL();

        // restoreCacheFile();
        deleteCacheFile();

        restoreWebapp();

        restoreVault();

        /*
         * restoreProfiles();
         * 
         * restoreWebFilesVaults();
         */
        try {
            FileIO.deleteDirectory(this.restoreDirectory);
        } catch (IOException e) {
            throw new ProgrammingErrorException(e);
        }

        for (RestoreAgent agent : agents) {
            agent.postRestore();
        }

        this.log.trace("Finished restore from [" + this.zipFileLocation + "].");

        this.logPrintStream
                .println("\n" + ServerExceptionMessageLocalizer.restoreCompleteMessage(Session.getCurrentLocale()));
    }

    /**
     * Check to make sure this restore makes sense. We want to fail before we do anything too important.
     */
    private void validateRestore() {
        String webappRootDir = DeployProperties.getDeployPath();

        // Check if the webapp that we're restoring onto has the same name as what's in the backup, otherwise the user may be restoring the wrong backup file!
        // TODO : Add support for the non-legacy properties format
        String propertiesFileName = "terraframe.properties";

        final Properties restoreProps = new Properties();
        try {
            restoreProps.load(new FileInputStream(
                    this.restoreDirectory.getPath() + File.separator + Backup.WEBAPP_DIR_NAME + File.separator
                            + "WEB-INF" + File.separator + "classes" + File.separator + propertiesFileName));
        } catch (FileNotFoundException e) {
            CorruptBackupException cbe = new CorruptBackupException(e);
            cbe.setBackupName(new File(zipFileLocation).getName());
            throw cbe;
        } catch (IOException e) {
            CorruptBackupException cbe = new CorruptBackupException(e);
            cbe.setBackupName(new File(zipFileLocation).getName());
            throw cbe;
        }

        String restoreAppName = restoreProps.getProperty("deploy.appname");
        String currentAppName = CommonProperties.getDeployAppName(); // It makes the most sense to get this value from DeployProperties, but for backwards compatibility (cough ddms) we'll do it this way

        if (!restoreAppName.equalsIgnoreCase(currentAppName)) {
            RestoreAppnameException rae = new RestoreAppnameException();
            rae.setCurrentAppname(currentAppName);
            rae.setRestoreAppname(restoreAppName);
            throw rae;
        }
    }

    private void dropApplicationTabels() {
        List<String> tableNames = null;
        try {
            tableNames = Database.getAllApplicationTables();
        } catch (Throwable e) {
            // The framework has already been dropped.
        }

        if (tableNames != null) {
            Database.cascadeDropTables(tableNames);
        }
    }

    private void unzipFile() {
        this.logPrintStream.println(ServerExceptionMessageLocalizer
                .extractingFileMessage(Session.getCurrentLocale(), this.zipFileLocation));

        try {
            FileIO.write(new ZipFile(this.zipFileLocation), this.restoreDirectory.getAbsolutePath());
            this.log.debug("Unzipped from [" + this.zipFileLocation + "] to [" + this.restoreDirectory + "]");
        } catch (ZipException e) {
            CorruptBackupException cbe = new CorruptBackupException(e);
            cbe.setBackupName(new File(zipFileLocation).getName());
            throw cbe;
        } catch (IOException e) {
            BackupReadException bre = new BackupReadException(e);
            bre.setLocation(new File(zipFileLocation).getName());
            throw bre;
        }
    }

    private void importSQL() {
        FilenameFilter filter = new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".sql");
            }
        };

        File sqlDir = new File(
                this.restoreDirectory.getAbsoluteFile() + File.separator + Backup.SQL + File.separator);

        this.log.debug("Importing SQL from directory [" + sqlDir + "]");

        File[] sqlFiles = sqlDir.listFiles(filter);

        if (sqlFiles != null) {
            for (File sqlFile : sqlFiles) {
                Database.importFromSQL(sqlFile.getAbsolutePath(), this.logPrintStream);
            }
        }
    }

    private void deleteCacheFile() {
        this.logPrintStream
                .println(ServerExceptionMessageLocalizer.backingUpCacheMessage(Session.getCurrentLocale()));

        File dataFile = new File(cacheDir + File.separator + cacheName + ".data");
        try {
            this.log.debug("Deleting cache data file [" + dataFile.getAbsolutePath() + "].");
            FileIO.deleteFile(dataFile);
        } catch (IOException e) {
            BackupReadException bre = new BackupReadException(e);
            bre.setLocation(dataFile.getAbsolutePath());
            throw bre;
        }

        File indexFile = new File(cacheDir + File.separator + cacheName + ".index");
        try {
            this.log.debug("Deleting cache index file [" + indexFile.getAbsolutePath() + "].");
            FileIO.deleteFile(indexFile);
        } catch (IOException e) {
            BackupReadException bre = new BackupReadException(e);
            bre.setLocation(indexFile.getAbsolutePath());
            throw bre;
        }

        this.log.trace("Finished backing up the cache files.");
    }

    // private void restoreCacheFile()
    // {
    // try
    // {
    // // Make the temp cache directory
    // File cacheDir = new File(this.restoreDirectory.getAbsoluteFile() +
    // File.separator + Backup.CACHE + File.separator);
    // this.log.trace("Restoring cache files from [" + cacheDir + "]");
    //
    // File[] files = cacheDir.listFiles();
    //
    // // the cache files might not exist if the backup was created without
    // // cache spooling up. Ignore these.
    // if (files != null)
    // {
    // for (File file : files)
    // {
    // String filename = this.cacheDir + File.separator + file.getName();
    // this.log.debug("Restoring cache file [" + filename + "]");
    //
    // FileInputStream iStream = new FileInputStream(file);
    // FileOutputStream oStream = new FileOutputStream(new File(filename));
    //
    // FileIO.write(oStream, iStream);
    // }
    // }
    // else
    // {
    // this.log.trace("There were no files in the cache directory [" + cacheDir +
    // "] to restore.");
    // }
    // }
    // catch (IOException e)
    // {
    // throw new ProgrammingErrorException(e);
    // }
    // }

    private void restoreWebapp() {
        File backupProfileLocationFile = new File(
                this.restoreDirectory.getPath() + File.separator + Backup.WEBAPP_DIR_NAME + File.separator);

        String webappRootDir = DeployProperties.getDeployPath();

        File webappRootFile = new File(webappRootDir);

        FilenameFilter filenameFilter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                if (name.endsWith(".svn") || dir.getName().startsWith(".")) {
                    return false;
                }

                return true;
            }
        };

        FileFilter fileFilter = new FileFilter() {
            public boolean accept(File pathname) {
                return true;
            }
        };

        try {
            this.logPrintStream.println("\n" + ServerExceptionMessageLocalizer
                    .cleaningWebappFolderMessage(Session.getCurrentLocale(), webappRootFile));
            FileIO.deleteFolderContent(webappRootFile, fileFilter);
        } catch (IOException e) {
            // Some files might have already been deleted. We will copy anyway, as the
            // files should overwrite.
        }

        boolean success = FileIO.copyFolder(backupProfileLocationFile, webappRootFile, filenameFilter,
                this.logPrintStream);
        if (!success) {
            // TODO : This success stuff is garbage, I want the actual IOException why swallow it
            BackupReadException bre = new BackupReadException();
            bre.setLocation(webappRootFile.getAbsolutePath());
            throw bre;
        }
    }

    public void addAgent(RestoreAgent agent) {
        agents.add(agent);
    }

    private void restoreVault() {
        log.trace("Starting restore of vaults.");

        QueryFactory qf = new QueryFactory();
        BusinessQuery vaultQ = qf.businessQuery(VaultInfo.CLASS);

        String backupVaultFileLocation = this.restoreDirectory.getPath() + File.separator + Backup.VAULT_DIR_NAME
                + File.separator;

        OIterator<Business> i = vaultQ.getIterator();
        try {
            for (Business vault : i) {
                String vaultName = vault.getValue(VaultInfo.VAULT_NAME);
                String vaultLocation = VaultProperties.getPath(vaultName);
                String vaultInsideBackup = backupVaultFileLocation + File.separator + vault.getId()
                        + File.separator;

                File vaultInsideBackupFile = new File(vaultInsideBackup);
                File vaultLocationFile = new File(vaultLocation);

                if (!vaultLocationFile.exists()) {
                    vaultLocationFile.mkdirs();
                }

                if (vaultInsideBackupFile.exists()) {
                    log.debug("Restoring vault [" + vaultName + "] from [" + vaultInsideBackup + "] to ["
                            + vaultLocation + "].");

                    FileIO.copyFolder(vaultInsideBackupFile, vaultLocationFile, this.logPrintStream);
                } else {
                    log.warn("Skipped restore of vault [" + vaultName + "] from backup [" + vaultInsideBackup
                            + "] to [" + vaultLocation + "] because the file in the backup does not exist.");
                }
            }
        } finally {
            i.close();
        }
    }

    /*
     * private void restoreProfiles() { File backupProfileLocationFile = new
     * File(this
     * .restoreDirectory.getPath()+File.separator+Backup.PROVILE_DIR_NAME+
     * File.separator);
     * 
     * String profileRootDir = ProfileManager.getProfileRootDir().toString();
     * 
     * File profileRootFile = new File(profileRootDir);
     * 
     * FilenameFilter filenameFilter = new FilenameFilter() { public boolean
     * accept(File dir, String name) { if (name.endsWith(".properties") ||
     * name.endsWith(".xml") || name.endsWith(".xsd") ) { return true; }
     * 
     * if (dir.isDirectory() && !dir.getName().startsWith(".")) { return true; }
     * 
     * return false; } };
     * 
     * FileIO.copyFolder(backupProfileLocationFile, profileRootFile,
     * filenameFilter, this.logPrintStream); }
     */
    /*
     * private void restoreWebFilesVaults() { QueryFactory qf = new
     * QueryFactory(); BusinessDAOQuery webFileQ =
     * qf.businessDAOQuery(WebFileInfo.CLASS);
     * 
     * String backupWebFileFileLocation =
     * this.restoreDirectory+File.separator+Backup
     * .WEBFILE_DIR_NAME+File.separator;
     * 
     * // Create the web file dir File backupWebFileFile = new
     * File(backupWebFileFileLocation); backupWebFileFile.mkdir();
     * 
     * OIterator<BusinessDAOIF> i = webFileQ.getIterator(); try { for
     * (BusinessDAOIF businessDAOIF : i) { WebFileDAOIF webFileDAOIF =
     * (WebFileDAOIF)businessDAOIF; File thisBackupWebFileFile = new
     * File(backupWebFileFileLocation+webFileDAOIF.getId()); try {
     * BufferedInputStream inputStream = new BufferedInputStream(new
     * FileInputStream(thisBackupWebFileFile)); webFileDAOIF.putFile(inputStream);
     * } catch (IOException e) { throw new
     * FileWriteException(thisBackupWebFileFile, e); } } } finally { i.close(); }
     * }
     */

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            Restore.start(args);
        } finally {
            CacheShutdown.shutdown();

        }
    }

    @Request
    private static void start(String[] args) {
        if (args.length != 1) {
            String errMessage = "Invalid number of arguments given.  Only one argument is required: the location of the backup file.";
            throw new RuntimeException(errMessage);
        } else {
            Restore restore = new Restore(System.out, args[0]);
            restore.restore();
        }
    }

}