currentInstances, Operation operation)
+ {
+ /**
+ * This scenario is triggered by a rename of a file matching
+ * the pattern
+ */
+ if(operation instanceof RenameFileOperation)
+ {
+ RenameFileOperation r = (RenameFileOperation)operation;
+
+ Matcher m = pattern.matcher(r.getTo());
+ if(m.matches())
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("New Scenario Double Rename Shuffle Instance strPattern:" + pattern + " matches" + r.getTo() );
+ }
+ ScenarioDoubleRenameShuffleInstance instance = new ScenarioDoubleRenameShuffleInstance();
+ instance.setTimeout(timeout);
+ instance.setRanking(ranking);
+ return instance;
+ }
+ }
+
+ // No not interested.
+ return null;
+
+ }
+
+ public void setPattern(String pattern)
+ {
+ this.pattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
+ this.strPattern = pattern;
+ }
+
+ public String getPattern()
+ {
+ return this.strPattern;
+ }
+
+ public void setTimeout(long timeout)
+ {
+ this.timeout = timeout;
+ }
+
+ public long getTimeout()
+ {
+ return timeout;
+ }
+
+ public void setRanking(Ranking ranking)
+ {
+ this.ranking = ranking;
+ }
+
+ public Ranking getRanking()
+ {
+ return ranking;
+ }
+}
diff --git a/source/java/org/alfresco/filesys/repo/rules/ScenarioDoubleRenameShuffleInstance.java b/source/java/org/alfresco/filesys/repo/rules/ScenarioDoubleRenameShuffleInstance.java
new file mode 100644
index 0000000000..f79f3a341e
--- /dev/null
+++ b/source/java/org/alfresco/filesys/repo/rules/ScenarioDoubleRenameShuffleInstance.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.filesys.repo.rules;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.filesys.repo.OpenFileMode;
+import org.alfresco.filesys.repo.rules.commands.CompoundCommand;
+import org.alfresco.filesys.repo.rules.commands.CopyContentCommand;
+import org.alfresco.filesys.repo.rules.commands.RenameFileCommand;
+import org.alfresco.filesys.repo.rules.operations.CreateFileOperation;
+import org.alfresco.filesys.repo.rules.operations.DeleteFileOperation;
+import org.alfresco.filesys.repo.rules.operations.OpenFileOperation;
+import org.alfresco.filesys.repo.rules.operations.RenameFileOperation;
+import org.alfresco.jlan.server.filesys.FileName;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This is an instance of a "double rename shuffle" triggered by rename of a file to a special pattern
+ * file matching a specified pattern. (*.backup.fm)
+ *
+ * a) Existing file moved out of the way. X.fm to X.backup.fm
+ * b) New file moved into place. X.fm.C29 X.fm
+ *
+ * If this filter is active then this is what happens.
+ * a) Existing file moved out of the way (Y to Z). Raname tracked.
+ * b) New file moved into place (X to Y). Scenario kicks in to change commands.
+ */
+public class ScenarioDoubleRenameShuffleInstance implements ScenarioInstance
+{
+ private static Log logger = LogFactory.getLog(ScenarioDoubleRenameShuffleInstance.class);
+
+ enum InternalState
+ {
+ NONE,
+ RENAME1,
+ RENAME2
+ }
+
+ InternalState internalState = InternalState.NONE;
+
+ private Date startTime = new Date();
+
+ private String fileMiddle;
+ private String fileFrom;
+ private String fileEnd;
+
+ private Ranking ranking;
+
+ /**
+ * Timeout in ms. Default 30 seconds.
+ */
+ private long timeout = 30000;
+
+ private boolean isComplete;
+
+ /**
+ * Keep track of re-names
+ */
+ private Maprenames = new HashMap();
+
+ /**
+ * Evaluate the next operation
+ * @param operation
+ */
+ public Command evaluate(Operation operation)
+ {
+
+ /**
+ * Anti-pattern : timeout
+ */
+ Date now = new Date();
+ if(now.getTime() > startTime.getTime() + getTimeout())
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("Instance timed out");
+ }
+ }
+
+ switch (internalState)
+ {
+
+ case NONE:
+
+ /**
+ * Looking for first rename Y(middle) to Z(end)
+ */
+ if(operation instanceof RenameFileOperation)
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("Got first rename - tracking rename: " + operation);
+ }
+ RenameFileOperation r = (RenameFileOperation)operation;
+ fileMiddle = r.getFrom();
+ fileEnd = r.getTo();
+ internalState = InternalState.RENAME1;
+ }
+ else
+ {
+ // anything else bomb out
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("State error, expected a RENAME");
+ }
+ isComplete = true;
+ }
+
+
+ case RENAME1:
+
+ /**
+ * Looking for the seconf of two renames X(createName) to Y(middle) to Z(end)
+ */
+ if(operation instanceof RenameFileOperation)
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("Tracking rename: " + operation);
+ }
+ RenameFileOperation r = (RenameFileOperation)operation;
+
+ // Now see if this rename makes a pair
+ if(fileMiddle.equalsIgnoreCase(r.getTo()))
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("Got second rename" );
+ }
+
+ fileFrom = r.getFrom();
+
+ /**
+ * This shuffle reverses the rename out of the way and then copies the
+ * content only. Finally it moves the temp file into place for the subsequent
+ * delete.
+ * a) Rename Z to Y (Reverse previous move)
+ * b) Copy Content from X to Y
+ * c) Rename X to Z (move temp file out to old location)
+ */
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("Go and shuffle! fromName:" + fileFrom + " middle: " + fileMiddle + " end: " + fileEnd);
+ }
+
+ String[] paths = FileName.splitPath(r.getFromPath());
+ String oldFolder = paths[0];
+
+ ArrayList commands = new ArrayList();
+ RenameFileCommand r1 = new RenameFileCommand(fileEnd, fileMiddle, r.getRootNodeRef(), oldFolder + "\\" + fileEnd, oldFolder + "\\" + fileMiddle);
+ CopyContentCommand copyContent = new CopyContentCommand(fileFrom, fileMiddle, r.getRootNodeRef(), oldFolder + "\\" + fileFrom, oldFolder + "\\" + fileMiddle);
+ RenameFileCommand r2 = new RenameFileCommand(fileFrom, fileEnd, r.getRootNodeRef(), oldFolder + "\\" + fileFrom, oldFolder + "\\" + fileEnd);
+
+ commands.add(r1);
+ commands.add(copyContent);
+ commands.add(r2);
+
+ isComplete = true;
+ return new CompoundCommand(commands);
+ }
+ }
+
+ break;
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean isComplete()
+ {
+ return isComplete;
+ }
+
+ @Override
+ public Ranking getRanking()
+ {
+ return ranking;
+ }
+
+ public void setRanking(Ranking ranking)
+ {
+ this.ranking = ranking;
+ }
+
+ public String toString()
+ {
+ return "ScenarioDoubleRename:" + fileMiddle;
+ }
+
+ public void setTimeout(long timeout)
+ {
+ this.timeout = timeout;
+ }
+
+ public long getTimeout()
+ {
+ return timeout;
+ }
+}
diff --git a/source/java/org/alfresco/filesys/repo/rules/ScenarioOpenFileInstance.java b/source/java/org/alfresco/filesys/repo/rules/ScenarioOpenFileInstance.java
index abc9f1a3c1..89faa0c3b8 100644
--- a/source/java/org/alfresco/filesys/repo/rules/ScenarioOpenFileInstance.java
+++ b/source/java/org/alfresco/filesys/repo/rules/ScenarioOpenFileInstance.java
@@ -21,6 +21,7 @@ package org.alfresco.filesys.repo.rules;
import java.util.ArrayList;
import java.util.Date;
+import org.alfresco.filesys.repo.OpenFileMode;
import org.alfresco.filesys.repo.ResultCallback;
import org.alfresco.filesys.repo.TempNetworkFile;
import org.alfresco.filesys.repo.rules.ScenarioInstance.Ranking;
@@ -160,7 +161,7 @@ class ScenarioOpenFileInstance implements ScenarioInstance
OpenFileOperation o = (OpenFileOperation)operation;
name = o.getName();
ArrayList commands = new ArrayList();
- commands.add(new OpenFileCommand(o.getName(), o.isWriteAccess(), o.isTruncate(), o.getRootNodeRef(), o.getPath()));
+ commands.add(new OpenFileCommand(o.getName(), o.getMode(), o.isTruncate(), o.getRootNodeRef(), o.getPath()));
ArrayList postCommitCommands = new ArrayList();
postCommitCommands.add(newOpenFileCallbackCommand());
return new CompoundCommand(commands, postCommitCommands);
@@ -298,14 +299,14 @@ class ScenarioOpenFileInstance implements ScenarioInstance
if(name.equalsIgnoreCase(o.getName()))
{
- if(o.isWriteAccess())
+ if(o.getMode() == OpenFileMode.WRITE)
{
// This is an open of a read write access
if(openReadWriteCount == 0)
{
logger.debug("Open first read/write from scenario:" + this);
ArrayList commands = new ArrayList();
- commands.add(new OpenFileCommand(o.getName(), o.isWriteAccess(), o.isTruncate(), o.getRootNodeRef(), o.getPath()));
+ commands.add(new OpenFileCommand(o.getName(), o.getMode(), o.isTruncate(), o.getRootNodeRef(), o.getPath()));
ArrayList postCommitCommands = new ArrayList();
postCommitCommands.add(newOpenFileCallbackCommand());
return new CompoundCommand(commands, postCommitCommands);
@@ -324,7 +325,7 @@ class ScenarioOpenFileInstance implements ScenarioInstance
{
logger.debug("Open first read only from scenario:" + this);
ArrayList commands = new ArrayList();
- commands.add(new OpenFileCommand(o.getName(), o.isWriteAccess(), o.isTruncate(), o.getRootNodeRef(), o.getPath()));
+ commands.add(new OpenFileCommand(o.getName(), o.getMode(), o.isTruncate(), o.getRootNodeRef(), o.getPath()));
ArrayList postCommitCommands = new ArrayList();
postCommitCommands.add(newOpenFileCallbackCommand());
return new CompoundCommand(commands, postCommitCommands);
diff --git a/source/java/org/alfresco/filesys/repo/rules/ScenarioRenameShuffle.java b/source/java/org/alfresco/filesys/repo/rules/ScenarioRenameShuffle.java
index 57e907b8d7..7ffa139071 100644
--- a/source/java/org/alfresco/filesys/repo/rules/ScenarioRenameShuffle.java
+++ b/source/java/org/alfresco/filesys/repo/rules/ScenarioRenameShuffle.java
@@ -18,10 +18,7 @@
*/
package org.alfresco.filesys.repo.rules;
-import java.util.Date;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -31,11 +28,12 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
- * The "Vi" shuffle is a sequence where a file is moved out of the way
+ * The "Vi" rename shuffle is a sequence where a file is moved out of the way
* and then a new copy of the file put into place.
*
* a) Rename File to File~
* b) Create File
+ * c) Delete File~
*
*/
public class ScenarioRenameShuffle implements Scenario
diff --git a/source/java/org/alfresco/filesys/repo/rules/ScenarioSimpleNonBufferedInstance.java b/source/java/org/alfresco/filesys/repo/rules/ScenarioSimpleNonBufferedInstance.java
index 559f40fa87..54ac229557 100644
--- a/source/java/org/alfresco/filesys/repo/rules/ScenarioSimpleNonBufferedInstance.java
+++ b/source/java/org/alfresco/filesys/repo/rules/ScenarioSimpleNonBufferedInstance.java
@@ -76,7 +76,7 @@ public class ScenarioSimpleNonBufferedInstance implements ScenarioInstance
else if(operation instanceof OpenFileOperation)
{
OpenFileOperation o = (OpenFileOperation)operation;
- return new OpenFileCommand(o.getName(), o.isWriteAccess(), o.isTruncate(), o.getRootNodeRef(), o.getPath());
+ return new OpenFileCommand(o.getName(), o.getMode(), o.isTruncate(), o.getRootNodeRef(), o.getPath());
}
else if(operation instanceof CloseFileOperation)
{
diff --git a/source/java/org/alfresco/filesys/repo/rules/commands/OpenFileCommand.java b/source/java/org/alfresco/filesys/repo/rules/commands/OpenFileCommand.java
index bca7cac376..2b9df70a0f 100644
--- a/source/java/org/alfresco/filesys/repo/rules/commands/OpenFileCommand.java
+++ b/source/java/org/alfresco/filesys/repo/rules/commands/OpenFileCommand.java
@@ -20,6 +20,7 @@ package org.alfresco.filesys.repo.rules.commands;
import java.util.List;
+import org.alfresco.filesys.repo.OpenFileMode;
import org.alfresco.filesys.repo.rules.Command;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -30,7 +31,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
public class OpenFileCommand implements Command
{
private String name;
- private boolean writeAccess = false;
+ private OpenFileMode mode = OpenFileMode.READ;
private boolean truncate = false;
private String path;
private NodeRef rootNode;
@@ -43,10 +44,10 @@ public class OpenFileCommand implements Command
* @param truncate
* @param path
*/
- public OpenFileCommand(String name, boolean writeAccess, boolean truncate, NodeRef rootNode, String path)
+ public OpenFileCommand(String name, OpenFileMode mode, boolean truncate, NodeRef rootNode, String path)
{
this.name = name;
- this.writeAccess = writeAccess;
+ this.mode = mode;
this.truncate = truncate;
this.rootNode = rootNode;
this.path = path;
@@ -67,9 +68,9 @@ public class OpenFileCommand implements Command
return rootNode;
}
- public boolean isWriteAccess()
+ public OpenFileMode getMode()
{
- return writeAccess;
+ return mode;
}
public boolean isTruncate()
diff --git a/source/java/org/alfresco/filesys/repo/rules/operations/OpenFileOperation.java b/source/java/org/alfresco/filesys/repo/rules/operations/OpenFileOperation.java
index e7897e1930..c61d85241f 100644
--- a/source/java/org/alfresco/filesys/repo/rules/operations/OpenFileOperation.java
+++ b/source/java/org/alfresco/filesys/repo/rules/operations/OpenFileOperation.java
@@ -18,22 +18,23 @@
*/
package org.alfresco.filesys.repo.rules.operations;
+import org.alfresco.filesys.repo.OpenFileMode;
import org.alfresco.filesys.repo.rules.Operation;
import org.alfresco.service.cmr.repository.NodeRef;
/**
- * Create File Operation.
+ * Open File Operation.
*
- * Create a file with the given name.
+ * Open a file with the given name.
*/
public class OpenFileOperation implements Operation
{
private String name;
- private boolean writeAccess = false;
+ private OpenFileMode mode;
private boolean truncate = false;
private String path;
private NodeRef rootNode;
-
+
/**
*
* @param name the name of the file to open
@@ -41,13 +42,13 @@ public class OpenFileOperation implements Operation
* @param rootNode
* @param path the full path/name to open
*/
- public OpenFileOperation(String name, boolean writeAccess, boolean truncate, NodeRef rootNode, String path)
+ public OpenFileOperation(String name, OpenFileMode mode, boolean truncate, NodeRef rootNode, String path)
{
this.name = name;
this.rootNode = rootNode;
this.truncate = truncate;
this.path = path;
- this.writeAccess = writeAccess;
+ this.mode = mode;
}
public String getName()
@@ -65,14 +66,15 @@ public class OpenFileOperation implements Operation
return rootNode;
}
- public boolean isWriteAccess()
+
+ public OpenFileMode getMode()
{
- return writeAccess;
+ return mode;
}
public boolean isTruncate()
{
- return writeAccess;
+ return truncate;
}
public String toString()
diff --git a/source/test-resources/filesys/X1.fm b/source/test-resources/filesys/X1.fm
new file mode 100644
index 0000000000..8f7cb29f59
Binary files /dev/null and b/source/test-resources/filesys/X1.fm differ
diff --git a/source/test-resources/filesys/X2.fm b/source/test-resources/filesys/X2.fm
new file mode 100644
index 0000000000..5f0f87b8ec
Binary files /dev/null and b/source/test-resources/filesys/X2.fm differ