mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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:
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user