/* * Copyright (C) 2009 eXo Platform SAS. * * This 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 2.1 of * the License, or (at your option) any later version. * * This software 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 this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.services.jcr.ext.backup.impl; import org.apache.commons.collections.map.HashedMap; import org.exoplatform.commons.utils.ClassLoading; import org.exoplatform.commons.utils.PrivilegedFileHelper; import org.exoplatform.commons.utils.PrivilegedSystemHelper; import org.exoplatform.commons.utils.SecurityHelper; import org.exoplatform.container.ExoContainerContext; import org.exoplatform.container.xml.InitParams; import org.exoplatform.container.xml.PropertiesParam; import org.exoplatform.services.jcr.RepositoryService; import org.exoplatform.services.jcr.config.RepositoryConfigurationException; import org.exoplatform.services.jcr.config.RepositoryEntry; import org.exoplatform.services.jcr.config.SimpleParameterEntry; import org.exoplatform.services.jcr.config.WorkspaceEntry; import org.exoplatform.services.jcr.config.WorkspaceInitializerEntry; import org.exoplatform.services.jcr.core.WorkspaceContainerFacade; import org.exoplatform.services.jcr.ext.backup.BackupChain; import org.exoplatform.services.jcr.ext.backup.BackupChainLog; import org.exoplatform.services.jcr.ext.backup.BackupConfig; import org.exoplatform.services.jcr.ext.backup.BackupConfigurationException; import org.exoplatform.services.jcr.ext.backup.BackupJob; import org.exoplatform.services.jcr.ext.backup.BackupJobListener; import org.exoplatform.services.jcr.ext.backup.BackupManager; import org.exoplatform.services.jcr.ext.backup.BackupOperationException; import org.exoplatform.services.jcr.ext.backup.ExtendedBackupManager; import org.exoplatform.services.jcr.ext.backup.JobEntryInfo; import org.exoplatform.services.jcr.ext.backup.RepositoryBackupChain; import org.exoplatform.services.jcr.ext.backup.RepositoryBackupChainLog; import org.exoplatform.services.jcr.ext.backup.RepositoryBackupConfig; import org.exoplatform.services.jcr.ext.backup.RepositoryRestoreExeption; import org.exoplatform.services.jcr.ext.backup.WorkspaceRestoreException; import org.exoplatform.services.jcr.ext.backup.impl.fs.FullBackupJob; import org.exoplatform.services.jcr.ext.backup.impl.rdbms.RdbmsWorkspaceInitializer; import org.exoplatform.services.jcr.ext.common.SessionProvider; import org.exoplatform.services.jcr.ext.registry.RegistryEntry; import org.exoplatform.services.jcr.ext.registry.RegistryService; import org.exoplatform.services.jcr.impl.backup.JCRRestore; import org.exoplatform.services.jcr.impl.core.RepositoryImpl; import org.exoplatform.services.jcr.impl.core.SysViewWorkspaceInitializer; import org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager; import org.exoplatform.services.jcr.impl.util.io.FileCleanerHolder; import org.exoplatform.services.jcr.util.IdGenerator; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.ws.frameworks.json.impl.JsonException; import org.exoplatform.ws.frameworks.json.impl.JsonGeneratorImpl; import org.picocontainer.Startable; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import javax.jcr.PathNotFoundException; import javax.jcr.RepositoryException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; /** * Created by The eXo Platform SAS .<br> * * @author Gennady Azarenkov * @version $Id: $ */ public class BackupManagerImpl implements ExtendedBackupManager, Startable { protected static final Log LOG = ExoLogger.getLogger("exo.jcr.component.ext.BackupManagerImpl"); /** * Name of default incremental job period parameter in configuration. */ public final static String DEFAULT_INCREMENTAL_JOB_PERIOD = "default-incremental-job-period"; /** * Name of backup properties parameter in configuration. */ public final static String BACKUP_PROPERTIES = "backup-properties"; /** * Name of full backup type parameter in configuration. */ public final static String FULL_BACKUP_TYPE = "full-backup-type"; /** * Name of incremental backup type parameter in configuration. */ public final static String INCREMENTAL_BACKUP_TYPE = "incremental-backup-type"; /** * Default value of incremental job period parameter in configuration. */ public final static String DEFAULT_VALUE_INCREMENTAL_JOB_PERIOD = "3600"; /** * Default value of incremental backup type parameter in configuration. */ public final static String DEFAULT_VALUE_INCREMENTAL_BACKUP_TYPE = org.exoplatform.services.jcr.ext.backup.impl.fs.IncrementalBackupJob.class.getName(); /** * Default value of incremental backup type parameter in configuration. */ public final static String DEFAULT_VALUE_FULL_BACKUP_TYPE = org.exoplatform.services.jcr.ext.backup.impl.rdbms.FullBackupJob.class.getName(); /** * Name of backup dir parameter in configuration. */ public final static String BACKUP_DIR = "backup-dir"; /** * Backup messages log max. size. */ private static final int MESSAGES_MAXSIZE = 5; private static final String SERVICE_NAME = "BackupManager"; /** * The timeout to checking finish of backup. */ private static final long AUTO_STOPPER_TIMEOUT = 5000; /** * Value of default incremental job period. */ private long defaultIncrementalJobPeriod; /** * Value of default incremental period. */ private String defIncrPeriod; /** * Path to backup folder. */ private String backupDir; /** * Value of full backup type. */ private String fullBackupType; /** * Value of incremental backup type. */ private String incrementalBackupType; /** * Set of current workspace backups. */ private final Set<BackupChain> currentBackups; /** * Set of current repository backups. */ private final Set<RepositoryBackupChain> currentRepositoryBackups; /** * The list of workspace restore job. */ private List<JobWorkspaceRestore> restoreJobs; /** * The list of repository restore job. */ protected CopyOnWriteArrayList<JobRepositoryRestore> restoreRepositoryJobs; /** * Initialization parameters of service. */ private InitParams initParams; /** * Directory to log. */ private File logsDirectory; private final RepositoryService repoService; private final RegistryService registryService; private final BackupMessagesLog messages; private final MessagesListener messagesListener; private final WorkspaceBackupAutoStopper workspaceBackupStopper; private final RepositoryBackupAutoStopper repositoryBackupStopper; /** * Temporary directory; */ private final File tempDir; class MessagesListener implements BackupJobListener { public void onError(BackupJob job, String message, Throwable error) { messages.addError(makeJobInfo(job, error) + message, error); LOG.error(makeJobInfo(job, error) + message, error); } public void onStateChanged(BackupJob job) { messages.addMessage(makeJobInfo(job, null)); if (LOG.isDebugEnabled()) { LOG.debug(makeJobInfo(job, null)); } } private String makeJobInfo(BackupJob job, Throwable error) { StringBuilder jobInfo = new StringBuilder(); if (job != null) { switch (job.getType()) { case BackupJob.FULL : { jobInfo.append("FULL BACKUP"); break; } case BackupJob.INCREMENTAL : { jobInfo.append("INCREMENTAL BACKUP"); break; } } jobInfo.append(" ["); switch (job.getState()) { case BackupJob.FINISHED : { jobInfo.append("FINISHED"); break; } case BackupJob.STARTING : { jobInfo.append("STARTING"); break; } case BackupJob.WAITING : { jobInfo.append("WAITING"); break; } case BackupJob.WORKING : { jobInfo.append("WORKING"); break; } } jobInfo.append("]"); if (error != null) { jobInfo.append(" Error: ").append(error.getMessage()); } try { jobInfo.append(" log: ").append(job.getStorageURL().getPath()); } catch (BackupOperationException e) { if (LOG.isTraceEnabled()) { LOG.trace("An exception occurred: " + e.getMessage()); } } finally { jobInfo.append(" "); } } return jobInfo.toString(); } public String printStackTrace(Throwable error) { ByteArrayOutputStream out = new ByteArrayOutputStream(); PrintWriter writer = new PrintWriter(out); error.printStackTrace(writer); return new String(out.toByteArray()); } } class TaskFilter implements FileFilter { public boolean accept(File pathname) { return pathname.getName().endsWith(".task"); } } class WorkspaceBackupAutoStopper extends Thread { private boolean isToBeStopped = false; WorkspaceBackupAutoStopper(ExoContainerContext ctx) { super("WorkspaceBackupAutoStopper" + (ctx == null ? "" : " " + ctx.getName())); } /** * {@inheritDoc} */ @Override public void run() { while (!isToBeStopped) { try { Thread.sleep(AUTO_STOPPER_TIMEOUT); Iterator<BackupChain> it = currentBackups.iterator(); List<BackupChain> stopedList = new ArrayList<BackupChain>(); while (it.hasNext()) { BackupChain chain = it.next(); boolean isFinished = (chain.getBackupJobs().get(0).getState() == BackupJob.FINISHED); for (int i = 1; i < chain.getBackupJobs().size(); i++) { isFinished &= (chain.getBackupJobs().get(i).getState() == BackupJob.FINISHED); } if (isFinished) { stopedList.add(chain); } } // STOP backups for (BackupChain chain : stopedList) { stopBackup(chain); } } catch (InterruptedException e) { LOG.error("The interapted this thread.", e); } catch (Throwable e) //NOSONAR { LOG.error("The unknown error", e); } } } public void close() { isToBeStopped = true; } } class RepositoryBackupAutoStopper extends Thread { boolean isToBeStopped = false; RepositoryBackupAutoStopper(ExoContainerContext ctx) { super("RepositoryBackupAutoStopper" + (ctx == null ? "" : " " + ctx.getName())); } /** * {@inheritDoc} */ @Override public void run() { while (!isToBeStopped) { try { Thread.sleep(AUTO_STOPPER_TIMEOUT); Iterator<RepositoryBackupChain> it = currentRepositoryBackups.iterator(); List<RepositoryBackupChain> stopedList = new ArrayList<RepositoryBackupChain>(); while (it.hasNext()) { RepositoryBackupChain chain = it.next(); if (chain.isFinished()) { stopedList.add(chain); } } // STOP backups for (RepositoryBackupChain chain : stopedList) { stopBackup(chain); } } catch (InterruptedException e) { LOG.error("The interapted this thread.", e); } catch (Throwable e) //NOSONAR { LOG.error("The unknown error", e); } } } public void close() { isToBeStopped = true; } } /** * BackupManagerImpl constructor. * * @param initParams * InitParams, the init parameters * @param repoService * RepositoryService, the repository service */ public BackupManagerImpl(InitParams initParams, RepositoryService repoService) { this(null, initParams, repoService, null); } /** * BackupManagerImpl constructor. * * @param initParams * InitParams, the init parameters * @param repoService * RepositoryService, the repository service */ public BackupManagerImpl(ExoContainerContext ctx, InitParams initParams, RepositoryService repoService) { this(ctx, initParams, repoService, null); } /** * BackupManagerImpl constructor. * * InitParams, the init parameters * @param repoService * RepositoryService, the repository service * @param registryService * RegistryService, the registry service */ public BackupManagerImpl(InitParams initParams, RepositoryService repoService, RegistryService registryService) { this(null, initParams, repoService, registryService); } /** * BackupManagerImpl constructor. * * InitParams, the init parameters * @param repoService * RepositoryService, the repository service * @param registryService * RegistryService, the registry service */ public BackupManagerImpl(ExoContainerContext ctx, InitParams initParams, RepositoryService repoService, RegistryService registryService) { this.messagesListener = new MessagesListener(); this.repoService = repoService; this.registryService = registryService; this.initParams = initParams; this.tempDir = new File(PrivilegedSystemHelper.getProperty("java.io.tmpdir")); currentBackups = Collections.synchronizedSet(new HashSet<BackupChain>()); currentRepositoryBackups = Collections.synchronizedSet(new HashSet<RepositoryBackupChain>()); messages = new BackupMessagesLog(MESSAGES_MAXSIZE); this.restoreJobs = new ArrayList<JobWorkspaceRestore>(); this.restoreRepositoryJobs = new CopyOnWriteArrayList<JobRepositoryRestore>(); this.workspaceBackupStopper = new WorkspaceBackupAutoStopper(ctx); this.repositoryBackupStopper = new RepositoryBackupAutoStopper(ctx); } /** * {@inheritDoc} */ public Set<BackupChain> getCurrentBackups() { return currentBackups; } /** * {@inheritDoc} */ public BackupMessage[] getMessages() { return messages.getMessages(); } /** * {@inheritDoc} */ public BackupChainLog[] getBackupsLogs() { File[] cfs = PrivilegedFileHelper.listFiles(logsDirectory, new BackupLogsFilter()); List<BackupChainLog> logs = new ArrayList<BackupChainLog>(); for (int i = 0; i < cfs.length; i++) { File cf = cfs[i]; try { if (!isCurrentBackup(cf)) { logs.add(new BackupChainLog(cf)); } } catch (BackupOperationException e) { LOG.warn("Log file " + PrivilegedFileHelper.getAbsolutePath(cf) + " is bussy or corrupted. Skipped. " + e, e); } } BackupChainLog[] ls = new BackupChainLog[logs.size()]; logs.toArray(ls); return ls; } /** * {@inheritDoc} */ public RepositoryBackupChainLog[] getRepositoryBackupsLogs() { File[] cfs = PrivilegedFileHelper.listFiles(logsDirectory, new RepositoryBackupLogsFilter()); List<RepositoryBackupChainLog> logs = new ArrayList<RepositoryBackupChainLog>(); for (int i = 0; i < cfs.length; i++) { File cf = cfs[i]; try { if (!isCurrentRepositoryBackup(cf)) { logs.add(new RepositoryBackupChainLog(cf)); } } catch (BackupOperationException e) { LOG.warn("Log file " + PrivilegedFileHelper.getAbsolutePath(cf) + " is bussy or corrupted. Skipped. " + e, e); } } RepositoryBackupChainLog[] ls = new RepositoryBackupChainLog[logs.size()]; logs.toArray(ls); return ls; } /** * isCurrentBackup. * * @param log * File, the log to backup * @return boolean return the 'true' if this log is current backup. */ private boolean isCurrentBackup(File log) { for (BackupChain chain : currentBackups) { if (log.getName().equals(new File(chain.getLogFilePath()).getName())) { return true; } } return false; } /** * isCurrentRepositoryBackup. * * @param log * File, the log to backup * @return boolean return the 'true' if this log is current backup. */ private boolean isCurrentRepositoryBackup(File log) { for (RepositoryBackupChain chain : currentRepositoryBackups) { if (log.getName().equals(new File(chain.getLogFilePath()).getName())) { return true; } } return false; } protected void restoreOverInitializer(BackupChainLog log, String repositoryName, WorkspaceEntry workspaceEntry) throws BackupOperationException, RepositoryException, RepositoryConfigurationException, BackupConfigurationException { List<JobEntryInfo> list = log.getJobEntryInfos(); BackupConfig config = log.getBackupConfig(); String reposytoryName = (repositoryName == null ? config.getRepository() : repositoryName); String workspaceName = workspaceEntry.getName(); String fullbackupType = null; try { if ((ClassLoading.forName(log.getFullBackupType(), this).equals(FullBackupJob.class))) { fullbackupType = log.getFullBackupType(); } else if ((ClassLoading.forName(log.getFullBackupType(), this) .equals(org.exoplatform.services.jcr.ext.backup.impl.rdbms.FullBackupJob.class))) { fullbackupType = log.getFullBackupType(); } else { throw new BackupOperationException("Class \"" + log.getFullBackupType() + "\" is not support as full backup."); } } catch (ClassNotFoundException e) { throw new BackupOperationException("Class \"" + log.getFullBackupType() + "\" is not found.", e); } // ws should not exists. if (!workspaceAlreadyExist(reposytoryName, workspaceName)) { for (int i = 0; i < list.size(); i++) { if (i == 0) { try { fullRestoreOverInitializer(list.get(i).getURL().getPath(), reposytoryName, workspaceEntry, fullbackupType); } catch (FileNotFoundException e) { throw new BackupOperationException("Restore of full backup file error " + e, e); } catch (IOException e) { throw new BackupOperationException("Restore of full backup file I/O error " + e, e); } catch (ClassNotFoundException e) { throw new BackupOperationException("Restore of full backup class load error " + e, e); } repoService.getConfig().retain(); // save configuration to persistence (file or persister) } else { try { incrementalRestore(list.get(i).getURL().getPath(), reposytoryName, workspaceName); } catch (FileNotFoundException e) { throw new BackupOperationException("Restore of incremental backup file error " + e, e); } catch (IOException e) { throw new BackupOperationException("Restore of incremental backup file I/O error " + e, e); } catch (ClassNotFoundException e) { throw new BackupOperationException("Restore of incremental backup error " + e, e); } } } } else { throw new BackupConfigurationException("Workspace \"" + workspaceName + "\" should not exists."); } } private boolean workspaceAlreadyExist(String repository, String workspace) throws RepositoryException, RepositoryConfigurationException { String[] ws = repoService.getRepository(repository).getWorkspaceNames(); for (int i = 0; i < ws.length; i++) { if (ws[i].equals(workspace)) { return true; } } return false; } /** * {@inheritDoc} */ public BackupChain startBackup(BackupConfig config) throws BackupOperationException, BackupConfigurationException, RepositoryException, RepositoryConfigurationException { return startBackup(config, null); } /** * Internally used for call with job listener from scheduler. * * @param config * @param jobListener * @return * @throws BackupOperationException * @throws BackupConfigurationException * @throws RepositoryException * @throws RepositoryConfigurationException */ BackupChain startBackup(BackupConfig config, BackupJobListener jobListener) throws BackupOperationException, BackupConfigurationException, RepositoryException, RepositoryConfigurationException { validateBackupConfig(config); Calendar startTime = Calendar.getInstance(); File dir = FileNameProducer.generateBackupSetDir(config.getRepository(), config.getWorkspace(), config.getBackupDir() .getPath(), startTime); PrivilegedFileHelper.mkdirs(dir); config.setBackupDir(dir); BackupChain bchain = new BackupChainImpl(config, logsDirectory, repoService, fullBackupType, incrementalBackupType, IdGenerator .generate(), logsDirectory, startTime); bchain.addListener(messagesListener); bchain.addListener(jobListener); currentBackups.add(bchain); bchain.startBackup(); return bchain; } /** * Initialize backup chain to workspace backup. * * @param config * @return * @throws BackupOperationException * @throws BackupConfigurationException * @throws RepositoryException * @throws RepositoryConfigurationException */ private void validateBackupConfig(RepositoryBackupConfig config) throws BackupConfigurationException { if (config.getIncrementalJobPeriod() < 0) { throw new BackupConfigurationException("The parameter 'incremental job period' can not be negative."); } if (config.getIncrementalJobNumber() < 0) { throw new BackupConfigurationException("The parameter 'incremental job number' can not be negative."); } if (config.getIncrementalJobPeriod() == 0 && config.getBackupType() == BackupManager.FULL_AND_INCREMENTAL) { config.setIncrementalJobPeriod(defaultIncrementalJobPeriod); } } /** * {@inheritDoc} */ public void stopBackup(BackupChain backup) { backup.stopBackup(); currentBackups.remove(backup); } /** * {@inheritDoc} */ public void start() { this.workspaceBackupStopper.start(); this.repositoryBackupStopper.start(); if (!PrivilegedFileHelper.exists(tempDir)) { throw new IllegalStateException("Directory " + tempDir.getAbsolutePath() + " not found. Please create it."); } //remove if exists all old jcrrestorewi*.tmp files. File[] files = PrivilegedFileHelper.listFiles(tempDir, new JcrRestoreWiFilter()); for (int i = 0; i < files.length; i++) { PrivilegedFileHelper.delete(files[i]); } // start all scheduled before tasks if (registryService != null && !registryService.getForceXMLConfigurationValue(initParams)) { SessionProvider sessionProvider = SessionProvider.createSystemProvider(); try { readParamsFromRegistryService(sessionProvider); } catch (Exception e) { readParamsFromFile(); try { writeParamsToRegistryService(sessionProvider); } catch (Exception exc) { LOG.error("Cannot write init configuration to RegistryService.", exc); } } finally { sessionProvider.close(); } } else { readParamsFromFile(); } } /** * {@inheritDoc} */ public void stop() { workspaceBackupStopper.close(); repositoryBackupStopper.close(); // 1. stop current backup chains // for (Iterator iterator = currentBackups.iterator(); iterator.hasNext();) { // BackupChain bc = (BackupChain) iterator.next(); // stopBackup(bc); // } // // // 2. stop all scheduled tasks // scheduler = null; } private void fullRestoreOverInitializer(String pathBackupFile, String repositoryName, WorkspaceEntry workspaceEntry, String fBackupType) throws FileNotFoundException, IOException, RepositoryException, RepositoryConfigurationException, ClassNotFoundException { WorkspaceInitializerEntry wieOriginal = workspaceEntry.getInitializer(); RepositoryImpl defRep = (RepositoryImpl)repoService.getRepository(repositoryName); WorkspaceInitializerEntry wiEntry = new WorkspaceInitializerEntry(); if ((ClassLoading.forName(fBackupType, this).equals(FullBackupJob.class))) { // set the initializer SysViewWorkspaceInitializer wiEntry.setType(SysViewWorkspaceInitializer.class.getCanonicalName()); List<SimpleParameterEntry> wieParams = new ArrayList<SimpleParameterEntry>(); wieParams.add(new SimpleParameterEntry(SysViewWorkspaceInitializer.RESTORE_PATH_PARAMETER, pathBackupFile)); wiEntry.setParameters(wieParams); } else if ((ClassLoading.forName(fBackupType, this) .equals(org.exoplatform.services.jcr.ext.backup.impl.rdbms.FullBackupJob.class))) { // set the initializer RdbmsWorkspaceInitializer wiEntry.setType(RdbmsWorkspaceInitializer.class.getCanonicalName()); List<SimpleParameterEntry> wieParams = new ArrayList<SimpleParameterEntry>(); wieParams.add(new SimpleParameterEntry(RdbmsWorkspaceInitializer.RESTORE_PATH_PARAMETER, new File( pathBackupFile).getParent())); wiEntry.setParameters(wieParams); } workspaceEntry.setInitializer(wiEntry); //restore defRep.configWorkspace(workspaceEntry); defRep.createWorkspace(workspaceEntry.getName()); //set original workspace initializer WorkspaceContainerFacade wcf = defRep.getWorkspaceContainer(workspaceEntry.getName()); WorkspaceEntry createdWorkspaceEntry = (WorkspaceEntry)wcf.getComponent(WorkspaceEntry.class); createdWorkspaceEntry.setInitializer(wieOriginal); } private void incrementalRestore(String pathBackupFile, String repositoryName, String workspaceName) throws RepositoryException, RepositoryConfigurationException, BackupOperationException, FileNotFoundException, IOException, ClassNotFoundException { WorkspaceContainerFacade workspaceContainer = repoService.getRepository(repositoryName).getWorkspaceContainer(workspaceName); WorkspacePersistentDataManager dataManager = (WorkspacePersistentDataManager)workspaceContainer.getComponent(WorkspacePersistentDataManager.class); FileCleanerHolder cleanerHolder = (FileCleanerHolder)workspaceContainer.getComponent(FileCleanerHolder.class); JCRRestore restorer = new JCRRestore(dataManager, cleanerHolder.getFileCleaner()); restorer.incrementalRestore(new File(pathBackupFile)); } /** * Write parameters to RegistryService. * * @param sessionProvider * The SessionProvider * @throws ParserConfigurationException * @throws SAXException * @throws IOException * @throws RepositoryException */ private void writeParamsToRegistryService(SessionProvider sessionProvider) throws IOException, SAXException, ParserConfigurationException, RepositoryException { Document doc = SecurityHelper.doPrivilegedParserConfigurationAction(new PrivilegedExceptionAction<Document>() { public Document run() throws Exception { return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); } }); Element root = doc.createElement(SERVICE_NAME); doc.appendChild(root); Element element = doc.createElement(BACKUP_PROPERTIES); setAttributeSmart(element, BACKUP_DIR, backupDir); setAttributeSmart(element, DEFAULT_INCREMENTAL_JOB_PERIOD, defIncrPeriod); setAttributeSmart(element, FULL_BACKUP_TYPE, fullBackupType); setAttributeSmart(element, INCREMENTAL_BACKUP_TYPE, incrementalBackupType); root.appendChild(element); RegistryEntry serviceEntry = new RegistryEntry(doc); registryService.createEntry(sessionProvider, RegistryService.EXO_SERVICES, serviceEntry); } /** * Read parameters from RegistryService. * * @param sessionProvider * The SessionProvider * @throws RepositoryException * @throws PathNotFoundException */ private void readParamsFromRegistryService(SessionProvider sessionProvider) throws PathNotFoundException, RepositoryException { String entryPath = RegistryService.EXO_SERVICES + "/" + SERVICE_NAME + "/" + BACKUP_PROPERTIES; RegistryEntry registryEntry = registryService.getEntry(sessionProvider, entryPath); Document doc = registryEntry.getDocument(); Element element = doc.getDocumentElement(); backupDir = getAttributeSmart(element, BACKUP_DIR); defIncrPeriod = getAttributeSmart(element, DEFAULT_INCREMENTAL_JOB_PERIOD); fullBackupType = getAttributeSmart(element, FULL_BACKUP_TYPE); incrementalBackupType = getAttributeSmart(element, INCREMENTAL_BACKUP_TYPE); LOG.info("Backup dir from RegistryService: " + backupDir); LOG.info("Default incremental job period from RegistryService: " + defIncrPeriod); LOG.info("Full backup type from RegistryService: " + fullBackupType); LOG.info("Incremental backup type from RegistryService: " + incrementalBackupType); checkParams(); } /** * Get attribute value. * * @param element * The element to get attribute value * @param attr * The attribute name * @return Value of attribute if present and null in other case */ private String getAttributeSmart(Element element, String attr) { return element.hasAttribute(attr) ? element.getAttribute(attr) : null; } /** * Set attribute value. If value is null the attribute will be removed. * * @param element * The element to set attribute value * @param attr * The attribute name * @param value * The value of attribute */ private void setAttributeSmart(Element element, String attr, String value) { if (value == null) { element.removeAttribute(attr); } else { element.setAttribute(attr, value); } } /** * Get parameters which passed from the file. * * @throws RepositoryConfigurationException */ private void readParamsFromFile() { PropertiesParam pps = initParams.getPropertiesParam(BACKUP_PROPERTIES); backupDir = pps.getProperty(BACKUP_DIR); // full backup type can be not defined. Using default. fullBackupType = pps.getProperty(FULL_BACKUP_TYPE) == null ? DEFAULT_VALUE_FULL_BACKUP_TYPE : pps.getProperty(FULL_BACKUP_TYPE); // incremental backup can be not configured. Using default values. defIncrPeriod = pps.getProperty(DEFAULT_INCREMENTAL_JOB_PERIOD) == null ? DEFAULT_VALUE_INCREMENTAL_JOB_PERIOD : pps .getProperty(DEFAULT_INCREMENTAL_JOB_PERIOD); incrementalBackupType = pps.getProperty(INCREMENTAL_BACKUP_TYPE) == null ? DEFAULT_VALUE_INCREMENTAL_BACKUP_TYPE : pps .getProperty(INCREMENTAL_BACKUP_TYPE); LOG.info("Backup dir from configuration file: " + backupDir); LOG.info("Full backup type from configuration file: " + fullBackupType); LOG.info("(Experimental) Incremental backup type from configuration file: " + incrementalBackupType); LOG.info("(Experimental) Default incremental job period from configuration file: " + defIncrPeriod); checkParams(); } /** * Check read params and initialize. */ private void checkParams() { if (backupDir == null) { throw new IllegalStateException(BACKUP_DIR + " not specified"); } logsDirectory = new File(backupDir); if (!PrivilegedFileHelper.exists(logsDirectory)) { if (!PrivilegedFileHelper.mkdirs(logsDirectory)) { throw new IllegalStateException("Could not create the backup directory at " + logsDirectory.getAbsolutePath()); } } if (defIncrPeriod == null) { throw new IllegalStateException(DEFAULT_INCREMENTAL_JOB_PERIOD + " not specified"); } defaultIncrementalJobPeriod = Integer.valueOf(defIncrPeriod); if (fullBackupType == null) { throw new IllegalStateException(FULL_BACKUP_TYPE + " not specified"); } if (incrementalBackupType == null) { throw new IllegalStateException(INCREMENTAL_BACKUP_TYPE + " not specified"); } } /** * {@inheritDoc} */ public BackupChain findBackup(String repository, String workspace) { Iterator<BackupChain> it = currentBackups.iterator(); while (it.hasNext()) { BackupChain chain = it.next(); if (repository.equals(chain.getBackupConfig().getRepository()) && workspace.equals(chain.getBackupConfig().getWorkspace())) { return chain; } } return null; } /** * {@inheritDoc} */ public BackupChain findBackup(String backupId) { Iterator<BackupChain> it = currentBackups.iterator(); while (it.hasNext()) { BackupChain chain = it.next(); if (backupId.equals(chain.getBackupId())) { return chain; } } return null; } /** * getLogsDirectory. * * @return File * return the logs directory */ File getLogsDirectory() { return logsDirectory; } /** * {@inheritDoc} */ public File getBackupDirectory() { return getLogsDirectory(); } /** * {@inheritDoc} */ public String getFullBackupType() { return fullBackupType; } /** * {@inheritDoc} */ public String getIncrementalBackupType() { return incrementalBackupType; } /** * {@inheritDoc} */ public long getDefaultIncrementalJobPeriod() { return defaultIncrementalJobPeriod; } /** * {@inheritDoc} */ public List<JobWorkspaceRestore> getRestores() { return restoreJobs; } /** * {@inheritDoc} */ public JobWorkspaceRestore getLastRestore(String repositoryName, String workspaceName) { for (int i = restoreJobs.size() - 1; i >= 0; i--) { JobWorkspaceRestore job = restoreJobs.get(i); if (repositoryName.equals(job.getRepositoryName()) && workspaceName.equals(job.getWorkspaceName())) { return job; } } return null; } /** * {@inheritDoc} */ public JobRepositoryRestore getLastRepositoryRestore(String repositoryName) { for (int i = restoreRepositoryJobs.size() - 1; i >= 0; i--) { JobRepositoryRestore job = restoreRepositoryJobs.get(i); if (repositoryName.equals(job.getRepositoryName())) { return job; } } return null; } public List<JobRepositoryRestore> getRepositoryRestores() { return restoreRepositoryJobs; } /** * {@inheritDoc} */ public void restore(BackupChainLog log, String repositoryName, WorkspaceEntry workspaceEntry, boolean asynchronous) throws BackupOperationException, BackupConfigurationException, RepositoryException, RepositoryConfigurationException { if (workspaceEntry == null) { if (!log.getBackupConfig().getRepository().equals(repositoryName)) { throw new WorkspaceRestoreException( "If workspaceEntry is null, so will be restored with original configuration. " + "The repositoryName (\"" + repositoryName + "\") should be equals original repository name (\"" + log.getBackupConfig().getRepository() + "\"). "); } if (log.getOriginalWorkspaceEntry() == null) { throw new RepositoryRestoreExeption("The backup log is not contains original repository log : " + log.getLogFilePath()); } this.restore(log, log.getBackupConfig().getRepository(), log.getOriginalWorkspaceEntry(), asynchronous); return; } if (asynchronous) { JobWorkspaceRestore jobRestore = new JobWorkspaceRestore(repoService, this, repositoryName, new File(log.getLogFilePath()), workspaceEntry); restoreJobs.add(jobRestore); jobRestore.start(); } else { this.restoreOverInitializer(log, repositoryName, workspaceEntry); } } /** * {@inheritDoc} */ public void restore(RepositoryBackupChainLog log, RepositoryEntry repositoryEntry, boolean asynchronous) throws BackupOperationException, BackupConfigurationException, RepositoryException, RepositoryConfigurationException { this.restore(log, repositoryEntry, asynchronous, false); } /** * {@inheritDoc} */ public void restore(RepositoryBackupChainLog log, RepositoryEntry repositoryEntry, boolean asynchronous, boolean removeJobOnceOver) throws BackupOperationException, BackupConfigurationException, RepositoryException, RepositoryConfigurationException { if (repositoryEntry == null) { if (log.getOriginalRepositoryEntry() == null) { throw new RepositoryRestoreExeption("The backup log is not contains original repository log : " + log.getLogFilePath()); } this.restore(log, log.getOriginalRepositoryEntry(), asynchronous); return; } this.restoreRepository(log, repositoryEntry, null, asynchronous, removeJobOnceOver); } /** * {@inheritDoc} */ public void restore(RepositoryBackupChainLog rblog, RepositoryEntry repositoryEntry, Map<String, String> workspaceNamesCorrespondMap, boolean asynchronous) throws BackupOperationException, BackupConfigurationException, RepositoryException, RepositoryConfigurationException { this.restoreRepository(rblog, repositoryEntry, workspaceNamesCorrespondMap, asynchronous, false); } /** * Repository restore from backup. * * @param log * RepositoryBackupChainLog, the repository backup log * @param repositoryEntry * RepositoryEntry, the repository entry * @param workspaceNamesCorrespondMap * Map<String, String>, the map with correspondence workspace name in RepositoryEntry and RepositoryBackupChainLog. * @param asynchronous * boolean, in 'true' then asynchronous restore. * @param removeJobOnceOver * boolean, in 'true' then restore job well remove after restore. * @throws BackupOperationException * will be generate the exception BackupOperationException * @throws BackupConfigurationException * will be generate the exception BackupConfigurationException * @throws RepositoryException * will be generate the exception RepositoryException * @throws RepositoryConfigurationException * will be generate the exception RepositoryConfigurationException */ private void restoreRepository(RepositoryBackupChainLog rblog, RepositoryEntry repositoryEntry, Map<String, String> workspaceNamesCorrespondMap, boolean asynchronous, boolean removeJobOnceOver) throws BackupOperationException, BackupConfigurationException, RepositoryException, RepositoryConfigurationException { // Checking repository exists. try { repoService.getRepository(repositoryEntry.getName()); throw new BackupConfigurationException("Repository \"" + repositoryEntry.getName() + "\" is already exists."); } catch (RepositoryException e) { //OK. Repository with "repositoryEntry.getName" is not exists. if (LOG.isTraceEnabled()) { LOG.trace("An exception occurred: " + e.getMessage()); } } Map<String, File> workspacesMapping = new HashedMap(); Map<String, BackupChainLog> backups = new HashedMap(); if (workspaceNamesCorrespondMap == null) { for (String path : rblog.getWorkspaceBackupsInfo()) { BackupChainLog bLog = new BackupChainLog(new File(path)); backups.put(bLog.getBackupConfig().getWorkspace(), bLog); } if (!rblog.getSystemWorkspace().equals(repositoryEntry.getSystemWorkspaceName())) { throw new BackupConfigurationException( "The backup to system workspace is not system workspace in repository entry: " + rblog.getSystemWorkspace() + " is not equal " + repositoryEntry.getSystemWorkspaceName()); } if (backups.size() != repositoryEntry.getWorkspaceEntries().size()) { throw new BackupConfigurationException( "The repository entry is contains more or less workspace entry than backups of workspace in " + rblog.getLogFilePath()); } for (WorkspaceEntry wsEntry : repositoryEntry.getWorkspaceEntries()) { if (!backups.containsKey(wsEntry.getName())) { throw new BackupConfigurationException("The workspace '" + wsEntry.getName() + "' is not found in backup " + rblog.getLogFilePath()); } else { workspacesMapping.put(wsEntry.getName(), new File (backups.get(wsEntry.getName()).getLogFilePath())); } } } else { // Create map [new_ws_name : backupLog to that workspace]. for (String path : rblog.getWorkspaceBackupsInfo()) { BackupChainLog bLog = new BackupChainLog(new File(path)); if (!workspaceNamesCorrespondMap.containsKey(bLog.getBackupConfig().getWorkspace())) { throw new BackupConfigurationException("Can not found coresptonding workspace name to workspace '" + bLog.getBackupConfig().getWorkspace() + "' in " + workspaceNamesCorrespondMap.keySet()); } backups.put(workspaceNamesCorrespondMap.get(bLog.getBackupConfig().getWorkspace()), bLog); } // Checking system workspace. if (!repositoryEntry.getSystemWorkspaceName().equals( workspaceNamesCorrespondMap.get(rblog.getSystemWorkspace()))) { throw new BackupConfigurationException( "The backup to system workspace is not system workspace in repository entry: " + repositoryEntry.getSystemWorkspaceName() + " is not equal " + workspaceNamesCorrespondMap.get(rblog.getSystemWorkspace())); } // Checking count of corresponding workspaces. if (workspaceNamesCorrespondMap.size() != repositoryEntry.getWorkspaceEntries().size()) { throw new BackupConfigurationException( "The repository entry is contains more or less workspace entry than backups of workspace in " + rblog.getLogFilePath()); } for (WorkspaceEntry wsEntry : repositoryEntry.getWorkspaceEntries()) { if (!workspaceNamesCorrespondMap.containsValue(wsEntry.getName())) { throw new BackupConfigurationException("The workspace '" + wsEntry.getName() + "' is not found workspaceNamesCorrespondMap : " + workspaceNamesCorrespondMap.values()); } else if (!backups.containsKey(wsEntry.getName())) { throw new BackupConfigurationException("The workspace '" + wsEntry.getName() + "' is not found in backup " + rblog.getLogFilePath()); } else { workspacesMapping.put(wsEntry.getName(), new File(backups.get(wsEntry.getName()).getLogFilePath())); } } } JobRepositoryRestore jobRepositoryRestore = new JobRepositoryRestore(repoService, this, repositoryEntry, workspacesMapping, new File(rblog.getLogFilePath()), removeJobOnceOver); restoreRepositoryJobs.add(jobRepositoryRestore); if (asynchronous) { jobRepositoryRestore.start(); } else { jobRepositoryRestore.restore(); } } /** * {@inheritDoc} */ public RepositoryBackupChain startBackup(RepositoryBackupConfig config) throws BackupOperationException, BackupConfigurationException, RepositoryException, RepositoryConfigurationException { validateBackupConfig(config); File dir = new File(config.getBackupDir() + File.separator + "repository_" + config.getRepository() + "_backup_" + System.currentTimeMillis()); PrivilegedFileHelper.mkdirs(dir); config.setBackupDir(dir); RepositoryBackupChain repositoryBackupChain = new RepositoryBackupChainImpl(config, logsDirectory, repoService, fullBackupType, incrementalBackupType, IdGenerator.generate()); repositoryBackupChain.startBackup(); currentRepositoryBackups.add(repositoryBackupChain); return repositoryBackupChain; } /** * {@inheritDoc} */ public void stopBackup(RepositoryBackupChain backup) { backup.stopBackup(); currentRepositoryBackups.remove(backup); } /** * {@inheritDoc} */ public RepositoryBackupChain findRepositoryBackup(String repository) { Iterator<RepositoryBackupChain> it = currentRepositoryBackups.iterator(); while (it.hasNext()) { RepositoryBackupChain chain = it.next(); if (repository.equals(chain.getBackupConfig().getRepository())) { return chain; } } return null; } /** * {@inheritDoc} */ public Set<RepositoryBackupChain> getCurrentRepositoryBackups() { return currentRepositoryBackups; } /** * {@inheritDoc} */ public RepositoryBackupChain findRepositoryBackupId(String backupId) { Iterator<RepositoryBackupChain> it = currentRepositoryBackups.iterator(); while (it.hasNext()) { RepositoryBackupChain chain = it.next(); if (backupId.equals(chain.getBackupId())) { return chain; } } return null; } /** * {@inheritDoc} */ public void restoreExistingRepository(RepositoryBackupChainLog rblog, RepositoryEntry repositoryEntry, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { try { // repository should be existed repoService.getRepository(repositoryEntry.getName()); } catch (RepositoryException e) { throw new RepositoryRestoreExeption("Repository \"" + repositoryEntry.getName() + "\" should be existed", e); } catch (RepositoryConfigurationException e) { throw new RepositoryRestoreExeption("Repository \"" + repositoryEntry.getName() + "\" should be existed", e); } Map<String, File> workspacesMapping = new HashedMap(); Map<String, BackupChainLog> backups = new HashedMap(); for (String path : rblog.getWorkspaceBackupsInfo()) { BackupChainLog bLog = new BackupChainLog(new File(path)); backups.put(bLog.getBackupConfig().getWorkspace(), bLog); } if (!rblog.getSystemWorkspace().equals(repositoryEntry.getSystemWorkspaceName())) { throw new BackupConfigurationException( "The backup to system workspace is not system workspace in repository entry: " + rblog.getSystemWorkspace() + " is not equal " + repositoryEntry.getSystemWorkspaceName()); } if (backups.size() != repositoryEntry.getWorkspaceEntries().size()) { throw new BackupConfigurationException( "The repository entry is contains more or less workspace entry than backups of workspace in " + rblog.getLogFilePath()); } for (WorkspaceEntry wsEntry : repositoryEntry.getWorkspaceEntries()) { if (!backups.containsKey(wsEntry.getName())) { throw new BackupConfigurationException("The workspace '" + wsEntry.getName() + "' is not found in backup " + rblog.getLogFilePath()); } else { workspacesMapping.put(wsEntry.getName(), new File(backups.get(wsEntry.getName()).getLogFilePath())); } } // check if we have deal with RDBMS backup boolean isSameConfigRestore = false; try { BackupChainLog bclog = new BackupChainLog(workspacesMapping.get(repositoryEntry.getWorkspaceEntries().get(0).getName())); if (ClassLoading.forName(bclog.getFullBackupType(), this) .equals(org.exoplatform.services.jcr.ext.backup.impl.rdbms.FullBackupJob.class)) { String newConf = new JsonGeneratorImpl().createJsonObject(repositoryEntry).toString(); String currnetConf = new JsonGeneratorImpl().createJsonObject( repoService.getRepository(repositoryEntry.getName()).getConfiguration()).toString(); isSameConfigRestore = newConf.equals(currnetConf); } } catch (JsonException e) { this.LOG.error("Can't get JSON object from wokrspace configuration", e); } catch (RepositoryException e) { this.LOG.error(e); } catch (RepositoryConfigurationException e) { this.LOG.error(e); } catch (ClassNotFoundException e) { this.LOG.error(e); } JobRepositoryRestore jobExistedRepositoryRestore = isSameConfigRestore ? new JobExistingRepositorySameConfigRestore(repoService, this, repositoryEntry, workspacesMapping, new File(rblog.getLogFilePath())) : new JobExistingRepositoryRestore(repoService, this, repositoryEntry, workspacesMapping, new File(rblog.getLogFilePath())); restoreRepositoryJobs.add(jobExistedRepositoryRestore); if (asynchronous) { jobExistedRepositoryRestore.start(); } else { jobExistedRepositoryRestore.restore(); } } /** * {@inheritDoc} */ public void restoreExistingRepository(String repositoryBackupIdentifier, RepositoryEntry repositoryEntry, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { RepositoryBackupChainLog backupChainLog = null; for (RepositoryBackupChainLog chainLog : getRepositoryBackupsLogs()) { if (chainLog.getBackupId().equals(repositoryBackupIdentifier)) { backupChainLog = chainLog; break; } } if (backupChainLog == null) { throw new BackupConfigurationException("Can not found backup of repository with id \"" + repositoryBackupIdentifier + "\""); } this.restoreExistingRepository(backupChainLog, repositoryEntry, asynchronous); } /** * {@inheritDoc} */ public void restoreExistingWorkspace(BackupChainLog log, String repositoryName, WorkspaceEntry workspaceEntry, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { try { // repository should be existed repoService.getRepository(repositoryName); // workspace should be existed if (!workspaceAlreadyExist(repositoryName, workspaceEntry.getName())) { throw new WorkspaceRestoreException("Workspace \"" + workspaceEntry.getName() + "\" should be existed in repository \"" + repositoryName + "\"."); } } catch (RepositoryException e) { throw new WorkspaceRestoreException("Repository \"" + repositoryName + "\" should be existed", e); } catch (RepositoryConfigurationException e) { throw new WorkspaceRestoreException("Repository \"" + repositoryName + "\" should be existed", e); } // check if we need to use restore with same configuration as original // it allows to use atomic restore in cluster env boolean isSameConfigRestore = false; try { if (ClassLoading.forName(log.getFullBackupType(), this).equals( org.exoplatform.services.jcr.ext.backup.impl.rdbms.FullBackupJob.class)) { WorkspaceEntry currentWsEntry = null; for (WorkspaceEntry wsEntry : repoService.getRepository(repositoryName).getConfiguration() .getWorkspaceEntries()) { if (wsEntry.getName().equals(workspaceEntry.getName())) { currentWsEntry = wsEntry; break; } } String newConf = new JsonGeneratorImpl().createJsonObject(workspaceEntry).toString(); String currnetConf = new JsonGeneratorImpl().createJsonObject(currentWsEntry).toString(); isSameConfigRestore = newConf.equals(currnetConf); } } catch (JsonException e) { LOG.error("Can't get JSON object from wokrspace configuration", e); } catch (RepositoryException e) { LOG.error(e); } catch (RepositoryConfigurationException e) { LOG.error(e); } catch (ClassNotFoundException e) { LOG.error(e); } JobWorkspaceRestore jobRestore; if (isSameConfigRestore) { jobRestore = new JobExistingWorkspaceSameConfigRestore(repoService, this, repositoryName, new File(log.getLogFilePath()), workspaceEntry); } else { jobRestore = new JobExistingWorkspaceRestore(repoService, this, repositoryName, new File(log.getLogFilePath()), workspaceEntry); } restoreJobs.add(jobRestore); if (asynchronous) { jobRestore.start(); } else { try { jobRestore.restore(); } catch (Throwable e) //NOSONAR { throw new BackupOperationException(e); } } } /** * {@inheritDoc} */ public void restoreExistingWorkspace(String workspaceBackupIdentifier, String repositoryName, WorkspaceEntry workspaceEntry, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { BackupChainLog backupChainLog = null; for (BackupChainLog chainLog : getBackupsLogs()) { if (chainLog.getBackupId().equals(workspaceBackupIdentifier)) { backupChainLog = chainLog; break; } } if (backupChainLog == null) { throw new BackupConfigurationException("Can not found backup of workspace with id \"" + workspaceBackupIdentifier + "\""); } this.restoreExistingWorkspace(backupChainLog, repositoryName, workspaceEntry, asynchronous); } /** * {@inheritDoc} */ public void restoreExistingRepository(String repositoryBackupIdentifier, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { RepositoryBackupChainLog backupChainLog = null; for (RepositoryBackupChainLog chainLog : getRepositoryBackupsLogs()) { if (chainLog.getBackupId().equals(repositoryBackupIdentifier)) { backupChainLog = chainLog; break; } } if (backupChainLog == null) { throw new BackupConfigurationException("Can not found backup of repository with id \"" + repositoryBackupIdentifier + "\""); } this.restoreExistingRepository(backupChainLog, backupChainLog.getOriginalRepositoryEntry(), asynchronous); } /** * {@inheritDoc} */ public void restoreExistingWorkspace(String workspaceBackupIdentifier, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { BackupChainLog backupChainLog = null; for (BackupChainLog chainLog : getBackupsLogs()) { if (chainLog.getBackupId().equals(workspaceBackupIdentifier)) { backupChainLog = chainLog; break; } } if (backupChainLog == null) { throw new BackupConfigurationException("Can not found backup of workspace with id \"" + workspaceBackupIdentifier + "\""); } this.restoreExistingWorkspace(backupChainLog, backupChainLog.getBackupConfig().getRepository(), backupChainLog .getOriginalWorkspaceEntry(), asynchronous); } /** * {@inheritDoc} */ public void restoreRepository(String repositoryBackupIdentifier, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { RepositoryBackupChainLog backupChainLog = null; for (RepositoryBackupChainLog chainLog : getRepositoryBackupsLogs()) { if (chainLog.getBackupId().equals(repositoryBackupIdentifier)) { backupChainLog = chainLog; break; } } if (backupChainLog == null) { throw new BackupConfigurationException("Can not found backup of repository with id \"" + repositoryBackupIdentifier + "\""); } try { this.restore(backupChainLog, backupChainLog.getOriginalRepositoryEntry(), asynchronous); } catch (RepositoryException e) { throw new RepositoryRestoreExeption("Repository \"" + backupChainLog.getOriginalRepositoryEntry().getName() + "\" was not restored", e); } catch (RepositoryConfigurationException e) { throw new RepositoryRestoreExeption("Repository \"" + backupChainLog.getOriginalRepositoryEntry().getName() + "\" was not restored", e); } } /** * {@inheritDoc} */ public void restoreWorkspace(String workspaceBackupIdentifier, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { BackupChainLog backupChainLog = null; for (BackupChainLog chainLog : getBackupsLogs()) { if (chainLog.getBackupId().equals(workspaceBackupIdentifier)) { backupChainLog = chainLog; break; } } if (backupChainLog == null) { throw new BackupConfigurationException("Can not found backup of workspace with id \"" + workspaceBackupIdentifier + "\""); } try { this.restore(backupChainLog, backupChainLog.getBackupConfig().getRepository(), backupChainLog .getOriginalWorkspaceEntry(), asynchronous); } catch (RepositoryException e) { throw new WorkspaceRestoreException("Workapce \"" + backupChainLog.getOriginalWorkspaceEntry().getName() + "\" was not restored in repository \"" + backupChainLog.getBackupConfig().getRepository() + "\"", e); } catch (RepositoryConfigurationException e) { throw new WorkspaceRestoreException("Workapce \"" + backupChainLog.getOriginalWorkspaceEntry().getName() + "\" was not restored in repository \"" + backupChainLog.getBackupConfig().getRepository() + "\"", e); } } /** * {@inheritDoc} */ public void restoreExistingRepository(File repositoryBackupSetDir, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { File[] cfs = PrivilegedFileHelper.listFiles(repositoryBackupSetDir, new RepositoryBackupLogsFilter()); if (cfs.length == 0) { throw new BackupConfigurationException("Can not found repository backup log in directory : " + repositoryBackupSetDir.getPath()); } if (cfs.length > 1) { throw new BackupConfigurationException( "Backup set directory should contains only one repository backup log : " + repositoryBackupSetDir.getPath()); } RepositoryBackupChainLog backupChainLog = new RepositoryBackupChainLog(cfs[0]); this.restoreExistingRepository(backupChainLog, backupChainLog.getOriginalRepositoryEntry(), asynchronous); } /** * {@inheritDoc} */ public void restoreExistingWorkspace(File workspaceBackupSetDir, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { File[] cfs = PrivilegedFileHelper.listFiles(workspaceBackupSetDir, new BackupLogsFilter()); if (cfs.length == 0) { throw new BackupConfigurationException("Can not found workspace backup log in directory : " + workspaceBackupSetDir.getPath()); } if (cfs.length > 1) { throw new BackupConfigurationException("Backup set directory should contains only one workspace backup log : " + workspaceBackupSetDir.getPath()); } BackupChainLog backupChainLog = new BackupChainLog(cfs[0]); this.restoreExistingWorkspace(backupChainLog, backupChainLog.getBackupConfig().getRepository(), backupChainLog .getOriginalWorkspaceEntry(), asynchronous); } /** * {@inheritDoc} */ public void restoreRepository(File repositoryBackupSetDir, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { File[] cfs = PrivilegedFileHelper.listFiles(repositoryBackupSetDir, new RepositoryBackupLogsFilter()); if (cfs.length == 0) { throw new BackupConfigurationException("Can not found repository backup log in directory : " + repositoryBackupSetDir.getPath()); } if (cfs.length > 1) { throw new BackupConfigurationException( "Backup set directory should contains only one repository backup log : " + repositoryBackupSetDir.getPath()); } RepositoryBackupChainLog backupChainLog = new RepositoryBackupChainLog(cfs[0]); try { this.restore(backupChainLog, backupChainLog.getOriginalRepositoryEntry(), asynchronous); } catch (RepositoryException e) { throw new RepositoryRestoreExeption("Repository \"" + backupChainLog.getOriginalRepositoryEntry().getName() + "\" was not restored", e); } catch (RepositoryConfigurationException e) { throw new RepositoryRestoreExeption("Repository \"" + backupChainLog.getOriginalRepositoryEntry().getName() + "\" was not restored", e); } } /** * {@inheritDoc} */ public void restoreWorkspace(File workspaceBackupSetDir, boolean asynchronous) throws BackupOperationException, BackupConfigurationException { File[] cfs = PrivilegedFileHelper.listFiles(workspaceBackupSetDir, new BackupLogsFilter()); if (cfs.length == 0) { throw new BackupConfigurationException("Can not found workspace backup log in directory : " + workspaceBackupSetDir.getPath()); } if (cfs.length > 1) { throw new BackupConfigurationException("Backup set directory should contains only one workspace backup log : " + workspaceBackupSetDir.getPath()); } BackupChainLog backupChainLog = new BackupChainLog(cfs[0]); try { this.restore(backupChainLog, backupChainLog.getBackupConfig().getRepository(), backupChainLog .getOriginalWorkspaceEntry(), asynchronous); } catch (RepositoryException e) { throw new WorkspaceRestoreException("Workapce \"" + backupChainLog.getOriginalWorkspaceEntry().getName() + "\" was not restored in repository \"" + backupChainLog.getBackupConfig().getRepository() + "\"", e); } catch (RepositoryConfigurationException e) { throw new WorkspaceRestoreException("Workapce \"" + backupChainLog.getOriginalWorkspaceEntry().getName() + "\" was not restored in repository \"" + backupChainLog.getBackupConfig().getRepository() + "\"", e); } } }