Merged BRANCHES/DEV/V4.1-BUG-FIX to HEAD

43598: Merged HEAD to BRANCHES/DEV/V4.1-BUG-FIX *RECORD ONLY*
             41906: ALF-11378: REST API has been modified to return extra information about a user whether s/he belongs to a group or not.
   44003: Merged BRANCHES/DEV/BELARUS/V4.1-BUG-FIX-2012_11_22 to BRANCHES/DEV/V4.1-BUG-FIX:
            ALF-15210: Inconsistency in the '?' icon over the dashlets projects\slingshot\source\web\js\share.js DashletTitleBarActions_onReady() function was updated. Fix initialize the style for actionsNode elements into the DOM for IE.
   44004: Merged BRANCHES/DEV/BELARUS/V4.1-BUG-FIX-2012_11_22 to V4.1-BUG-FIX:
            ALF-15793: edit offline hides version history projects\slingshot\source\web\components\document-details\document-actions.js onActionUploadNewVersion function was updated. Fix sets version variable correctly now using asset.workingCopy property instead asset.custom property, which is undefined.
   44018: ALF-16540 : CMIS: createDocument with VersioningState.CHECKEDOUT causes NodeLockedException for types with mandatory versionable aspect
            The ckeck for lock was disabled when beforeCreateVersion policy is handled.
            Version could be created for a locked node. 
   44054: Fix for ALF-16337. Datalist assignee not searchable by full name.
   44056: Trivial change. Fixing some compiler warnings under org.alfresco.repo.content.metadata including a noisy Tika one.
   44143: Merged BRANCHES/DEV/BELARUS/V4.1-BUG-FIX-2012_10_19 to BRANCHES/DEV/V4.1-BUG-FIX:
            42989: ALF-16331: Wrong user for "completed by" information provided in Group Review And Approve workflow
   44147: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/DEV/V4.1-BUG-FIX:
   44146: Merged BRANCHES/DEV/BELARUS/V3.4-BUG-FIX-2012_05_22 to BRANCHES/DEV/V3.4-BUG-FIX:
            37733: ALF-12051: Webdav - Cannot open files containing "?" character in the filename in WinXP
   44152: ALF-17009 : Merged V3.4-BUG-FIX (3.4.12) to V4.1-BUG-FIX (4.1.3)
            44151: ALF-14035 Tiny HTML file that causes Jodconverter to launch a 100% CPU soffice instance
               - HTML to PDF is now done via ODT as the direct transform hangs if there are <sub> tags in the HTML.
               - Added in 'unsupportedTransformations' to stop a bare transformer.JodConverter from doing HTML to PDF 
               - TransformerDebug test file debugTransformers.txt no longer needs to be 18 bytes, as it made it too fiddly.
               - Modified debug from RuntimeExec so less editing is required to running from the command line
            - Removed tabs that had been added to enterprise/content-services-context.xml in 4.1-BUG-FIX
   44192: ALF-16560 - CIFS: Word document version history lost after saving content in Word:mac 2011 on Mac Mountain Lion
   44224: ALF-16896 Exception with TIKA meta data extractor.
            - Patch POI to handle parsing of Unicode properties that starts on a 4 byte boundary
              rather than the specified offset. Example file was created using http://www.aspose.com/
   44241: Merged DEV to V4.1-BUG-FIX
            44208: ALF-14591 : Ordering not supported for IMAP properties defining IMAP sort fields in Share
                   Make properties from imap:imapContent aspect indexable for SOLR. 
   44253: Merged BRANCHES/DEV/AMILLER/CLOUD1 to BRANCHES/DEV/V4.1-BUG-FIX:
            38927: CLOUD-128 - Update rules works incorrectly
          This is a partial fix for ALF-14568. The rest is coming in a separate check-in.
          I made some minor adjustments to this change - trivial spelling fix and whitespace changes.
   44257: ALF-16563 - CIFS: Image document version history lost after saving content in Preview on Mac Mountain Lion
   44260: Fix for ALF-16430 - List of values shown in alphabetical order in Share Forms. Values now only sorted if the Forms config 'field' element has the sorted='true' attribute.
   44269: Completion of fix for ALF-14568 - Update rule works incorrectly.
   44318: Fix for ALF-17055 - remoteadm webscript set a Last-Modified HTTP header whose date format does not conform to RFC 2616 hence breaking proxy caching
   44320: Fix for ALF-16463 - documentLibrary RSS feed does not pass the w3c validator, in particular pubDate breaks RFC-822, date not displayed when using non English locale
   44352: Merged BRANCHES/DEV/BELARUS/V4.1-BUG-FIX-2012_11_12 to BRANCHES/DEV/V4.1-BUG-FIX
            43860: ALF-16263: Search using a "Stop Word" not displaying any result

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@44459 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2012-12-07 14:04:23 +00:00
parent 4f3f2ce521
commit f651abe34a
38 changed files with 1442 additions and 66 deletions

