/* * Copyright (C) 2003-2010 eXo Platform SAS. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see<http://www.gnu.org/licenses/>. */ package org.exoplatform.services.jcr.ext.backup.impl; import org.exoplatform.commons.utils.ClassLoading; 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.ManageableRepository; import org.exoplatform.services.jcr.core.WorkspaceContainerFacade; import org.exoplatform.services.jcr.ext.backup.BackupChainLog; import org.exoplatform.services.jcr.ext.backup.BackupOperationException; import org.exoplatform.services.jcr.ext.backup.RepositoryBackupChainLog; import org.exoplatform.services.jcr.ext.backup.RepositoryRestoreExeption; import org.exoplatform.services.jcr.ext.backup.impl.fs.FullBackupJob; import org.exoplatform.services.jcr.ext.backup.impl.rdbms.RdbmsBackupWorkspaceInitializer; import org.exoplatform.services.jcr.impl.core.BackupWorkspaceInitializer; import org.exoplatform.services.jcr.impl.core.RepositoryImpl; import org.exoplatform.services.jcr.impl.core.SessionRegistry; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import java.io.File; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Map; import javax.jcr.InvalidItemStateException; import javax.jcr.NoSuchWorkspaceException; import javax.jcr.RepositoryException; /** * Created by The eXo Platform SAS. * * <br>Date: 2010 * * @author <a href="mailto:alex.reshetnyak@exoplatform.com.ua">Alex Reshetnyak</a> * @version $Id$ */ public class JobRepositoryRestore extends Thread { /** * The apache logger. */ protected static final Log LOG = ExoLogger.getLogger("exo.jcr.component.ext.JobRepositoryRestore"); /** * REPOSITORY_RESTORE_STARTED. The state of start restore. */ public static final int REPOSITORY_RESTORE_STARTED = 1; /** * REPOSITORY_RESTORE_SUCCESSFUL. The state of restore successful. */ public static final int REPOSITORY_RESTORE_SUCCESSFUL = 2; /** * REPOSITORY_RESTORE_FAIL. The state of restore fail. */ public static final int REPOSITORY_RESTORE_FAIL = 3; /** * REPOSITORY_RESTORE_STARTED. The state of initialized restore. */ public static final int REPOSITORY_RESTORE_INITIALIZED = 4; /** * The state of restore. */ private int stateRestore; /** * The start time of restore. */ private Calendar startTime; /** * The end time of restore. */ private Calendar endTime; /** * The exception on restore. */ private Throwable restoreException = null; protected RepositoryService repositoryService; private BackupManagerImpl backupManager; protected RepositoryEntry repositoryEntry; protected Map<String, File> workspacesMapping; private File repositoryBackupChainLogFile; /** * removeJobOnceOver, in 'true' then restore job well remove after restore. */ private boolean removeJobOnceOver; public JobRepositoryRestore(RepositoryService repoService, BackupManagerImpl backupManagerImpl, RepositoryEntry repositoryEntry, Map<String, File> workspacesMapping, File backupChainLog, boolean removeJobOnceOver) { super("JobRepositoryRestore " + repositoryEntry.getName()); this.repositoryService = repoService; this.backupManager = backupManagerImpl; this.repositoryEntry = repositoryEntry; this.workspacesMapping = workspacesMapping; this.repositoryBackupChainLogFile = backupChainLog; this.removeJobOnceOver = removeJobOnceOver; } /** * Restore repository. Provide information about start and finish process. * * @throws RepositoryRestoreExeption * if exception occurred during restore */ final protected void restore() throws RepositoryRestoreExeption { try { stateRestore = REPOSITORY_RESTORE_STARTED; startTime = Calendar.getInstance(); restoreRepository(); stateRestore = REPOSITORY_RESTORE_SUCCESSFUL; endTime = Calendar.getInstance(); } catch (Throwable t) //NOSONAR { stateRestore = REPOSITORY_RESTORE_FAIL; restoreException = t; throw new RepositoryRestoreExeption(t.getMessage(), t); } finally { if (removeJobOnceOver) { backupManager.restoreRepositoryJobs.remove(this); } } } /** * Will be restored the workspace. * @throws RepositoryRestoreExeption * @throws ClassNotFoundException * @throws BackupOperationException * * @throws RepositoryRestoreExeption * @throws BackupOperationException * @throws ClassNotFoundException */ protected void restoreRepository() throws RepositoryRestoreExeption, BackupOperationException, ClassNotFoundException { List<WorkspaceEntry> originalWorkspaceEntrys = repositoryEntry.getWorkspaceEntries(); //Getting system workspace entry WorkspaceEntry systemWorkspaceEntry = null; for (WorkspaceEntry wsEntry : originalWorkspaceEntrys) { if (wsEntry.getName().equals(repositoryEntry.getSystemWorkspaceName())) { systemWorkspaceEntry = wsEntry; break; } } if (systemWorkspaceEntry == null) { throw new RepositoryRestoreExeption("Can not restore workspace \"" + repositoryEntry.getSystemWorkspaceName() + " in repository \"" + repositoryEntry.getName() + "\"." + " The related configuration cannot be found."); } WorkspaceInitializerEntry wieOriginal = systemWorkspaceEntry.getInitializer(); //getting backup chail log to system workspace. BackupChainLog systemBackupChainLog = new BackupChainLog(workspacesMapping.get(systemWorkspaceEntry.getName())); WorkspaceInitializerEntry wiEntry = getWorkspaceInitializerEntry(systemBackupChainLog); // set initializer systemWorkspaceEntry.setInitializer(wiEntry); ArrayList<WorkspaceEntry> newEntries = new ArrayList<WorkspaceEntry>(); newEntries.add(systemWorkspaceEntry); repositoryEntry.setWorkspaceEntries(newEntries); String currennWorkspaceName = repositoryEntry.getSystemWorkspaceName(); boolean restored = true; try { LOG.info("Trying to create the repository '" + repositoryEntry.getName() + "'"); repositoryService.createRepository(repositoryEntry); //set original initializer to created workspace. RepositoryImpl defRep = (RepositoryImpl)repositoryService.getRepository(repositoryEntry.getName()); WorkspaceContainerFacade wcf = defRep.getWorkspaceContainer(systemWorkspaceEntry.getName()); WorkspaceEntry createdWorkspaceEntry = (WorkspaceEntry)wcf.getComponent(WorkspaceEntry.class); createdWorkspaceEntry.setInitializer(wieOriginal); // save configuration to persistence (file or persister) repositoryService.getConfig().retain(); for (WorkspaceEntry wsEntry : originalWorkspaceEntrys) { if (!(wsEntry.getName().equals(repositoryEntry.getSystemWorkspaceName()))) { currennWorkspaceName = wsEntry.getName(); LOG.info("Trying to restore the workspace " + wsEntry.getName()); backupManager.restore(new BackupChainLog(workspacesMapping.get(wsEntry.getName())), repositoryEntry.getName(), wsEntry, false); } } } catch (InvalidItemStateException e) { restored = false; LOG.error( "Can not restore workspace \"" + currennWorkspaceName + " in repository \"" + repositoryEntry.getName() + "\".", e); throw new RepositoryRestoreExeption("Can not restore workspace \"" + currennWorkspaceName + " in repository \"" + repositoryEntry.getName() + "\"." + " There was database error.", e); } catch (Throwable t) //NOSONAR { restored = false; LOG.error( "Can not restore workspace \"" + currennWorkspaceName + " in repository \"" + repositoryEntry.getName() + "\".", t); throw new RepositoryRestoreExeption("Can not restore workspace \"" + currennWorkspaceName + " in repository \"" + repositoryEntry.getName() + "\".", t); } finally { if (!restored) { try { removeRepository(repositoryService, repositoryEntry.getName()); } catch (Throwable thr) //NOSONAR { LOG.error("The partly restored repository \"" + repositoryEntry.getName() + "\" can not be removed.", thr); } } } } /** * Remove repository. * * @param repositoryService * RepositoryService, the repository service * @param repositoryName * String, the repository name * @throws RepositoryException * will be generated the RepositoryException * @throws RepositoryConfigurationException */ protected void removeRepository(RepositoryService repositoryService, String repositoryName) throws RepositoryException, RepositoryConfigurationException { ManageableRepository mr = null; try { mr = repositoryService.getRepository(repositoryName); } catch (RepositoryException e) { // The repository not exist. if (LOG.isTraceEnabled()) { LOG.trace("An exception occurred: " + e.getMessage()); } } if (mr != null) { closeAllSession(mr); repositoryService.removeRepository(repositoryName); repositoryService.getConfig().retain(); // save configuration to persistence (file or persister) } } private WorkspaceInitializerEntry getWorkspaceInitializerEntry(BackupChainLog systemBackupChainLog) throws BackupOperationException, ClassNotFoundException { String fullBackupPath = systemBackupChainLog.getJobEntryInfos().get(0).getURL().getPath(); String fullbackupType = null; try { if ((ClassLoading.forName(systemBackupChainLog.getFullBackupType(), this).equals(FullBackupJob.class))) { fullbackupType = systemBackupChainLog.getFullBackupType(); } else if ((ClassLoading.forName(systemBackupChainLog.getFullBackupType(), this) .equals(org.exoplatform.services.jcr.ext.backup.impl.rdbms.FullBackupJob.class))) { fullbackupType = systemBackupChainLog.getFullBackupType(); } else { throw new BackupOperationException("Class \"" + systemBackupChainLog.getFullBackupType() + "\" is not support as full backup."); } } catch (ClassNotFoundException e) { throw new BackupOperationException("Class \"" + systemBackupChainLog.getFullBackupType() + "\" is not found.", e); } WorkspaceInitializerEntry wiEntry = new WorkspaceInitializerEntry(); if ((ClassLoading.forName(fullbackupType, this).equals(FullBackupJob.class))) { // set the initializer BackupWorkspaceInitializer wiEntry.setType(BackupWorkspaceInitializer.class.getCanonicalName()); List<SimpleParameterEntry> wieParams = new ArrayList<SimpleParameterEntry>(); wieParams.add(new SimpleParameterEntry(BackupWorkspaceInitializer.RESTORE_PATH_PARAMETER, (new File( fullBackupPath).getParent()))); wiEntry.setParameters(wieParams); } else if ((ClassLoading.forName(fullbackupType, this) .equals(org.exoplatform.services.jcr.ext.backup.impl.rdbms.FullBackupJob.class))) { // set the initializer RdbmsBackupWorkspaceInitializer wiEntry.setType(RdbmsBackupWorkspaceInitializer.class.getCanonicalName()); List<SimpleParameterEntry> wieParams = new ArrayList<SimpleParameterEntry>(); wieParams.add(new SimpleParameterEntry(RdbmsBackupWorkspaceInitializer.RESTORE_PATH_PARAMETER, (new File( fullBackupPath).getParent()))); wiEntry.setParameters(wieParams); } return wiEntry; } /** * Close all open session in repository * * @param mr * * @throws NoSuchWorkspaceException */ private void closeAllSession(ManageableRepository mr) throws NoSuchWorkspaceException { for (String wsName : mr.getWorkspaceNames()) { if (!mr.canRemoveWorkspace(wsName)) { WorkspaceContainerFacade wc = mr.getWorkspaceContainer(wsName); SessionRegistry sessionRegistry = (SessionRegistry)wc.getComponent(SessionRegistry.class); sessionRegistry.closeSessions(wsName); } } } /** * {@inheritDoc} */ @Override public void run() { try { restore(); } catch (Throwable t) //NOSONAR { LOG.error("The restore was fail", t); } } /** * getRestoreException. * * @return Throwable return the exception of repository restore. */ public Throwable getRestoreException() { return restoreException; } /** * getStateRestore. * * @return int return state of restore. */ public int getStateRestore() { return stateRestore; } /** * getBeginTime. * * @return Calendar return the start time of restore */ public Calendar getStartTime() { return startTime; } /** * getEndTime. * * @return Calendar return the end time of restore */ public Calendar getEndTime() { return endTime; } /** * getRepositoryName. * * @return String * the name of destination repository */ public String getRepositoryName() { return repositoryEntry.getName(); } /** * GetRepositoryBackupChainLog. * * @return repositoryBackupChainLog */ public RepositoryBackupChainLog getRepositoryBackupChainLog() throws BackupOperationException { return new RepositoryBackupChainLog(repositoryBackupChainLogFile); } /** * getRepositoryEntry. * * @return repositoryBackupChainLog */ public RepositoryEntry getRepositoryEntry() { return repositoryEntry; } }