diff --git a/config/alfresco/model/systemModel.xml b/config/alfresco/model/systemModel.xml
index 41f99a7d6c..75d16dd404 100644
--- a/config/alfresco/model/systemModel.xml
+++ b/config/alfresco/model/systemModel.xml
@@ -147,6 +147,12 @@
false
+
+
+ NoContent
+ false
+
+
Archived
diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
index a9390a000c..f33c57b753 100644
--- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
+++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
@@ -1835,6 +1835,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Create it - the path will be created, if necessary
NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, true);
+ nodeService.addAspect(nodeRef, ContentModel.ASPECT_NO_CONTENT, null);
// Create the network file
diff --git a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
index d3a312bf5c..d48c88f083 100644
--- a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
+++ b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
@@ -408,9 +408,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile
if (contentChanged)
{
ContentData contentData = content.getContentData();
+ NodeRef contentNodeRef = getNodeRef();
+ nodeService.removeAspect(contentNodeRef, ContentModel.ASPECT_NO_CONTENT);
try
{
- nodeService.setProperty( getNodeRef(), ContentModel.PROP_CONTENT, contentData);
+ nodeService.setProperty( contentNodeRef, ContentModel.PROP_CONTENT, contentData);
}
catch (ContentQuotaException qe)
{
diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java
index 45d2122723..85830415a7 100644
--- a/source/java/org/alfresco/model/ContentModel.java
+++ b/source/java/org/alfresco/model/ContentModel.java
@@ -45,6 +45,9 @@ public interface ContentModel
// tag for temporary nodes
static final QName ASPECT_TEMPORARY = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "temporary");
+ // tag for nodes being formed (CIFS)
+ static final QName ASPECT_NO_CONTENT = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "noContent");
+
// tag for localized nodes
static final QName ASPECT_LOCALIZED = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "localized");
static final QName PROP_LOCALE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "locale");
diff --git a/source/java/org/alfresco/repo/content/ContentServiceImpl.java b/source/java/org/alfresco/repo/content/ContentServiceImpl.java
index fb92cb1250..0c43136de3 100644
--- a/source/java/org/alfresco/repo/content/ContentServiceImpl.java
+++ b/source/java/org/alfresco/repo/content/ContentServiceImpl.java
@@ -35,6 +35,7 @@ import org.alfresco.repo.content.cleanup.EagerContentStoreCleaner;
import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.repo.content.transform.ContentTransformer;
import org.alfresco.repo.content.transform.ContentTransformerRegistry;
+import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
@@ -175,7 +176,7 @@ public class ContentServiceImpl implements ContentService
// Bind on update properties behaviour
this.policyComponent.bindClassBehaviour(
- QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
+ NodeServicePolicies.OnUpdatePropertiesPolicy.QNAME,
this,
new JavaBehaviour(this, "onUpdateProperties"));
@@ -197,6 +198,12 @@ public class ContentServiceImpl implements ContentService
Map before,
Map after)
{
+ // ALF-254: empty files (0 bytes) do not trigger content rules
+ if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_NO_CONTENT))
+ {
+ return;
+ }
+
// Don't duplicate work when firing multiple policies
Set types = null;
OnContentPropertyUpdatePolicy propertyPolicy = null; // Doesn't change for the node instance
diff --git a/source/java/org/alfresco/repo/content/cleanup/EagerContentStoreCleaner.java b/source/java/org/alfresco/repo/content/cleanup/EagerContentStoreCleaner.java
index 6c2fdd1521..07e03394a0 100644
--- a/source/java/org/alfresco/repo/content/cleanup/EagerContentStoreCleaner.java
+++ b/source/java/org/alfresco/repo/content/cleanup/EagerContentStoreCleaner.java
@@ -26,9 +26,6 @@ import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.repo.transaction.TransactionalResourceHelper;
-import org.alfresco.service.cmr.repository.ContentData;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.namespace.QName;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -69,13 +66,11 @@ public class EagerContentStoreCleaner extends TransactionListenerAdapter
{
/**
* Content URLs to delete once the transaction commits.
- * @see #onContentPropertyUpdate(NodeRef, QName, ContentData, ContentData)
* @see #afterCommit()
*/
private static final String KEY_POST_COMMIT_DELETION_URLS = "ContentStoreCleaner.PostCommitDeletionUrls";
/**
- * Content URLs to delete if the transaction rolls b ack.
- * @see #onContentPropertyUpdate(NodeRef, QName, ContentData, ContentData)
+ * Content URLs to delete if the transaction rolls back.
* @see #afterRollback()
*/
private static final String KEY_POST_ROLLBACK_DELETION_URLS = "ContentStoreCleaner.PostRollbackDeletionUrls";
diff --git a/source/java/org/alfresco/service/cmr/repository/ContentData.java b/source/java/org/alfresco/service/cmr/repository/ContentData.java
index 4d362c4a7a..19ee93307e 100644
--- a/source/java/org/alfresco/service/cmr/repository/ContentData.java
+++ b/source/java/org/alfresco/service/cmr/repository/ContentData.java
@@ -153,7 +153,7 @@ public class ContentData implements Serializable
* Helper method to determine if the data represents any physical content or not.
*
* @param contentData the content to check (may be null)
- * @return true if the value is non-null and has a content URL of non-zero length
+ * @return true if the value is non-null
*/
public static boolean hasContent(ContentData contentData)
{
@@ -161,7 +161,7 @@ public class ContentData implements Serializable
{
return false;
}
- return (contentData.contentUrl != null) && (contentData.size > 0L);
+ return contentData.contentUrl != null;
}
/**