diff --git a/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml b/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml index 137def01b5..54dc76cb0e 100644 --- a/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml +++ b/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml @@ -140,6 +140,7 @@ 30000 HIGH + .*~$ 30000 @@ -153,6 +154,11 @@ 3000000 HIGH + + .*.backup.fm$ + 60000 + HIGH + diff --git a/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java b/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java index 0cf5d58aec..234d28ac55 100644 --- a/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java +++ b/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java @@ -146,7 +146,7 @@ public class CommandExecutorImpl implements CommandExecutor */ if(command instanceof CompoundCommand) { - logger.debug("post Commit"); + logger.debug("post commit of compound command"); CompoundCommand c = (CompoundCommand)command; List commands = c.getPostCommitCommands(); @@ -210,7 +210,8 @@ public class CommandExecutorImpl implements CommandExecutor int openAction = FileAction.OpenIfExists; // TODO Open Action FileAction.NTOverwrite o.truncate - FileOpenParams params = new FileOpenParams(o.getPath(), openAction, o.isWriteAccess() ? AccessMode.ReadWrite : AccessMode.ReadOnly, FileAttribute.NTNormal, 0); + // TODO ATTRIBUTES ONLY and DELETE ONLY + FileOpenParams params = new FileOpenParams(o.getPath(), openAction, o.getMode() == OpenFileMode.WRITE ? AccessMode.ReadWrite : AccessMode.ReadOnly, FileAttribute.NTNormal, 0); return diskInterface.openFile(sess, tree, params); } diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java index b4c7498e24..f14a1b5bd2 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java @@ -3185,6 +3185,28 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD Serializable prop = nodeService.getProperty(sourceNodeRef, ContentModel.PROP_CONTENT); if(prop != null) { + if(prop instanceof ContentData) + { + ContentData data = (ContentData)prop; + if(data.getMimetype().equalsIgnoreCase(MimetypeMap.MIMETYPE_BINARY)) + { + if(logger.isDebugEnabled()) + { + logger.debug("mimetype is binary - guess mimetype has failed"); + } + Serializable targetProp = nodeService.getProperty(targetNodeRef, ContentModel.PROP_CONTENT); + + if(targetProp != null && targetProp instanceof ContentData) + { + ContentData targetData = (ContentData)targetProp; + logger.debug("copy the existing mimetype"); + prop = ContentData.setMimetype(data, targetData.getMimetype()); + } + + + } + } + nodeService.setProperty(targetNodeRef, ContentModel.PROP_CONTENT, prop); } else diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java index 826d54f900..acb4b22521 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java @@ -2232,25 +2232,7 @@ public class ContentDiskDriverTest extends TestCase { ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest1.docx"); assertNotNull("unable to find test resource filesys/ContentDiskDriverTest1.docx", fileResource); - - byte[] buffer= new byte[1000]; - InputStream is = fileResource.getInputStream(); - try - { - long offset = 0; - int i = is.read(buffer, 0, buffer.length); - while(i > 0) - { - // testContext.firstFileHandle.writeFile(buffer, i, 0, offset); - driver.writeFile(testSession, testConnection, testContext.firstFileHandle, buffer, 0, i, offset); - offset += i; - i = is.read(buffer, 0, buffer.length); - } - } - finally - { - is.close(); - } + writeResourceToNetworkFile(fileResource, testContext.firstFileHandle); logger.debug("close the file, firstFileHandle"); driver.closeFile(testSession, testConnection, testContext.firstFileHandle); @@ -3132,7 +3114,204 @@ public class ContentDiskDriverTest extends TestCase assertFalse("version not incremented", version.equals(version3)); } // OpenCloseVersionableFile + + /** + * Frame maker save + * a) Lock File Created (X.fm.lck) + * b) Create new file (X.fm.C29) + * c) Existing file rename out of the way. (X.backup.fm) + * d) New file rename into place. (X.fm.C29) + * e) Old file deleted (open with delete on close) + * f) Lock file deleted (open with delete on close) + */ + public void testScenarioFrameMakerShuffle() throws Exception + { + logger.debug("testScenarioFramemakerShuffle"); + + final String LOCK_FILE = "X.fm.lck"; + final String FILE_NAME = "X.fm"; + final String FILE_OLD_TEMP = "X.backup.fm"; + final String FILE_NEW_TEMP = "X.fm.C29"; + + class TestContext + { + NetworkFile firstFileHandle; + String mimetype; + }; + + final TestContext testContext = new TestContext(); + + final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioFramemakerShuffle"; + + ServerConfiguration scfg = new ServerConfiguration("testServer"); + TestServer testServer = new TestServer("testServer", scfg); + final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName"); + DiskSharedDevice share = getDiskSharedDevice(); + final TreeConnection testConnection = testServer.getTreeConnection(share); + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + /** + * Clean up just in case garbage is left from a previous run + */ + RetryingTransactionCallback deleteGarbageFileCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME); + return null; + } + }; + + try + { + tran.doInTransaction(deleteGarbageFileCB); + } + catch (Exception e) + { + // expect to go here + } + + logger.debug("a) create new file"); + RetryingTransactionCallback createFileCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + /** + * Create the test directory we are going to use + */ + FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0); + FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0); + driver.createDirectory(testSession, testConnection, createRootDirParams); + driver.createDirectory(testSession, testConnection, createDirParams); + + /** + * Create the file we are going to test + */ + FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0); + testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams); + assertNotNull(testContext.firstFileHandle); + ClassPathResource fileResource = new ClassPathResource("filesys/X1.fm"); + assertNotNull("unable to find test resource filesys/X1.fm", fileResource); + writeResourceToNetworkFile(fileResource, testContext.firstFileHandle); + driver.closeFile(testSession, testConnection, testContext.firstFileHandle); + NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME); + nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null); + + return null; + } + }; + tran.doInTransaction(createFileCB, false, true); + + /** + * b) Save the new file + * Write X2.fm to the test file, + */ + logger.debug("b) move new file into place"); + RetryingTransactionCallback writeFileCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0); + testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams); + + ClassPathResource fileResource = new ClassPathResource("filesys/X2.fm"); + assertNotNull("unable to find test resource filesys/X2.fm", fileResource); + writeResourceToNetworkFile(fileResource, testContext.firstFileHandle); + driver.closeFile(testSession, testConnection, testContext.firstFileHandle); + + + NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME); + Map props = nodeService.getProperties(file1NodeRef); + ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT); + assertNotNull("data is null", data); + assertEquals("size is wrong", 166912, data.getSize()); + testContext.mimetype = data.getMimetype(); + + return null; + } + }; + tran.doInTransaction(writeFileCB, false, true); + + /** + * c) rename the old file + */ + logger.debug("c) rename old file"); + RetryingTransactionCallback renameOldFileCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP); + return null; + } + }; + tran.doInTransaction(renameOldFileCB, false, true); + + /** + * d) Move the new file into place, stuff should get shuffled + */ + logger.debug("d) move new file into place"); + RetryingTransactionCallback moveNewFileCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); + return null; + } + }; + + tran.doInTransaction(moveNewFileCB, false, true); + + /** + * d) Delete the old file + */ + logger.debug("d) move new file into place"); + RetryingTransactionCallback deleteOldFileCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP); + return null; + } + }; + + tran.doInTransaction(deleteOldFileCB, false, true); + + logger.debug("e) validate results"); + + /** + * Now validate everything is correct + */ + RetryingTransactionCallback validateCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME); + + Map props = nodeService.getProperties(shuffledNodeRef); + + ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT); + assertNotNull("data is null", data); + assertEquals("size is wrong", 123904, data.getSize()); + + NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME); + assertTrue("file has lost versionable aspect", nodeService.hasAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE)); + + assertEquals("mimeType is wrong", testContext.mimetype, data.getMimetype()); + + + return null; + } + }; + + tran.doInTransaction(validateCB, true, true); + } // Scenario frame maker save /** * Test server @@ -3206,4 +3385,32 @@ public class ContentDiskDriverTest extends TestCase return cifsHelper.getNodeRef(ctx.getRootNode(), path); } + + /** + * Write the resource to the specified NetworkFile + * @param resource + * @param file + * @throws IOException + */ + private void writeResourceToNetworkFile(ClassPathResource resource, NetworkFile file) throws IOException + { + + byte[] buffer= new byte[1000]; + InputStream is = resource.getInputStream(); + try + { + long offset = 0; + int i = is.read(buffer, 0, buffer.length); + while(i > 0) + { + file.writeFile(buffer, i, 0, offset); + offset += i; + i = is.read(buffer, 0, buffer.length); + } + } + finally + { + is.close(); + } + } } diff --git a/source/java/org/alfresco/filesys/repo/NonTransactionalRuleContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/NonTransactionalRuleContentDiskDriver.java index a0d5311b46..1e0352087a 100644 --- a/source/java/org/alfresco/filesys/repo/NonTransactionalRuleContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/repo/NonTransactionalRuleContentDiskDriver.java @@ -341,6 +341,7 @@ public class NonTransactionalRuleContentDiskDriver implements ExtendedDiskInterf + ", requestBatchOpLock:" +param.requestBatchOpLock() + ", requestExclusiveOpLock:" +param.requestExclusiveOpLock() + ", isDeleteOnClose:" +param.isDeleteOnClose() + + ", allocationSize:" + param.getAllocationSize() + ", sharedAccess: " + strSharedAccess ); @@ -356,8 +357,19 @@ public class NonTransactionalRuleContentDiskDriver implements ExtendedDiskInterf String file = paths[1]; EvaluatorContext ctx = getEvaluatorContext(driverState, folder); - - boolean writeAccess = param.isReadWriteAccess(); + + // Todo what about attributes only and writeOnly ? + OpenFileMode writeAccess = param.isReadWriteAccess() ? OpenFileMode.WRITE : OpenFileMode.READ ; + + if(param.isDeleteOnClose()) + { + if(logger.isDebugEnabled()) + { + logger.debug("open file has delete on close"); + } + writeAccess = OpenFileMode.DELETE; + } + boolean truncate = param.isOverwrite(); Operation o = new OpenFileOperation(file, writeAccess, truncate, rootNode, path); diff --git a/source/java/org/alfresco/filesys/repo/OpenFileMode.java b/source/java/org/alfresco/filesys/repo/OpenFileMode.java new file mode 100644 index 0000000000..49db82e5a8 --- /dev/null +++ b/source/java/org/alfresco/filesys/repo/OpenFileMode.java @@ -0,0 +1,9 @@ +package org.alfresco.filesys.repo; + +public enum OpenFileMode +{ + READ, + WRITE, + DELETE, + ATTRIBUTES_ONLY +} diff --git a/source/java/org/alfresco/filesys/repo/rules/ScenarioDoubleRenameShuffle.java b/source/java/org/alfresco/filesys/repo/rules/ScenarioDoubleRenameShuffle.java new file mode 100644 index 0000000000..b7521d225b --- /dev/null +++ b/source/java/org/alfresco/filesys/repo/rules/ScenarioDoubleRenameShuffle.java @@ -0,0 +1,113 @@ +/* + * 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.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.alfresco.filesys.repo.rules.ScenarioInstance.Ranking; +import org.alfresco.filesys.repo.rules.operations.CreateFileOperation; +import org.alfresco.filesys.repo.rules.operations.RenameFileOperation; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A double rename shuffle + * + * a) Existing file renamed out of the way. X.fm to X.backup.fm + * b) New file moved renamed into place. X.fm.C29 + */ +public class ScenarioDoubleRenameShuffle implements Scenario +{ + private static Log logger = LogFactory.getLog(ScenarioDoubleRenameShuffle.class); + + /** + * The regex pattern of a create that will trigger a new instance of + * the scenario. + */ + private Pattern pattern; + private String strPattern; + + + private long timeout = 30000; + + private Ranking ranking = Ranking.HIGH; + + @Override + public ScenarioInstance createInstance(final List 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