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