diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml
index 94a8fcf7f0..b21121a42e 100644
--- a/config/alfresco/content-services-context.xml
+++ b/config/alfresco/content-services-context.xml
@@ -730,7 +730,7 @@
parent="baseComplexContentTransformer" >
-
+
@@ -871,6 +871,14 @@
+
+
+
+ text/html
+ application/pdf
+
+
+
@@ -938,7 +946,7 @@
parent="baseComplexContentTransformer" >
-
+
@@ -989,6 +997,61 @@
+
+
+
+
+
+
+
+
+
+
+
+ application/pdf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ application/vnd.oasis.opendocument.text
+
+
+
+
+
+ text/html
+ application/pdf
+
+
+
+
+
+
+ text/html
+ application/pdf
+
+
+
+
+
diff --git a/config/alfresco/model/imapModel.xml b/config/alfresco/model/imapModel.xml
index 3bc8243383..1d79886e02 100644
--- a/config/alfresco/model/imapModel.xml
+++ b/config/alfresco/model/imapModel.xml
@@ -40,31 +40,71 @@
d:text
+
+ true
+ false
+ both
+
d:text
+
+ true
+ false
+ both
+
d:text
+
+ true
+ false
+ both
+
d:text
+
+ true
+ false
+ both
+
d:text
+
+ true
+ false
+ both
+
d:text
+
+ true
+ false
+ both
+
Date Received
d:datetime
false
+
+ true
+ false
+ both
+
Date Sent
d:datetime
false
+
+ true
+ false
+ both
+
diff --git a/config/alfresco/rule-services-context.xml b/config/alfresco/rule-services-context.xml
index 02bfa6faa4..deac3bf049 100644
--- a/config/alfresco/rule-services-context.xml
+++ b/config/alfresco/rule-services-context.xml
@@ -143,13 +143,24 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
onCreateAssociation
-
+
onDeleteAssociation
diff --git a/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml b/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml
index eb32c6a834..b2cb6ea006 100644
--- a/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml
+++ b/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml
@@ -140,6 +140,14 @@
60000
MEDIUM
+
+
+
+ .*
+ 20000
+ MEDIUM
+
+
.*
@@ -207,7 +215,16 @@
20000
MEDIUM
true
-
+
+
+
+
+ ^Word Work File L_.*\.tmp?
+ 20000
+ MEDIUM
+ false
+
+
diff --git a/config/alfresco/swf-transform-context.xml b/config/alfresco/swf-transform-context.xml
index 05d43fea8a..47d52cd681 100644
--- a/config/alfresco/swf-transform-context.xml
+++ b/config/alfresco/swf-transform-context.xml
@@ -31,7 +31,7 @@
parent="baseComplexContentTransformer" >
-
+
diff --git a/source/java/org/alfresco/filesys/alfresco/ExtendedDiskInterface.java b/source/java/org/alfresco/filesys/alfresco/ExtendedDiskInterface.java
index 1e349499da..b2560ca98e 100644
--- a/source/java/org/alfresco/filesys/alfresco/ExtendedDiskInterface.java
+++ b/source/java/org/alfresco/filesys/alfresco/ExtendedDiskInterface.java
@@ -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;
diff --git a/source/java/org/alfresco/filesys/alfresco/RepositoryDiskInterface.java b/source/java/org/alfresco/filesys/alfresco/RepositoryDiskInterface.java
index 3e9340c29a..68b112753f 100644
--- a/source/java/org/alfresco/filesys/alfresco/RepositoryDiskInterface.java
+++ b/source/java/org/alfresco/filesys/alfresco/RepositoryDiskInterface.java
@@ -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;
/**
diff --git a/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java b/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java
index 86e8097c1d..b5c842ad75 100644
--- a/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java
+++ b/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java
@@ -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)
{
diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java
index 9e5698151d..3074c1e62e 100644
--- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java
+++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java
@@ -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 auditableProps = new HashMap(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)
{
diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java
index 3c5bb0895e..722220f359 100644
--- a/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java
+++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java
@@ -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 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/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 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/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 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) delete the old file");
+ 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);
+ } // 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 createFileCB = new RetryingTransactionCallback() {
+
+ @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 deleteTargetFileCB = new RetryingTransactionCallback() {
+
+ @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 moveTempFileCB = new RetryingTransactionCallback() {
+
+ @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 validateCB = new RetryingTransactionCallback() {
+
+ @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
*/
diff --git a/source/java/org/alfresco/filesys/repo/rules/ScenarioDeleteOnCloseRename.java b/source/java/org/alfresco/filesys/repo/rules/ScenarioDeleteOnCloseRename.java
new file mode 100644
index 0000000000..37b297fd8e
--- /dev/null
+++ b/source/java/org/alfresco/filesys/repo/rules/ScenarioDeleteOnCloseRename.java
@@ -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 .
+ */
+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;
+ }
+}
diff --git a/source/java/org/alfresco/filesys/repo/rules/ScenarioDeleteOnCloseRenameInstance.java b/source/java/org/alfresco/filesys/repo/rules/ScenarioDeleteOnCloseRenameInstance.java
new file mode 100644
index 0000000000..35703369fc
--- /dev/null
+++ b/source/java/org/alfresco/filesys/repo/rules/ScenarioDeleteOnCloseRenameInstance.java
@@ -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 .
+ */
+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 commands = new ArrayList();
+ ArrayList postCommitCommands = new ArrayList();
+ ArrayList postErrorCommands = new ArrayList();
+ 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 commands = new ArrayList();
+ 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 commands = new ArrayList();
+ 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;
+ }
+ };
+ }
+
+}
+
diff --git a/source/java/org/alfresco/filesys/repo/rules/ScenarioOpenFileInstance.java b/source/java/org/alfresco/filesys/repo/rules/ScenarioOpenFileInstance.java
index 04fc80965e..68caa96acd 100644
--- a/source/java/org/alfresco/filesys/repo/rules/ScenarioOpenFileInstance.java
+++ b/source/java/org/alfresco/filesys/repo/rules/ScenarioOpenFileInstance.java
@@ -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 commands = new ArrayList();
+ ArrayList postCommitCommands = new ArrayList();
+ ArrayList postErrorCommands = new ArrayList();
+ 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
diff --git a/source/java/org/alfresco/repo/content/ContentServiceImpl.java b/source/java/org/alfresco/repo/content/ContentServiceImpl.java
index 1c914f7da0..562bdb0ab7 100644
--- a/source/java/org/alfresco/repo/content/ContentServiceImpl.java
+++ b/source/java/org/alfresco/repo/content/ContentServiceImpl.java
@@ -800,9 +800,8 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
private void debugActiveTransformers(String sourceMimetype, String targetMimetype,
long sourceSize, TransformationOptions transformOptions)
{
- // check the file name, but do faster tests first
- if (sourceSize == 18 &&
- MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(sourceMimetype) &&
+ // check the file name
+ if (MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(sourceMimetype) &&
MimetypeMap.MIMETYPE_IMAGE_PNG.equals(targetMimetype) &&
"debugTransformers.txt".equals(transformerDebug.getFileName(transformOptions, true, 0)))
{
diff --git a/source/java/org/alfresco/repo/content/metadata/DWGMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/DWGMetadataExtracter.java
index 52dc38fe4a..ccc6670998 100644
--- a/source/java/org/alfresco/repo/content/metadata/DWGMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/DWGMetadataExtracter.java
@@ -65,6 +65,7 @@ public class DWGMetadataExtracter extends TikaPoweredMetadataExtracter
super(SUPPORTED_MIMETYPES);
}
+ @SuppressWarnings("deprecation")
@Override
protected Map extractSpecific(Metadata metadata,
Map properties, Map headers)
diff --git a/source/java/org/alfresco/repo/content/metadata/DWGMetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/DWGMetadataExtracterTest.java
index 3260fc8fec..ab43839c2f 100644
--- a/source/java/org/alfresco/repo/content/metadata/DWGMetadataExtracterTest.java
+++ b/source/java/org/alfresco/repo/content/metadata/DWGMetadataExtracterTest.java
@@ -45,6 +45,7 @@ public class DWGMetadataExtracterTest extends AbstractMetadataExtracterTest
private static final QName TIKA_LAST_AUTHOR_TEST_PROPERTY =
QName.createQName("TikaLastAuthorTestProp");
+ @SuppressWarnings("deprecation")
@Override
public void setUp() throws Exception
{
diff --git a/source/java/org/alfresco/repo/content/metadata/MP3MetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/MP3MetadataExtracter.java
index 226db82850..478a0bb400 100644
--- a/source/java/org/alfresco/repo/content/metadata/MP3MetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/MP3MetadataExtracter.java
@@ -77,6 +77,7 @@ public class MP3MetadataExtracter extends TikaAudioMetadataExtracter
return new Mp3Parser();
}
+ @SuppressWarnings("deprecation")
@Override
protected Map extractSpecific(Metadata metadata,
Map properties, Map headers)
diff --git a/source/java/org/alfresco/repo/content/metadata/MailMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/MailMetadataExtracter.java
index 45a40224e9..193a260529 100644
--- a/source/java/org/alfresco/repo/content/metadata/MailMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/MailMetadataExtracter.java
@@ -59,7 +59,7 @@ public class MailMetadataExtracter extends TikaPoweredMetadataExtracter
public static ArrayList SUPPORTED_MIMETYPES = buildSupportedMimetypes(
new String[] {MimetypeMap.MIMETYPE_OUTLOOK_MSG},
- null
+ (Parser[])null
);
public MailMetadataExtracter()
@@ -74,6 +74,7 @@ public class MailMetadataExtracter extends TikaPoweredMetadataExtracter
return new OfficeParser();
}
+ @SuppressWarnings("deprecation")
@Override
protected Map extractSpecific(Metadata metadata,
Map properties, Map headers)
diff --git a/source/java/org/alfresco/repo/content/metadata/MailMetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/MailMetadataExtracterTest.java
index abffac8d20..d0d035e673 100644
--- a/source/java/org/alfresco/repo/content/metadata/MailMetadataExtracterTest.java
+++ b/source/java/org/alfresco/repo/content/metadata/MailMetadataExtracterTest.java
@@ -20,7 +20,6 @@ package org.alfresco.repo.content.metadata;
import java.io.File;
import java.io.Serializable;
-import java.util.Collection;
import java.util.Map;
import org.alfresco.model.ContentModel;
diff --git a/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java b/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java
index 1aabf85e94..2411611503 100644
--- a/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java
+++ b/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java
@@ -173,6 +173,7 @@ public class MetadataExtracterRegistry
return liveExtractor;
}
+ @SuppressWarnings("deprecation")
private String getName(MetadataExtracter extractor)
{
return extractor == null
diff --git a/source/java/org/alfresco/repo/content/metadata/OfficeMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/OfficeMetadataExtracter.java
index e2629318a9..d08d9fe3d2 100644
--- a/source/java/org/alfresco/repo/content/metadata/OfficeMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/OfficeMetadataExtracter.java
@@ -92,6 +92,7 @@ public class OfficeMetadataExtracter extends TikaPoweredMetadataExtracter
return new OfficeParser();
}
+ @SuppressWarnings("deprecation")
@Override
protected Map extractSpecific(Metadata metadata,
Map properties, Map headers)
diff --git a/source/java/org/alfresco/repo/content/metadata/OpenDocumentMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/OpenDocumentMetadataExtracter.java
index f6ca5d86ee..976e5ce803 100644
--- a/source/java/org/alfresco/repo/content/metadata/OpenDocumentMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/OpenDocumentMetadataExtracter.java
@@ -70,8 +70,8 @@ public class OpenDocumentMetadataExtracter extends TikaPoweredMetadataExtracter
private static final String KEY_INITIAL_CREATOR = "initialCreator";
private static final String KEY_KEYWORD = "keyword";
private static final String KEY_LANGUAGE = "language";
- private static final String KEY_PRINT_DATE = "printDate";
- private static final String KEY_PRINTED_BY = "printedBy";
+// private static final String KEY_PRINT_DATE = "printDate";
+// private static final String KEY_PRINTED_BY = "printedBy";
private static final String CUSTOM_PREFIX = "custom:";
@@ -110,6 +110,7 @@ public class OpenDocumentMetadataExtracter extends TikaPoweredMetadataExtracter
return new OpenDocumentParser();
}
+ @SuppressWarnings("deprecation")
@Override
protected Map extractSpecific(Metadata metadata,
Map properties, Map headers)
diff --git a/source/java/org/alfresco/repo/content/metadata/RFC822MetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/RFC822MetadataExtracter.java
index d9a482cdb8..4ff8530375 100644
--- a/source/java/org/alfresco/repo/content/metadata/RFC822MetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/RFC822MetadataExtracter.java
@@ -162,6 +162,7 @@ public class RFC822MetadataExtracter extends AbstractMappingMetadataExtracter
* Extract values from all header fields, including extension fields "X-"
*/
Set keys = getMapping().keySet();
+ @SuppressWarnings("unchecked")
Enumeration headers = mimeMessage.getAllHeaders();
while (headers.hasMoreElements())
{
diff --git a/source/java/org/alfresco/repo/content/metadata/RFC822MetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/RFC822MetadataExtracterTest.java
index 86a731b772..7dee659984 100644
--- a/source/java/org/alfresco/repo/content/metadata/RFC822MetadataExtracterTest.java
+++ b/source/java/org/alfresco/repo/content/metadata/RFC822MetadataExtracterTest.java
@@ -91,6 +91,7 @@ public class RFC822MetadataExtracterTest extends AbstractMetadataExtracterTest
* Check that this was sprung-in - if not, then
* other tests will fail!
*/
+ @SuppressWarnings("unchecked")
public void testHasDateFormats() throws Exception {
Set supportedDateFormats;
diff --git a/source/java/org/alfresco/repo/content/metadata/TikaAudioMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/TikaAudioMetadataExtracter.java
index 9f4030286e..31b74a1221 100644
--- a/source/java/org/alfresco/repo/content/metadata/TikaAudioMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/TikaAudioMetadataExtracter.java
@@ -155,6 +155,7 @@ public class TikaAudioMetadataExtracter extends TikaPoweredMetadataExtracter
* @param props the properties extracted from the file
* @return the description
*/
+ @SuppressWarnings("deprecation")
private String generateDescription(Metadata metadata)
{
StringBuilder result = new StringBuilder();
diff --git a/source/java/org/alfresco/repo/content/metadata/TikaAutoMetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/TikaAutoMetadataExtracterTest.java
index 4617a92eae..8a4c01b044 100644
--- a/source/java/org/alfresco/repo/content/metadata/TikaAutoMetadataExtracterTest.java
+++ b/source/java/org/alfresco/repo/content/metadata/TikaAutoMetadataExtracterTest.java
@@ -225,7 +225,8 @@ public class TikaAutoMetadataExtracterTest extends AbstractMetadataExtracterTest
* Instead, these will be handled by the Auto Tika Parser, and
* this test ensures that they are
*/
- public void testImageVideo() throws Throwable {
+ @SuppressWarnings("deprecation")
+public void testImageVideo() throws Throwable {
Map p;
// Image
diff --git a/source/java/org/alfresco/repo/content/metadata/TikaPoweredMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/TikaPoweredMetadataExtracter.java
index 3217a49c0d..b527fc2ddf 100644
--- a/source/java/org/alfresco/repo/content/metadata/TikaPoweredMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/TikaPoweredMetadataExtracter.java
@@ -269,6 +269,7 @@ public abstract class TikaPoweredMetadataExtracter
}
}
+ @SuppressWarnings("deprecation")
@Override
protected Map extractRaw(ContentReader reader) throws Throwable
{
diff --git a/source/java/org/alfresco/repo/content/metadata/xml/XPathMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/xml/XPathMetadataExtracter.java
index e7aee2bcd9..e195b65660 100644
--- a/source/java/org/alfresco/repo/content/metadata/xml/XPathMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/xml/XPathMetadataExtracter.java
@@ -149,6 +149,7 @@ public class XPathMetadataExtracter extends AbstractMappingMetadataExtracter imp
}
/** {@inheritDoc} */
+ @SuppressWarnings("rawtypes")
public Iterator getPrefixes(String namespaceURI)
{
ParameterCheck.mandatoryString("namespaceURI", namespaceURI);
@@ -341,6 +342,7 @@ public class XPathMetadataExtracter extends AbstractMappingMetadataExtracter imp
*
* @see #setMappingProperties(Properties)
*/
+ @SuppressWarnings("rawtypes")
protected void readXPathMappingProperties(Properties xpathMappingProperties)
{
// Get the namespaces
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerHelper.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerHelper.java
index 08a2a4ba38..c7278c124b 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformerHelper.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerHelper.java
@@ -38,6 +38,7 @@ public class ContentTransformerHelper
private MimetypeService mimetypeService;
private List explicitTransformations;
private List supportedTransformations;
+ private List unsupportedTransformations;
/**
*
@@ -46,6 +47,7 @@ public class ContentTransformerHelper
{
setExplicitTransformations(Collections. emptyList());
setSupportedTransformations(null);
+ setUnsupportedTransformations(null);
}
/**
@@ -78,7 +80,7 @@ public class ContentTransformerHelper
/**
* Restricts the transformations that may be performed even though the transformer
- * may perform other transformations. An null value applies no additional restrictions.
+ * may perform other transformations. An null value applies no additional restrictions.
* Even if a list is specified, the
* {@link ContentTransformer#isTransformableMimetype(String, String, TransformationOptions)}
* method will still be called.
@@ -88,6 +90,18 @@ public class ContentTransformerHelper
this.supportedTransformations = supportedTransformations;
}
+ /**
+ * Restricts the transformations that may be performed even though the transformer
+ * may claim to perform the transformations. An null value applies no additional restrictions.
+ * Even if a list is specified, the
+ * {@link ContentTransformer#isTransformableMimetype(String, String, TransformationOptions)}
+ * method will still be called.
+ */
+ public void setUnsupportedTransformations(List unsupportedTransformations)
+ {
+ this.unsupportedTransformations = unsupportedTransformations;
+ }
+
/**
* Convenience to fetch and check the mimetype for the given content
*
@@ -131,10 +145,10 @@ public class ContentTransformerHelper
public boolean isSupportedTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
- boolean result = true;
+ boolean supported = true;
if (supportedTransformations != null)
{
- result = false;
+ supported = false;
for (SupportedTransformation suportedTransformation : supportedTransformations)
{
String supportedSourceMimetype = suportedTransformation.getSourceMimetype();
@@ -142,11 +156,25 @@ public class ContentTransformerHelper
if ((supportedSourceMimetype == null || sourceMimetype.equals(supportedSourceMimetype)) &&
(supportedTargetMimetype == null || targetMimetype.equals(supportedTargetMimetype)))
{
- result = true;
+ supported = true;
break;
}
}
}
- return result;
+ if (supported && unsupportedTransformations != null)
+ {
+ for (SupportedTransformation unsuportedTransformation : unsupportedTransformations)
+ {
+ String unsupportedSourceMimetype = unsuportedTransformation.getSourceMimetype();
+ String unsupportedTargetMimetype = unsuportedTransformation.getTargetMimetype();
+ if ((unsupportedSourceMimetype == null || sourceMimetype.equals(unsupportedSourceMimetype)) &&
+ (unsupportedTargetMimetype == null || targetMimetype.equals(unsupportedTargetMimetype)))
+ {
+ supported = false;
+ break;
+ }
+ }
+ }
+ return supported;
}
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/lock/LockServiceImpl.java b/source/java/org/alfresco/repo/lock/LockServiceImpl.java
index ffcb227b79..7ca0561934 100644
--- a/source/java/org/alfresco/repo/lock/LockServiceImpl.java
+++ b/source/java/org/alfresco/repo/lock/LockServiceImpl.java
@@ -22,7 +22,6 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
-import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@@ -33,7 +32,6 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.copy.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails;
import org.alfresco.repo.copy.CopyServicePolicies;
-import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
import org.alfresco.repo.copy.DoNothingCopyBehaviourCallback;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.BehaviourFilter;
@@ -72,7 +70,6 @@ public class LockServiceImpl implements LockService,
NodeServicePolicies.BeforeDeleteNodePolicy,
NodeServicePolicies.OnMoveNodePolicy,
CopyServicePolicies.OnCopyNodePolicy,
- VersionServicePolicies.BeforeCreateVersionPolicy,
VersionServicePolicies.OnCreateVersionPolicy
{
/** Key to the nodes ref's to ignore when checking for locks */
@@ -148,10 +145,10 @@ public class LockServiceImpl implements LockService,
new JavaBehaviour(this, "getCopyCallback"));
// Register the onCreateVersion behavior for the version aspect
- this.policyComponent.bindClassBehaviour(
- VersionServicePolicies.BeforeCreateVersionPolicy.QNAME,
- ContentModel.ASPECT_LOCKABLE,
- new JavaBehaviour(this, "beforeCreateVersion"));
+
+ // BeforeCreateVersion behavior was removed
+ // we should be able to version a node regardless of its lock state, see ALF-16540
+
this.policyComponent.bindClassBehaviour(
VersionServicePolicies.OnCreateVersionPolicy.QNAME,
ContentModel.ASPECT_LOCKABLE,
@@ -544,16 +541,6 @@ public class LockServiceImpl implements LockService,
{
return DoNothingCopyBehaviourCallback.getInstance();
}
-
- /**
- * Ensures that node is not locked.
- *
- * @see #checkForLock(NodeRef)
- */
- public void beforeCreateVersion(NodeRef versionableNode)
- {
- checkForLock(versionableNode);
- }
/**
* OnCreateVersion behaviour for the lock aspect
diff --git a/source/java/org/alfresco/repo/rule/MiscellaneousRulesTest.java b/source/java/org/alfresco/repo/rule/MiscellaneousRulesTest.java
new file mode 100644
index 0000000000..c451a76537
--- /dev/null
+++ b/source/java/org/alfresco/repo/rule/MiscellaneousRulesTest.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2005-2012 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.repo.rule;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.action.executer.AddFeaturesActionExecuter;
+import org.alfresco.repo.action.executer.CopyActionExecuter;
+import org.alfresco.repo.content.MimetypeMap;
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
+import org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.action.ActionService;
+import org.alfresco.service.cmr.repository.CopyService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.rule.RuleService;
+import org.alfresco.service.cmr.rule.RuleType;
+import org.alfresco.service.cmr.site.SiteInfo;
+import org.alfresco.service.cmr.site.SiteService;
+import org.alfresco.service.cmr.site.SiteVisibility;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.test.junitrules.AlfrescoPerson;
+import org.alfresco.util.test.junitrules.ApplicationContextInit;
+import org.alfresco.util.test.junitrules.RunAsFullyAuthenticatedRule;
+import org.alfresco.util.test.junitrules.TemporaryNodes;
+import org.alfresco.util.test.junitrules.TemporarySites;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.springframework.context.ApplicationContext;
+
+
+/**
+ * Integration tests for Alfresco Rules. This class does not test the internals of the {@link RuleService}
+ * but rather sets up and runs common or previously problematic rules use cases and ensures they are correct.
+ *
+ * @author Neil Mc Erlean
+ * @since 4.1.3
+ */
+public class MiscellaneousRulesTest
+{
+ // Static JUnit Rules
+ public static ApplicationContextInit APP_CTXT_INIT = new ApplicationContextInit();
+ public static AlfrescoPerson TEST_USER = new AlfrescoPerson(APP_CTXT_INIT);
+
+ // Rule chain to ensure they run in the right order
+ @ClassRule public static RuleChain STATIC_RULE_CHAIN = RuleChain.outerRule(APP_CTXT_INIT)
+ .around(TEST_USER);
+
+ // Non-static JUnit Rules
+ public RunAsFullyAuthenticatedRule runAsRule = new RunAsFullyAuthenticatedRule(TEST_USER);
+ public TemporarySites testSites = new TemporarySites(APP_CTXT_INIT);
+ public TemporaryNodes testNodes = new TemporaryNodes(APP_CTXT_INIT);
+
+ // Rule chain to ensure they run in the right order
+ @Rule public RuleChain ruleChain = RuleChain.outerRule(runAsRule)
+ .around(testSites)
+ .around(testNodes);
+
+ private static ActionService ACTION_SERVICE;
+ private static CopyService COPY_SERVICE;
+ private static NodeService NODE_SERVICE;
+ private static RetryingTransactionHelper TRANSACTION_HELPER;
+ private static RuleService RULE_SERVICE;
+ private static SiteService SITE_SERVICE;
+
+ private SiteInfo testSite;
+
+ @BeforeClass public static void initSpringBeans() throws Exception
+ {
+ final ApplicationContext appCtxt = APP_CTXT_INIT.getApplicationContext();
+
+ ACTION_SERVICE = appCtxt.getBean("ActionService", ActionService.class);
+ COPY_SERVICE = appCtxt.getBean("CopyService", CopyService.class);
+ NODE_SERVICE = appCtxt.getBean("NodeService", NodeService.class);
+ TRANSACTION_HELPER = appCtxt.getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
+ RULE_SERVICE = appCtxt.getBean("RuleService", RuleService.class);
+ SITE_SERVICE = appCtxt.getBean("SiteService", SiteService.class);
+ }
+
+ @Before public void createTestData() throws Exception
+ {
+ testSite = testSites.createSite("sitePreset", "testSiteName", "testSiteTitle", "test site description",
+ SiteVisibility.PUBLIC, TEST_USER.getUsername());
+
+ }
+
+ @Test public void alf14568() throws Exception
+ {
+ final NodeRef testSiteDocLib = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public NodeRef execute() throws Throwable
+ {
+ return SITE_SERVICE.getContainer(testSite.getShortName(), SiteService.DOCUMENT_LIBRARY);
+ }
+ });
+ assertNotNull("Null doclib", testSiteDocLib);
+
+ // Create four folders - the first (zero'th) will not be used.
+ final NodeRef[] folders = new NodeRef[4];
+ for (int i : new int[] {0, 1, 2, 3})
+ {
+ folders[i] = testNodes.createFolder(testSiteDocLib, "folder" + i, TEST_USER.getUsername());
+ }
+
+ // Create an inbound rule for Folder1 - copy to Folder2.
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ // Clashes with the JUnit annotation @Rule
+ org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
+ rule.setRuleType(RuleType.INBOUND);
+ rule.applyToChildren(false);
+ rule.setRuleDisabled(false);
+ rule.setTitle("Copy to folder2");
+ rule.setExecuteAsynchronously(false);
+
+ Map params = new HashMap();
+ params.put(CopyActionExecuter.PARAM_DESTINATION_FOLDER, folders[2]);
+ Action copyAction = ACTION_SERVICE.createAction("copy", params);
+ rule.setAction(copyAction);
+
+ RULE_SERVICE.saveRule(folders[1], rule);
+
+ return null;
+ }
+ });
+
+ // Create an update rule for Folder2 - copy to Folder3.
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
+ rule.setRuleType(RuleType.UPDATE);
+ rule.applyToChildren(false);
+ rule.setRuleDisabled(false);
+ rule.setTitle("Copy to folder3");
+ rule.setExecuteAsynchronously(false);
+
+ Map params = new HashMap();
+ params.put(CopyActionExecuter.PARAM_DESTINATION_FOLDER, folders[3]);
+ Action copyAction = ACTION_SERVICE.createAction("copy", params);
+ rule.setAction(copyAction);
+
+ RULE_SERVICE.saveRule(folders[2], rule);
+
+ return null;
+ }
+ });
+
+ // Now put a file in Folder1. - don't need transaction as one is included within this call
+ testNodes.createQuickFile(MimetypeMap.MIMETYPE_TEXT_PLAIN, folders[1], "quick.txt", TEST_USER.getUsername());
+
+ // Which folders is the file in?
+ final Set foldersContainingFile = new HashSet();
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ for (NodeRef folder : folders)
+ {
+ NodeRef child = NODE_SERVICE.getChildByName(folder, ContentModel.ASSOC_CONTAINS, "quick.txt");
+ if (child != null)
+ {
+ foldersContainingFile.add(folder);
+ }
+ }
+
+ return null;
+ }
+ });
+
+ // Now disable all the rules - I don't think this should be necessary, but if we don't do this, the teardown
+ // parts of the JUnit Rules cause problems in the repo.
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ for (NodeRef folder : folders)
+ {
+ RULE_SERVICE.removeAllRules(folder);
+ }
+
+ return null;
+ }
+ });
+
+ final Set expectedFolders = new HashSet();
+ expectedFolders.add(folders[1]);
+ expectedFolders.add(folders[2]);
+
+ assertEquals(expectedFolders, foldersContainingFile);
+ }
+
+ /**
+ * ALF-14568 doesn't explicitly say so, but there is a related problem on top of the
+ * 'creating cm:original assoc triggers rule' bug. It is the related 'deleting cm:original assoc triggers rule' bug.
+ * This test case validates the fix for that issue.
+ */
+ @Test public void alf14568_supplementary() throws Exception
+ {
+ final NodeRef testSiteDocLib = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public NodeRef execute() throws Throwable
+ {
+ return SITE_SERVICE.getContainer(testSite.getShortName(), SiteService.DOCUMENT_LIBRARY);
+ }
+ });
+ assertNotNull("Null doclib", testSiteDocLib);
+
+ // Create a folder to put our Alfresco Rules on - but don't put any rules on it yet.
+ final NodeRef ruleFolder = testNodes.createFolder(testSiteDocLib, "ruleFolder", TEST_USER.getUsername());
+
+ // Create a piece of content outside our Rules folder.
+ final NodeRef originalContent = testNodes.createQuickFile(MimetypeMap.MIMETYPE_TEXT_PLAIN,
+ testSiteDocLib,
+ "original.txt",
+ TEST_USER.getUsername());
+
+ // Now copy that node into the Ruled folder, which will create a cm:original assoc.
+ final NodeRef copyNode = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public NodeRef execute() throws Throwable
+ {
+ return COPY_SERVICE.copy(originalContent, ruleFolder, ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS);
+ }
+ });
+
+ final QName exifAspectQName = QName.createQName("{http://www.alfresco.org/model/exif/1.0}exif");
+
+ // Only now do we create the update rule on our folder - put a marker aspect on the node.
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ // Clashes with the JUnit annotation @Rule
+ org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
+ rule.setRuleType(RuleType.UPDATE);
+ rule.applyToChildren(false);
+ rule.setRuleDisabled(false);
+ rule.setTitle("Put EXIF aspect on changed nodes");
+ rule.setExecuteAsynchronously(false);
+
+ Map params = new HashMap();
+ params.put(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, exifAspectQName);
+ Action addAspectAction = ACTION_SERVICE.createAction("add-features", params);
+ rule.setAction(addAspectAction);
+
+ RULE_SERVICE.saveRule(ruleFolder, rule);
+
+ return null;
+ }
+ });
+
+ // Now delete the original node.
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ NODE_SERVICE.deleteNode(originalContent);
+
+ return null;
+ }
+ });
+
+ // The removal of the cm:original association should NOT have triggered the rule.
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ assertFalse("Rule executed when it shouldn't have.", NODE_SERVICE.hasAspect(copyNode, exifAspectQName));
+
+ return null;
+ }
+ });
+ }
+}
diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java
index 63219a3463..48265a676a 100644
--- a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java
+++ b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java
@@ -199,7 +199,30 @@ public class RuleTriggerTest extends BaseSpringTest
this.nodeService.createAssociation(nodeRef, nodeRef2, ContentModel.ASSOC_CHILDREN);
// Check to see if the rule type has been triggered
- assertTrue(ruleType.rulesTriggered);
+ assertTrue(ruleType.rulesTriggered);
+ }
+
+ public void testOnCreateOriginalAssociationTrigger()
+ {
+ NodeRef nodeRef = this.nodeService.createNode(
+ this.rootNodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ ContentModel.ASSOC_CHILDREN,
+ ContentModel.TYPE_CONTAINER).getChildRef();
+ NodeRef nodeRef2 = this.nodeService.createNode(
+ this.rootNodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ ContentModel.ASSOC_CHILDREN,
+ ContentModel.TYPE_CONTAINER).getChildRef();
+
+ TestRuleType ruleType = createTestRuleType(ON_CREATE_ASSOCIATION_TRIGGER);
+ assertFalse(ruleType.rulesTriggered);
+
+ // Try and trigger the type
+ this.nodeService.createAssociation(nodeRef, nodeRef2, ContentModel.ASSOC_ORIGINAL);
+
+ // Check to see if the rule type has been triggered
+ assertFalse(ruleType.rulesTriggered);
}
public void testOnDeleteAssociationTrigger()
diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/SingleAssocRefPolicyRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/SingleAssocRefPolicyRuleTrigger.java
index 3516e0f52b..ecaf9f5d02 100644
--- a/source/java/org/alfresco/repo/rule/ruletrigger/SingleAssocRefPolicyRuleTrigger.java
+++ b/source/java/org/alfresco/repo/rule/ruletrigger/SingleAssocRefPolicyRuleTrigger.java
@@ -18,7 +18,9 @@
*/
package org.alfresco.repo.rule.ruletrigger;
+import java.util.Collections;
import java.util.List;
+import java.util.Set;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.service.cmr.repository.AssociationRef;
@@ -36,6 +38,7 @@ public class SingleAssocRefPolicyRuleTrigger extends RuleTriggerAbstractBase
private String policyNamespace = NamespaceService.ALFRESCO_URI;
private String policyName;
+ private Set excludedAssocTypes = Collections.emptySet();
public void setPolicyNamespace(String policyNamespace)
{
@@ -47,6 +50,10 @@ public class SingleAssocRefPolicyRuleTrigger extends RuleTriggerAbstractBase
this.policyName = policyName;
}
+ public void setExcludedAssociationTypes(Set assocTypes) {
+ this.excludedAssocTypes = assocTypes;
+ }
+
/**
* @see org.alfresco.repo.rule.ruletrigger.RuleTrigger#registerRuleTrigger()
*/
@@ -63,19 +70,23 @@ public class SingleAssocRefPolicyRuleTrigger extends RuleTriggerAbstractBase
public void policyBehaviour(AssociationRef assocRef)
{
- NodeRef nodeRef = assocRef.getSourceRef();
-
- if (nodeService.exists(nodeRef))
+ final QName assocTypeQName = assocRef.getTypeQName();
+ if ( !excludedAssocTypes.contains(assocTypeQName))
{
- List parentsAssocRefs = this.nodeService.getParentAssocs(nodeRef);
- for (ChildAssociationRef parentAssocRef : parentsAssocRefs)
+ NodeRef nodeRef = assocRef.getSourceRef();
+
+ if (nodeService.exists(nodeRef))
{
- triggerRules(parentAssocRef.getParentRef(), nodeRef);
- if (logger.isDebugEnabled() == true)
+ List parentsAssocRefs = this.nodeService.getParentAssocs(nodeRef);
+ for (ChildAssociationRef parentAssocRef : parentsAssocRefs)
{
- logger.debug(
- "OnUpdateAssoc rule triggered (parent); " +
- "nodeRef=" + parentAssocRef.getParentRef());
+ triggerRules(parentAssocRef.getParentRef(), nodeRef);
+ if (logger.isDebugEnabled() == true)
+ {
+ logger.debug(
+ "OnUpdateAssoc rule triggered (parent); " +
+ "nodeRef=" + parentAssocRef.getParentRef());
+ }
}
}
}
diff --git a/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService.java b/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService.java
index b8c271cdf3..abf35f7750 100644
--- a/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService.java
+++ b/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService.java
@@ -48,7 +48,10 @@ import org.alfresco.util.ScriptPagingDetails;
* @author Mark Rogers
*/
public class ScriptAuthorityService extends BaseScopableProcessorExtension
-{
+{
+ /** RegEx to split a String on the first space. */
+ public static final String ON_FIRST_SPACE = " +";
+
/** The group/authority service */
private AuthorityService authorityService;
/** The person service */
@@ -468,6 +471,15 @@ public class ScriptAuthorityService extends BaseScopableProcessorExtension
filter.add(new Pair(ContentModel.PROP_LASTNAME, nameFilter));
filter.add(new Pair(ContentModel.PROP_USERNAME, nameFilter));
+ // In order to support queries for "Alan Smithee", we'll parse these tokens
+ // and add them in to the query.
+ final Pair tokenisedName = tokeniseName(nameFilter);
+ if (tokenisedName != null)
+ {
+ filter.add(new Pair(ContentModel.PROP_FIRSTNAME, tokenisedName.getFirst()));
+ filter.add(new Pair(ContentModel.PROP_LASTNAME, tokenisedName.getSecond()));
+ }
+
// Build the sorting. The user controls the primary sort, we supply
// additional ones automatically
List> sort = new ArrayList>();
@@ -506,4 +518,39 @@ public class ScriptAuthorityService extends BaseScopableProcessorExtension
return users;
}
+
+ /**
+ * This method will tokenise a name string in order to extract first name, last name - if possible.
+ * The split is simple - it's made on the first whitespace within the trimmed nameFilter String. So
+ *
+ * "Luke Skywalker" becomes ["Luke", "Skywalker"].
+ *
+ * "Jar Jar Binks" becomes ["Jar", "Jar Binks"].
+ *
+ * "C-3PO" becomes null.
+ *
+ * @param nameFilter
+ * @return A Pair if the String is valid, else null.
+ */
+ private Pair tokeniseName(String nameFilter)
+ {
+ Pair result = null;
+
+ if (nameFilter != null)
+ {
+ final String trimmedNameFilter = nameFilter.trim();
+
+ // We can only have a first name and a last name if we have at least 3 characters e.g. "A B".
+ if (trimmedNameFilter.length() > 3)
+ {
+ final String[] tokens = trimmedNameFilter.split(ON_FIRST_SPACE, 2);
+ if (tokens.length == 2)
+ {
+ result = new Pair(tokens[0], tokens[1]);
+ }
+ }
+ }
+
+ return result;
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService_RegExTest.java b/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService_RegExTest.java
new file mode 100644
index 0000000000..944f5ad9a6
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService_RegExTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005-2012 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.repo.security.authority.script;
+
+import static org.alfresco.repo.security.authority.script.ScriptAuthorityService.ON_FIRST_SPACE;
+import static org.junit.Assert.assertArrayEquals;
+
+import org.junit.Test;
+
+/**
+ * Simple sanity tests for regular expression {@link ScriptAuthorityService#ON_FIRST_SPACE}.
+ *
+ * @author Neil Mc Erlean
+ * @since 4.1.3
+ */
+public class ScriptAuthorityService_RegExTest
+{
+ @Test public void validateFirstNameLastNameRegEx() throws Exception
+ {
+ assertArrayEquals(new String[] {"Luke", "Skywalker"}, "Luke Skywalker".split(ON_FIRST_SPACE, 2));
+
+ // Surnames with spaces in - yes, this is wrong (I think), but it's what we expect our naive algorithm to do.
+ assertArrayEquals(new String[] {"Jar", "Jar Binks"}, "Jar Jar Binks".split(ON_FIRST_SPACE, 2));
+
+ // Too short names (no surname)
+ assertArrayEquals(new String[] {"C-3PO"}, "C-3PO".split(ON_FIRST_SPACE, 2));
+ }
+}
diff --git a/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java b/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java
index 2e96ee5a88..0171b9fb9c 100644
--- a/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java
+++ b/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java
@@ -35,6 +35,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.version.common.versionlabel.SerialVersionLabelPolicy;
+import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
@@ -66,6 +67,7 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
protected NodeArchiveService nodeArchiveService;
protected NodeService nodeService;
protected PermissionService permissionService;
+ protected CheckOutCheckInService checkOutCheckInService;
/*
* Data used by tests
@@ -155,6 +157,7 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
this.nodeArchiveService = (NodeArchiveService) applicationContext.getBean("nodeArchiveService");
this.nodeService = (NodeService)applicationContext.getBean("nodeService");
this.permissionService = (PermissionService)this.applicationContext.getBean("permissionService");
+ this.checkOutCheckInService = (CheckOutCheckInService) applicationContext.getBean("checkOutCheckInService");
setVersionService((VersionService)applicationContext.getBean("versionService"));
diff --git a/source/java/org/alfresco/repo/version/Version2ServiceImpl.java b/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
index 48ae441c5f..d694503cdb 100644
--- a/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
+++ b/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
@@ -353,11 +353,20 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe
// Create the version data object
Version version = getVersion(newVersionRef);
- // Set the new version label on the 'live' (versioned) node
- this.nodeService.setProperty(
- nodeRef,
- ContentModel.PROP_VERSION_LABEL,
- version.getVersionLabel());
+ // Disabling behavior to be able to create properties for a locked node, see ALF-16540
+ policyBehaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_LOCKABLE);
+ try
+ {
+ // Set the new version label on the 'live' (versioned) node
+ this.nodeService.setProperty(
+ nodeRef,
+ ContentModel.PROP_VERSION_LABEL,
+ version.getVersionLabel());
+ }
+ finally
+ {
+ policyBehaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_LOCKABLE);
+ }
// Re-enable the auditable aspect (if we turned it off earlier)
policyBehaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
diff --git a/source/java/org/alfresco/repo/version/VersionServiceImplTest.java b/source/java/org/alfresco/repo/version/VersionServiceImplTest.java
index 0a979c290c..ad1e3d6319 100644
--- a/source/java/org/alfresco/repo/version/VersionServiceImplTest.java
+++ b/source/java/org/alfresco/repo/version/VersionServiceImplTest.java
@@ -2052,6 +2052,36 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
assertEquals(USER_NAME_A, nodeService.getProperty(versioned, ContentModel.PROP_MODIFIER));
}
+ /*
+ * It should be possible to create a version for a locked node, see ALF-16540
+ */
+ public void testVersionLockedNode()
+ {
+ transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback