org.exoplatform.services.jcr.ext.backup.impl.BackupManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.exoplatform.services.jcr.ext.backup.impl.BackupManagerImpl.java

Source

/*
 * 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);
        }

    }
}