/* * Copyright (C) 2003-2017 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.management.backup.operations; import org.apache.commons.lang.StringUtils; import org.exoplatform.container.PortalContainer; import org.exoplatform.management.backup.service.BackupInProgressException; import org.exoplatform.management.backup.service.idm.IDMBackup; import org.exoplatform.management.backup.service.jcr.JCRBackup; import org.exoplatform.management.backup.service.webui.BackupExceptionHandlerLifeCycle; import org.exoplatform.management.common.AbstractOperationHandler; import org.exoplatform.management.service.impl.StagingMessageREST; import org.exoplatform.portal.application.PortalRequestContext; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.scheduler.JobSchedulerService; import org.exoplatform.web.application.Application; import org.exoplatform.web.application.ApplicationLifecycle; import org.gatein.management.api.exceptions.OperationException; import org.gatein.management.api.operation.OperationAttributes; import org.gatein.management.api.operation.OperationContext; import org.gatein.management.api.operation.OperationNames; import org.gatein.management.api.operation.ResultHandler; import org.gatein.management.api.operation.model.NoResultModel; import java.io.File; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * The Class BackupExportResource. * * @author <a href="mailto:boubaker.khanfir@exoplatform.com">Boubaker * Khanfir</a> * @version $Revision$ */ public class BackupExportResource extends AbstractOperationHandler { /** The Constant log. */ private static final Log log = ExoLogger.getLogger(BackupExportResource.class); /** The Constant backupDirPattern. */ private static final Pattern backupDirPattern = Pattern.compile("^directory:(.*)$"); /** The Constant WRITE_STRATEGY_SUSPEND. */ public static final String WRITE_STRATEGY_SUSPEND = "suspend"; /** The Constant WRITE_STRATEGY_EXCEPTION. */ public static final String WRITE_STRATEGY_EXCEPTION = "exception"; /** The Constant WRITE_STRATEGY_NOTHING. */ public static final String WRITE_STRATEGY_NOTHING = "nothing"; /** The Constant DISPLAY_MESSAGE_FOR_ALL. */ public static final String DISPLAY_MESSAGE_FOR_ALL = "all"; /** The Constant DISPLAY_MESSAGE_FOR_ADMIN. */ public static final String DISPLAY_MESSAGE_FOR_ADMIN = "admin"; /** The Constant DATE_FORMAT. */ public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yy-MMM-dd-HH-mm-ss"); /** The backup in progress. */ public static boolean backupInProgress = false; /** The write strategy. */ public static String writeStrategy = null; /** The display message for. */ public static String displayMessageFor = null; /** The message. */ public static String message = null; /** The job scheduler service. */ private JobSchedulerService jobSchedulerService = null; /** * {@inheritDoc} */ @Override public void execute(OperationContext operationContext, ResultHandler resultHandler) throws OperationException { if (backupInProgress) { throw new BackupInProgressException(); } String portalContainerName = operationContext.getAddress().resolvePathTemplate("portal"); PortalContainer portalContainer = getPortalContainer(portalContainerName); StagingMessageREST stagingMessageREST = (StagingMessageREST) portalContainer.getComponentInstanceOfType(StagingMessageREST.class); increaseCurrentTransactionTimeOut(portalContainer); // Suspend Thread Schedulers jobSchedulerService = (JobSchedulerService) portalContainer.getComponentInstanceOfType(JobSchedulerService.class); jobSchedulerService.suspend(); OperationAttributes attributes = operationContext.getAttributes(); backupInProgress = true; writeStrategy = null; displayMessageFor = null; message = null; try { String exportJCRString = attributes.getValue("export-jcr"); String exportIDMString = attributes.getValue("export-idm"); boolean exportJCR = StringUtils.isEmpty(exportJCRString) ? true : exportJCRString.trim().equalsIgnoreCase("true"); boolean exportIDM = StringUtils.isEmpty(exportIDMString) ? true : exportIDMString.trim().equalsIgnoreCase("true"); writeStrategy = attributes.getValue("writeStrategy"); displayMessageFor = attributes.getValue("displayMessageFor"); message = attributes.getValue("message"); stagingMessageREST.setDisplayForAll(DISPLAY_MESSAGE_FOR_ALL.equals(displayMessageFor)); stagingMessageREST.setMessage(message); stagingMessageREST.setPosition("top-center"); File backupDirFile = getBackupDirectoryFile(attributes, true); if (!exportIDM && !exportJCR) { throw new OperationException(OperationNames.EXPORT_RESOURCE, "You have to choose IDM, JCR or both datas to backup."); } if (BackupExportResource.WRITE_STRATEGY_EXCEPTION.equals(BackupExportResource.writeStrategy)) { handleWriteOperations(); } String backupParentFolder = backupDirFile.getAbsolutePath() + File.separator + "Backup-" + DATE_FORMAT.format(Calendar.getInstance().getTime()); backupDirFile = new File(backupParentFolder); if (!backupDirFile.mkdir()) { throw new IllegalStateException("Cannot create directory: " + backupParentFolder + ". " + (backupDirFile.exists() ? " It already exists." : "")); } if (exportJCR) { // Backup JCR log.info("Start full backup of repository to directory: " + backupDirFile); JCRBackup.backup(portalContainer, backupDirFile); } if (exportIDM) { // Backup IDM log.info("Start full backup of IDM to directory: " + backupDirFile); IDMBackup.backup(portalContainer, backupDirFile); } log.info("Backup operation finished successfully. Files under {} ", backupDirFile); // Nothing to return here resultHandler.completed(NoResultModel.INSTANCE); } catch (Exception e) { throw new OperationException(OperationNames.EXPORT_RESOURCE, e.getMessage(), e); } finally { backupInProgress = false; stagingMessageREST.readParametersFromProperties(); jobSchedulerService.resume(); restoreDefaultTransactionTimeOut(portalContainer); if (BackupExportResource.WRITE_STRATEGY_EXCEPTION.equals(BackupExportResource.writeStrategy)) { deleteWriteOperationHandler(); } } } /** * Handle write operations. */ private void handleWriteOperations() { deleteWriteOperationHandler(); PortalRequestContext portalRequestContext = PortalRequestContext.getCurrentInstance(); Application application = portalRequestContext.getApplication(); application.getApplicationLifecycle().add(new BackupExceptionHandlerLifeCycle()); } /** * Delete write operation handler. */ private void deleteWriteOperationHandler() { PortalRequestContext portalRequestContext = PortalRequestContext.getCurrentInstance(); Application application = portalRequestContext.getApplication(); @SuppressWarnings("rawtypes") Iterator<ApplicationLifecycle> applicationLifecycleIterator = application.getApplicationLifecycle().iterator(); while (applicationLifecycleIterator.hasNext()) { ApplicationLifecycle<?> applicationLifecycle = (ApplicationLifecycle<?>) applicationLifecycleIterator.next(); if (applicationLifecycle instanceof BackupExceptionHandlerLifeCycle) { applicationLifecycleIterator.remove(); } } } /** * Gets the backup directory file. * * @param attributes the attributes * @param create the create * @return the backup directory file */ public static File getBackupDirectoryFile(OperationAttributes attributes, boolean create) { String backupDir = attributes.getValue("directory"); if (backupDir == null) { List<String> filters = attributes.getValues("filter"); if (filters != null && !filters.isEmpty()) { for (String filter : filters) { Matcher dirMatcher = backupDirPattern.matcher(filter); if (dirMatcher.matches()) { backupDir = dirMatcher.group(1); continue; } } } } if (backupDir == null) { throw new IllegalArgumentException("backup directory was not found: " + backupDir); } File backupDirFile = new File(backupDir); if (!backupDirFile.exists() && create) { backupDirFile.mkdirs(); } return backupDirFile; } }