/* * Copyright (C) 2012 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.impl.quota; import org.exoplatform.commons.utils.PrivilegedFileHelper; import org.exoplatform.commons.utils.PrivilegedSystemHelper; import org.exoplatform.commons.utils.SecurityHelper; import org.exoplatform.services.jcr.impl.backup.BackupException; import org.exoplatform.services.jcr.impl.backup.Backupable; import org.exoplatform.services.jcr.impl.backup.DataRestore; import org.exoplatform.services.jcr.impl.backup.rdbms.DBBackup; import org.exoplatform.services.jcr.impl.backup.rdbms.DataRestoreContext; import org.exoplatform.services.jcr.impl.dataflow.serialization.ZipObjectReader; import org.exoplatform.services.jcr.impl.dataflow.serialization.ZipObjectWriter; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import java.io.File; import java.io.IOException; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; /** * {@link DataRestore} implementation for quota. * * @author <a href="abazko@exoplatform.com">Anatoliy Bazko</a> * @version $Id: WorkspaceQuotaRestore.java Aug 13, 2012 tolusha $ */ public class WorkspaceQuotaRestore implements DataRestore { /** * Logger. */ protected final Log LOG = ExoLogger.getLogger("exo.jcr.component.core.WorkspaceQuotaRestore"); /** * File name for backuped data. */ protected static final String BACKUP_FILE_NAME = "quota"; /** * File where temporary data are stored will be restored at rollback. */ private final File tempFile; /** * File where backuped data are stored. */ private final File backupFile; /** * {@link WorkspaceQuotaManager} instance. */ private final WorkspaceQuotaManager wqm; /** * Workspace name. */ private final String wsName; /** * Repository name. */ private final String rName; /** * {@link QuotaPersister} */ private final QuotaPersister quotaPersister; /** * WorkspaceQuotaRestore constructor. */ WorkspaceQuotaRestore(WorkspaceQuotaManager wqm, DataRestoreContext context) { this(wqm, (File)context.getObject(DataRestoreContext.STORAGE_DIR)); } /** * WorkspaceQuotaRestore constructor. */ WorkspaceQuotaRestore(WorkspaceQuotaManager wqm, File storageDir) { this.wqm = wqm; this.backupFile = new File(storageDir, BACKUP_FILE_NAME + DBBackup.CONTENT_FILE_SUFFIX); File tempDir = new File(PrivilegedSystemHelper.getProperty("java.io.tmpdir")); this.tempFile = new File(tempDir, "temp.dump"); this.wsName = wqm.getContext().wsName; this.rName = wqm.getContext().rName; this.quotaPersister = wqm.getContext().quotaPersister; } /** * {@inheritDoc} */ public void clean() throws BackupException { try { SecurityHelper.doPrivilegedExceptionAction(new PrivilegedExceptionAction<Void>() { public Void run() throws BackupException { doBackup(tempFile); doClean(); return null; } }); } catch (PrivilegedActionException e) { Throwable cause = e.getCause(); if (cause instanceof BackupException) { throw (BackupException)cause; } else { throw new BackupException(cause); } } } /** * {@inheritDoc} */ public void restore() throws BackupException { doRestore(backupFile); } /** * {@inheritDoc} */ public void commit() throws BackupException { } /** * {@inheritDoc} */ public void rollback() throws BackupException { doClean(); doRestore(tempFile); } /** * {@inheritDoc} */ public void close() throws BackupException { PrivilegedFileHelper.delete(tempFile); } /** * {@link Backupable#backup(File)} */ public void backup() throws BackupException { doBackup(backupFile); } /** * Restores content. */ protected void doRestore(File backupFile) throws BackupException { if (!PrivilegedFileHelper.exists(backupFile)) { LOG.warn("Nothing to restore for quotas"); return; } ZipObjectReader in = null; try { in = new ZipObjectReader(PrivilegedFileHelper.zipInputStream(backupFile)); quotaPersister.restoreWorkspaceData(rName, wsName, in); } catch (IOException e) { throw new BackupException(e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { LOG.error("Can't close input stream", e); } } } repairDataSize(); } /** * After workspace data size being restored, need also to update * repository and global data size on respective value. */ private void repairDataSize() { try { long dataSize = quotaPersister.getWorkspaceDataSize(rName, wsName); ChangesItem changesItem = new ChangesItem(); changesItem.updateWorkspaceChangedSize(dataSize); quotaPersister.setWorkspaceDataSize(rName, wsName, 0); // workaround Runnable task = new ApplyPersistedChangesTask(wqm.getContext(), changesItem); task.run(); } catch (UnknownDataSizeException e) { if (LOG.isTraceEnabled()) { LOG.trace(e.getMessage(), e); } } } /** * Backups data to define file. */ protected void doBackup(File backupFile) throws BackupException { ZipObjectWriter out = null; try { out = new ZipObjectWriter(PrivilegedFileHelper.zipOutputStream(backupFile)); quotaPersister.backupWorkspaceData(rName, wsName, out); } catch (IOException e) { throw new BackupException(e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { LOG.error("Can't close output stream", e); } } } } /** * Clean workspace data. Also decrease repository and global data size. */ protected void doClean() throws BackupException { try { long dataSize = wqm.quotaPersister.getWorkspaceDataSize(rName, wsName); ChangesItem changesItem = new ChangesItem(); changesItem.updateWorkspaceChangedSize(-dataSize); Runnable task = new ApplyPersistedChangesTask(wqm.getContext(), changesItem); task.run(); } catch (UnknownDataSizeException e) { if (LOG.isTraceEnabled()) { LOG.trace(e.getMessage(), e); } } quotaPersister.clearWorkspaceData(wqm.rName, wqm.wsName); } }