package org.jboss.system.server.profileservice.repository.clustered.local.file;
import java.io.File;
import java.io.IOException;
import org.jboss.logging.Logger;
import org.jboss.system.server.profileservice.repository.clustered.sync.AbstractContentMetadataMutatorAction;
import org.jboss.system.server.profileservice.repository.clustered.sync.ContentModification;
public abstract class AbstractLocalContentChangeAction
extends AbstractContentMetadataMutatorAction<FileBasedSynchronizationActionContext>
{
private final File targetFile;
private final boolean targetWasDir;
private final boolean targetExists;
private final long targetTimestamp;
private File tempRollback;
/**
* Create a new AbstractLocalContentChangeAction.
*
* @param targetFile the file whose content is to be changed
* @param context the overall context of the modification
* @param modification the modification
*/
protected AbstractLocalContentChangeAction(File targetFile, FileBasedSynchronizationActionContext context,
ContentModification modification)
{
super(context, modification);
if (targetFile == null)
{
throw new IllegalArgumentException("Null targetFile");
}
this.targetFile = targetFile;
this.targetWasDir = targetFile.isDirectory();
this.targetExists = targetFile.exists();
this.targetTimestamp = targetFile.lastModified();
}
protected abstract Logger getLogger();
protected abstract boolean modifyTarget() throws IOException;
protected File getTargetFile()
{
return targetFile;
}
@Override
protected void doCancel()
{
safeCleanup();
}
@Override
protected void doComplete() throws Exception
{
if (getLogger().isTraceEnabled())
{
ContentModification mod = getRepositoryContentModification();
getLogger().trace("doComplete(): " + mod.getType() + " for " + mod.getItem().getRelativePath());
}
}
@Override
protected boolean doPrepare()
{
File backup = null;
try
{
if (targetExists)
{
if (!targetWasDir)
{
// Make a backup copy of target in case of rollback
backup = createTempFile();
FileUtil.localMove(targetFile, backup, targetTimestamp);
// assign after creation so the ref to the file
// indicates a successful write -- useful in rollback
this.tempRollback = backup;
}
else
{
// No backup copy needed; we can just recreate
targetFile.delete();
}
}
boolean result = modifyTarget();
if (getLogger().isTraceEnabled())
{
ContentModification mod = getRepositoryContentModification();
getLogger().trace("doPrepare(): modifyTarget result for " +
mod.getType() + " for " + mod.getItem().getRelativePath() +
" is " + result);
}
return result;
}
catch (Exception e)
{
getLogger().error("Caught exception in doPrepare() ", e);
if (backup != null && tempRollback == null)
{
// We failed during backup creation.
// Discard unneeded backup copy
backup.delete();
}
}
return false;
}
@Override
protected void doRollbackFromCancelled()
{
// no-op
}
@Override
protected void doRollbackFromComplete()
{
safeCleanup();
}
@Override
protected void doRollbackFromOpen()
{
safeCleanup();
}
@Override
protected void doRollbackFromPrepared()
{
boolean cleanRollback = true;
rollbackContentMetadata();
if (targetWasDir)
{
targetFile.delete();
targetFile.mkdirs();
targetFile.setLastModified(targetTimestamp);
}
else if (targetExists)
{
// Restore it
try
{
FileUtil.localMove(tempRollback, targetFile, this.targetTimestamp);
}
catch (IOException e)
{
getLogger().error("Failed restoring " + targetFile + " during rollback. " +
"Backup copy is stored in " + tempRollback, e);
// Don't discard the rollback file
cleanRollback = false;
}
}
else
{
targetFile.delete();
}
safeCleanup(cleanRollback);
}
@Override
protected void doRollbackFromRollbackOnly()
{
boolean cleanRollback = true;
// We get here either from complete or from prepare. We
// can tell which by whether tempRollback exists
if (tempRollback != null && tempRollback.exists())
{
// Restore it
try
{
FileUtil.localMove(tempRollback, targetFile, targetTimestamp);
}
catch (IOException e)
{
getLogger().error("Failed restoring " + targetFile + " during rollback. " +
"Backup copy is stored in " + tempRollback, e);
// Don't discard the rollback file
cleanRollback = false;
}
}
else if (targetWasDir)
{
if (targetFile.exists())
{
if (targetFile.isDirectory() == false)
{
targetFile.delete();
targetFile.mkdirs();
targetFile.setLastModified(targetTimestamp);
}
}
else
{
targetFile.mkdirs();
targetFile.setLastModified(targetTimestamp);
}
}
else if (targetExists == false)
{
// if we created one, get rid of it
targetFile.delete();
}
safeCleanup(cleanRollback);
}
@Override
protected void doCommit()
{
updateContentMetadata();
safeCleanup();
}
protected File createTempFile() throws IOException
{
FileBasedSynchronizationActionContext ctx = getContext();
File f = FileUtil.createTempFile(ctx.getTempDir(), ctx.getStoreName());
f.deleteOnExit();
return f;
}
protected synchronized void safeCleanup(boolean cleanRollback)
{
if (cleanRollback && tempRollback != null)
{
tempRollback.delete();
}
}
protected void safeCleanup()
{
safeCleanup(true);
}
}