View File

@@ -18,7 +18,6 @@
*/
package org.alfresco.filesys.alfresco;
import org.alfresco.filesys.config.ServerConfigurationBean;
import org.alfresco.jlan.server.core.DeviceContext;
import org.alfresco.jlan.server.core.DeviceContextException;
import org.alfresco.jlan.server.filesys.DiskInterface;

View File

@@ -92,9 +92,10 @@ public interface RepositoryDiskInterface
* @param rootNode
* @param fromPath - the source node
* @param toPath - the target node
* @throws FileNotFoundException
* @throws FileNotFoundException
* @return node ref of deleted file or null if no file deleted
*/
public void closeFile(NodeRef rootNode, String Path, NetworkFile file) throws IOException;
public NodeRef closeFile(NodeRef rootNode, String Path, NetworkFile file) throws IOException;
/**

View File

@@ -242,7 +242,7 @@ public class CommandExecutorImpl implements CommandExecutor
{
logger.debug("close file command");
CloseFileCommand c = (CloseFileCommand)command;
repositoryDiskInterface.closeFile(c.getRootNodeRef(), c.getPath(), c.getNetworkFile());
return repositoryDiskInterface.closeFile(c.getRootNodeRef(), c.getPath(), c.getNetworkFile());
}
else if(command instanceof ReduceQuotaCommand)
{

View File

@@ -1505,7 +1505,14 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
// Inhibit versioning for this transaction
getPolicyFilter().disableBehaviour( ContentModel.ASPECT_VERSIONABLE);
// Check if the file is being marked for deletion, if so then check if the file is locked
// Check if the file is being marked for deletion, if so then check if the file is locked
/*
* Which DeleteOnClose flag has priority?
* SetDeleteOnClose is not set or used in this method.
* The NTProtocolHandler sets the deleteOnClose in both
* info and the NetworkFile - it's the one in NetworkFile that results in the file being deleted.
*/
if ( info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose())
{
if(logger.isDebugEnabled())
@@ -1542,6 +1549,8 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
throw new DirectoryNotEmptyException( name);
}
}
}
if(info.hasSetFlag(FileInfo.SetAttributes))
@@ -1618,10 +1627,7 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
// Set the creation and modified date/time
Map<QName, Serializable> auditableProps = new HashMap<QName, Serializable>(5);
// Which DeleteOnClose flag has priority?
// SetDeleteOnClose is not set or used in this method.
// The NTProtocolHandler sets the deleteOnClose in both
// info and the NetworkFile - it's the one in NetworkFile that works.
if ( info.hasSetFlag(FileInfo.SetCreationDate) && info.hasCreationDateTime())
{
@@ -2725,8 +2731,9 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
* Close the file.
*
* @exception java.io.IOException If an error occurs.
* @return node ref of deleted file
*/
public void closeFile(NodeRef rootNode, String path, NetworkFile file) throws IOException
public NodeRef closeFile(NodeRef rootNode, String path, NetworkFile file) throws IOException
{
if ( logger.isDebugEnabled())
{
@@ -2736,7 +2743,7 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
if( file instanceof PseudoNetworkFile)
{
file.close();
return;
return null;
}
/**
@@ -2744,13 +2751,15 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
*/
if(file.hasDeleteOnClose())
{
NodeRef target = null;
if(logger.isDebugEnabled())
{
logger.debug("closeFile has delete on close set path:" + path);
}
try
{
NodeRef target = getCifsHelper().getNodeRef(rootNode, path);
target = getCifsHelper().getNodeRef(rootNode, path);
if(target!=null)
{
nodeService.deleteNode(target);
@@ -2774,7 +2783,7 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
logger.debug("Closed file: network file=" + file + " delete on close=" + file.hasDeleteOnClose());
}
return;
return target;
}
// Check for a temp file - which will be a new file or a read/write file
@@ -2890,6 +2899,8 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
logger.debug(" File " + file.getFullName() + ", version=" + nodeService.getProperty( cFile.getNodeRef(), ContentModel.PROP_VERSION_LABEL));
}
}
return null;
}
catch (IOException e)
{

View File

@@ -5432,6 +5432,354 @@ public class ContentDiskDriverTest extends TestCase
} // testMacDragAndDrop
/**
* Mountain Lion 2011 Word
* a) Create new file (Word Work File D2.tmp)
* (Actually in real life its renamed from a temp directory.
* c) Existing file rename out of the way. (Word Work File L_5.tmp)
* d) New file rename into place. (MacWord1.docx)
* e) Old file deleted
*/
public void testScenarioMountainLionWord2011() throws Exception
{
logger.debug("testScenarioMountainLionWord2011");
final String FILE_NAME = "MacWord1.docx";
final String FILE_OLD_TEMP = "Word Work File L_5.tmp";
final String FILE_NEW_TEMP = "Word Work File D_2.tmp";
class TestContext
{
NetworkFile firstFileHandle;
String mimetype;
};
final TestContext testContext = new TestContext();
final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMountainLionWord2011";
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<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {
@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<Void> createFileCB = new RetryingTransactionCallback<Void>() {
@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/ContentDiskDriverTest3.doc");
assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", 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 ContentDiskDriverTest3.doc,
*/
logger.debug("b) move new file into place");
RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {
@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/ContentDiskDriverTest3.doc");
assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);
writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
driver.closeFile(testSession, testConnection, testContext.firstFileHandle);
NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
Map<QName, Serializable> 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<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {
@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<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {
@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) delete the old file");
RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {
@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<Void> validateCB = new RetryingTransactionCallback<Void>() {
@Override
public Void execute() throws Throwable
{
NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
Map<QName, Serializable> 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);
} // Test Word 2011 Mountain Lion
/**
* This test tries to simulate the cifs shuffling that is done
* from Save from Mac Mountain Lion by Preview
*
* a) Temp file created in temporary folder (Crysanthemum.jpg)
* b) Target file deleted by open / delete on close flag / close
* c) Temp file moved to target file.
*/
public void testScenarioMacMountainLionPreview() throws Exception
{
logger.debug("testScenarioMountainLionPreview");
final String FILE_NAME = "Crysanthemeum.jpg";
final String TEMP_FILE_NAME = "Crysanthemeum.jpg";
final String UPDATED_TEXT = "Mac Lion Preview Updated Content";
class TestContext
{
NetworkFile firstFileHandle;
NetworkFile tempFileHandle;
NodeRef testNodeRef; // node ref Crysanthemenum.jpg
};
final TestContext testContext = new TestContext();
final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionPreview";
final String TEST_TEMP_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionPreview\\.Temporary Items";
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();
/**
* Create a file in the test directory
*/
RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {
@Override
public Void execute() throws Throwable
{
/**
* Create the test directory we are going to use
*/
FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
driver.createDirectory(testSession, testConnection, createRootDirParams);
driver.createDirectory(testSession, testConnection, createDirParams);
driver.createDirectory(testSession, testConnection, createTempDirParams);
/**
* Create the file we are going to use
*/
FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
assertNotNull(testContext.firstFileHandle);
String testContent = "Mac Mountain Lion Text";
byte[] testContentBytes = testContent.getBytes();
driver.writeFile(testSession, testConnection, testContext.firstFileHandle, testContentBytes, 0, testContentBytes.length, 0);
driver.closeFile(testSession, testConnection, testContext.firstFileHandle);
/**
* Create the temp file we are going to use
*/
FileOpenParams createTempFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
testContext.tempFileHandle = driver.createFile(testSession, testConnection, createTempFileParams);
assertNotNull(testContext.tempFileHandle);
testContent = UPDATED_TEXT;
testContentBytes = testContent.getBytes();
driver.writeFile(testSession, testConnection, testContext.tempFileHandle, testContentBytes, 0, testContentBytes.length, 0);
driver.closeFile(testSession, testConnection, testContext.tempFileHandle);
/**
* Also add versionable to target file
*/
testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
return null;
}
};
tran.doInTransaction(createFileCB, false, true);
/**
* b) Delete the target file by opening it and set the delete on close bit
*/
RetryingTransactionCallback<Void> deleteTargetFileCB = new RetryingTransactionCallback<Void>() {
@Override
public Void execute() throws Throwable
{
FileOpenParams openFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
testContext.tempFileHandle = driver.openFile(testSession, testConnection, openFileParams);
FileInfo info = new FileInfo();
info.setFileInformationFlags(FileInfo.SetDeleteOnClose);
info.setDeleteOnClose(true);
testContext.tempFileHandle.setDeleteOnClose(true);
driver.setFileInformation(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, info);
assertNotNull(testContext.tempFileHandle);
logger.debug("this close should result in a file being deleted");
driver.closeFile(testSession, testConnection, testContext.tempFileHandle);
return null;
}
};
tran.doInTransaction(deleteTargetFileCB, false, true);
/**
* c) Move the temp file into target directory
*/
RetryingTransactionCallback<Void> moveTempFileCB = new RetryingTransactionCallback<Void>() {
@Override
public Void execute() throws Throwable
{
driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, TEST_DIR + "\\" + FILE_NAME);
return null;
}
};
tran.doInTransaction(moveTempFileCB, false, true);
/**
* Validate results.
*/
RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {
@Override
public Void execute() throws Throwable
{
NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
assertTrue("node is not versionable", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
assertEquals("shuffledNode ref is different", shuffledNodeRef, testContext.testNodeRef);
return null;
}
};
tran.doInTransaction(validateCB, false, true);
} // testScenarioMountainLionPreview
/**
* Test server
*/

View File

@@ -0,0 +1,115 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.filesys.repo.rules;
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.CloseFileOperation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* The DeleteOnClose rename shuffle is a delete on close of a file resulting in a file being deleted followed by a rename of a file from
* somewhere else.
*
* First case of this is Mac Mountain Lion Preview application.
* and then a new copy of the file put into place.
*
* a) DeleteOnClose fileA
* b) Close fileA
* c) Rename whatever fileA
*
*/
public class ScenarioDeleteOnCloseRename implements Scenario
{
private static Log logger = LogFactory.getLog(ScenarioDeleteOnCloseRename.class);
/**
* The regex pattern of a close that will trigger a new instance of
* the scenario.
*/
private Pattern pattern;
private String strPattern;
private long timeout = 30000;
@Override
public ScenarioInstance createInstance(final EvaluatorContext ctx, Operation operation)
{
/**
* This scenario is triggered by a rename of a file matching
* the pattern
*/
if(operation instanceof CloseFileOperation)
{
CloseFileOperation c = (CloseFileOperation)operation;
Matcher m = pattern.matcher(c.getName());
if(m.matches() && c.getNetworkFile().hasDeleteOnClose())
{
if(logger.isDebugEnabled())
{
logger.debug("New Scenario ScenarioDeleteOnCloseRename strPattern:" + pattern);
}
ScenarioDeleteOnCloseRenameInstance instance = new ScenarioDeleteOnCloseRenameInstance();
instance.setTimeout(timeout);
instance.setRanking(ranking);
return instance;
}
}
// No not interested.
return null;
}
public void setTimeout(long timeout)
{
this.timeout = timeout;
}
public long getTimeout()
{
return timeout;
}
public void setPattern(String pattern)
{
this.pattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
this.strPattern = pattern;
}
public String getPattern()
{
return strPattern;
}
private Ranking ranking = Ranking.HIGH;
public void setRanking(Ranking ranking)
{
this.ranking = ranking;
}
public Ranking getRanking()
{
return ranking;
}
}

View File

@@ -0,0 +1,251 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.filesys.repo.rules;
import java.util.ArrayList;
import java.util.Date;
import org.alfresco.filesys.repo.ResultCallback;
import org.alfresco.filesys.repo.rules.commands.CloseFileCommand;
import org.alfresco.filesys.repo.rules.commands.CompoundCommand;
import org.alfresco.filesys.repo.rules.commands.CopyContentCommand;
import org.alfresco.filesys.repo.rules.commands.DeleteFileCommand;
import org.alfresco.filesys.repo.rules.commands.RestoreFileCommand;
import org.alfresco.filesys.repo.rules.operations.CloseFileOperation;
import org.alfresco.filesys.repo.rules.operations.MoveFileOperation;
import org.alfresco.filesys.repo.rules.operations.RenameFileOperation;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* First case of this is Mac Mountain Lion Preview application.
* and then a new copy of the file put into place.
*
* a) DeleteOnClose fileA
* b) Close fileA
* c) Rename whatever fileA
*
* This rule will kick in and ...
*
*/
class ScenarioDeleteOnCloseRenameInstance implements ScenarioInstance
{
private static Log logger = LogFactory.getLog(ScenarioDeleteOnCloseRenameInstance.class);
private Date startTime = new Date();
/**
* Timeout in ms. Default 30 seconds.
*/
private long timeout = 30000;
private boolean isComplete = false;
private Ranking ranking = Ranking.HIGH;
private NodeRef originalNodeRef = null;
enum InternalState
{
NONE,
LOOK_FOR_RENAME
} ;
InternalState state = InternalState.NONE;
String name;
/**
* 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");
}
isComplete = true;
return null;
}
switch (state)
{
case NONE:
if(operation instanceof CloseFileOperation)
{
CloseFileOperation c = (CloseFileOperation)operation;
this.name = c.getName();
logger.debug("New scenario initialised for file " + name);
state = InternalState.LOOK_FOR_RENAME;
ArrayList<Command> commands = new ArrayList<Command>();
ArrayList<Command> postCommitCommands = new ArrayList<Command>();
ArrayList<Command> postErrorCommands = new ArrayList<Command>();
commands.add(new CloseFileCommand(c.getName(), c.getNetworkFile(), c.getRootNodeRef(), c.getPath()));
postCommitCommands.add(newDeleteFileCallbackCommand());
return new CompoundCommand(commands, postCommitCommands, postErrorCommands);
}
break;
case LOOK_FOR_RENAME:
if(operation instanceof RenameFileOperation)
{
RenameFileOperation r = (RenameFileOperation)operation;
if(name.equals(r.getTo()))
{
logger.debug("Delete on close Rename shuffle - fire!");
if(originalNodeRef != null)
{
/**
* Shuffle is as follows
* a) Copy content from File to File~
* b) Delete File
* c) Rename File~ to File
*/
ArrayList<Command> commands = new ArrayList<Command>();
RestoreFileCommand r1 = new RestoreFileCommand(r.getTo(), r.getRootNodeRef(), r.getToPath(), 0, originalNodeRef);
CopyContentCommand copyContent = new CopyContentCommand(r.getFrom(), r.getTo(), r.getRootNodeRef(), r.getFromPath(), r.getToPath());
DeleteFileCommand d1 = new DeleteFileCommand(r.getFrom(), r.getRootNodeRef(), r.getFromPath());
commands.add(r1);
commands.add(copyContent);
commands.add(d1);
logger.debug("Scenario complete");
isComplete = true;
return new CompoundCommand(commands);
}
else
{
logger.debug("Scenario complete");
isComplete = true;
return null;
}
}
}
if(operation instanceof MoveFileOperation)
{
MoveFileOperation r = (MoveFileOperation)operation;
if(name.equals(r.getTo()))
{
logger.debug("Delete on close Rename shuffle - fire!");
if(originalNodeRef != null)
{
/**
* Shuffle is as follows
* a) Copy content from File to File~
* b) Delete File
* c) Rename File~ to File
*/
ArrayList<Command> commands = new ArrayList<Command>();
RestoreFileCommand r1 = new RestoreFileCommand(r.getTo(), r.getRootNodeRef(), r.getToPath(), 0, originalNodeRef);
CopyContentCommand copyContent = new CopyContentCommand(r.getFrom(), r.getTo(), r.getRootNodeRef(), r.getFromPath(), r.getToPath());
DeleteFileCommand d1 = new DeleteFileCommand(r.getFrom(), r.getRootNodeRef(), r.getFromPath());
commands.add(r1);
commands.add(copyContent);
commands.add(d1);
logger.debug("Scenario complete");
isComplete = true;
return new CompoundCommand(commands);
}
else
{
logger.debug("Scenario complete");
isComplete = true;
return null;
}
}
}
}
return null;
}
@Override
public boolean isComplete()
{
return isComplete;
}
public String toString()
{
return "ScenarioDeleteOnCloseRenameShuffleInstance name:" + name ;
}
public void setTimeout(long timeout)
{
this.timeout = timeout;
}
public long getTimeout()
{
return timeout;
}
@Override
public Ranking getRanking()
{
return ranking;
}
public void setRanking(Ranking ranking)
{
this.ranking = ranking;
}
/**
* Called for delete file.
*/
private ResultCallback newDeleteFileCallbackCommand()
{
return new ResultCallback()
{
@Override
public void execute(Object result)
{
if(result instanceof NodeRef)
{
logger.debug("got node ref of deleted node");
originalNodeRef = (NodeRef)result;
}
}
@Override
public TxnReadState getTransactionRequired()
{
return TxnReadState.TXN_NONE;
}
};
}
}

View File

@@ -562,6 +562,23 @@ class ScenarioOpenFileInstance implements ScenarioInstance, DependentInstance
logger.debug("returning merged high priority executor");
return new CompoundCommand(commands, postCommitCommands, postErrorCommands);
}
if(looser.scenario instanceof ScenarioDeleteOnCloseRenameInstance)
{
CompoundCommand l = (CompoundCommand)looser.command;
ArrayList<Command> commands = new ArrayList<Command>();
ArrayList<Command> postCommitCommands = new ArrayList<Command>();
ArrayList<Command> postErrorCommands = new ArrayList<Command>();
commands.addAll(c.getCommands());
postCommitCommands.addAll(c.getPostCommitCommands());
// Merge in the loosing post commit
postCommitCommands.addAll(l.getPostCommitCommands());
postErrorCommands.addAll(c.getPostErrorCommands());
logger.debug("returning merged high priority executor");
return new CompoundCommand(commands, postCommitCommands, postErrorCommands);
}
}
}
// No change