diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml
index 21e3a7b5bf..fe5ac5a120 100644
--- a/config/alfresco/model/contentModel.xml
+++ b/config/alfresco/model/contentModel.xml
@@ -227,22 +227,27 @@
Created
d:datetime
+ true
Creator
d:text
+ true
Modified
d:datetime
+ true
Modifier
d:text
+ true
Accessed
d:datetime
+ true
diff --git a/config/alfresco/rule-services-context.xml b/config/alfresco/rule-services-context.xml
index b038b4bcc9..1ddff2a2fa 100644
--- a/config/alfresco/rule-services-context.xml
+++ b/config/alfresco/rule-services-context.xml
@@ -71,14 +71,14 @@
-
-
+
@@ -100,6 +100,9 @@
+
+
+
diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
index cb8435823b..215e811dee 100644
--- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
+++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
@@ -275,14 +275,20 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
addDefaultAspects(nodeTypeDef, node, childAssocRef.getChildRef(), properties);
// set the properties - it is a new node so only set properties if there are any
+ Map propertiesBefore = getProperties(childAssocRef.getChildRef());
+ Map propertiesAfter = null;
if (properties.size() > 0)
{
- this.setProperties(node.getNodeRef(), properties);
+ propertiesAfter = setPropertiesImpl(childAssocRef.getChildRef(), properties);
}
// Invoke policy behaviour
invokeOnCreateNode(childAssocRef);
invokeOnUpdateNode(parentRef);
+ if (propertiesAfter != null)
+ {
+ invokeOnUpdateProperties(childAssocRef.getChildRef(), propertiesBefore, propertiesAfter);
+ }
// done
return childAssocRef;
@@ -853,6 +859,26 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// Invoke policy behaviours
invokeBeforeUpdateNode(nodeRef);
+ // Do the set properties
+ Map propertiesBefore = getProperties(nodeRef);
+ Map propertiesAfter = setPropertiesImpl(nodeRef, properties);
+
+ // Invoke policy behaviours
+ invokeOnUpdateNode(nodeRef);
+ invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter);
+ }
+
+ /**
+ * Does the work of setting the property values. Returns a map containing the state of the properties after the set
+ * operation is complete.
+ *
+ * @param nodeRef the node reference
+ * @param properties the map of property values
+ * @return the map of property values after the set operation is complete
+ * @throws InvalidNodeRefException
+ */
+ private Map setPropertiesImpl(NodeRef nodeRef, Map properties) throws InvalidNodeRefException
+ {
if (properties == null)
{
throw new IllegalArgumentException("Properties may not be null");
@@ -863,8 +889,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// find the node
Node node = getNodeNotNull(nodeRef);
- // get the properties before
- Map propertiesBefore = getProperties(nodeRef);
// copy properties onto node
Map nodeProperties = node.getProperties();
@@ -880,15 +904,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
nodeProperties.put(propertyQName, propertyValue);
}
- // store the properties after the change
- Map propertiesAfter = Collections.unmodifiableMap(properties);
-
- // Invoke policy behaviours
- invokeOnUpdateNode(nodeRef);
- invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter);
-
// update the node status
nodeDaoService.recordChangeId(nodeRef);
+
+ // Return the properties after
+ return Collections.unmodifiableMap(properties);
}
/**
@@ -904,26 +924,40 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// Invoke policy behaviours
invokeBeforeUpdateNode(nodeRef);
+ // Do the set operation
+ Map propertiesBefore = getProperties(nodeRef);
+ Map propertiesAfter = setPropertyImpl(nodeRef, qname, value);
+
+ // Invoke policy behaviours
+ invokeOnUpdateNode(nodeRef);
+ invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter);
+ }
+
+ /**
+ * Does the work of setting a property value. Returns the values of the properties after the set operation is
+ * complete.
+ *
+ * @param nodeRef the node reference
+ * @param qname the qname of the property
+ * @param value the value of the property
+ * @return the values of the properties after the set operation is complete
+ * @throws InvalidNodeRefException
+ */
+ public Map setPropertyImpl(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException
+ {
// get the node
Node node = getNodeNotNull(nodeRef);
- // get properties before
- Map propertiesBefore = getProperties(nodeRef);
Map properties = node.getProperties();
PropertyDefinition propertyDef = dictionaryService.getProperty(qname);
// get a persistable value
PropertyValue propertyValue = makePropertyValue(propertyDef, value);
properties.put(qname, propertyValue);
-
- // get properties after the change
- Map propertiesAfter = getProperties(nodeRef);
-
- // Invoke policy behaviours
- invokeOnUpdateNode(nodeRef);
- invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter);
-
+
// update the node status
nodeDaoService.recordChangeId(nodeRef);
+
+ return getProperties(nodeRef);
}
/**
diff --git a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
index 5cf83e3703..284909b402 100644
--- a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
+++ b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
@@ -1294,6 +1294,134 @@ public class RuleServiceCoverageTest extends TestCase
ContentModel.ASPECT_VERSIONABLE));
}
+ public void testInboundRuleType()
+ {
+ Map params = new HashMap(1);
+ params.put("aspect-name", ContentModel.ASPECT_VERSIONABLE);
+ Rule rule = createRule(
+ RuleType.INBOUND,
+ AddFeaturesActionExecuter.NAME,
+ params,
+ NoConditionEvaluator.NAME,
+ null);
+
+ this.ruleService.saveRule(this.nodeRef, rule);
+
+ // Create a non-content node
+ NodeRef newNodeRef = this.nodeService.createNode(
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_CONTAINER).getChildRef();
+ assertTrue(this.nodeService.hasAspect(newNodeRef, ContentModel.ASPECT_VERSIONABLE));
+
+ // Create a content node
+ NodeRef contentNodeRef = this.nodeService.createNode(
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_CONTENT).getChildRef();
+ assertFalse(this.nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE));
+ addContentToNode(contentNodeRef);
+ assertTrue(this.nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE));
+
+ // Create a node to be moved
+ NodeRef moveNode = this.nodeService.createNode(
+ newNodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_CONTENT).getChildRef();
+ addContentToNode(moveNode);
+ assertFalse(this.nodeService.hasAspect(moveNode, ContentModel.ASPECT_VERSIONABLE));
+ this.nodeService.moveNode(
+ moveNode,
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"));
+ assertTrue(this.nodeService.hasAspect(moveNode, ContentModel.ASPECT_VERSIONABLE));
+
+ // Enusre the rule type does not get fired when the node is updated
+ this.nodeService.removeAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ assertFalse(this.nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE));
+ this.nodeService.setProperty(contentNodeRef, ContentModel.PROP_NAME, "name.txt");
+ assertFalse(this.nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE));
+ addContentToNode(contentNodeRef);
+ assertFalse(this.nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE));
+ }
+
+ public void testUpdateRuleType()
+ {
+ Map params = new HashMap(1);
+ params.put("aspect-name", ContentModel.ASPECT_VERSIONABLE);
+ Rule rule = createRule(
+ RuleType.UPDATE,
+ AddFeaturesActionExecuter.NAME,
+ params,
+ NoConditionEvaluator.NAME,
+ null);
+
+ this.ruleService.saveRule(this.nodeRef, rule);
+
+ // Create a non-content node
+ NodeRef newNodeRef = this.nodeService.createNode(
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_FOLDER).getChildRef();
+ assertFalse(this.nodeService.hasAspect(newNodeRef, ContentModel.ASPECT_VERSIONABLE));
+
+ // Update the non-content node
+ this.nodeService.setProperty(newNodeRef, ContentModel.PROP_NAME, "testName");
+ assertTrue(this.nodeService.hasAspect(newNodeRef, ContentModel.ASPECT_VERSIONABLE));
+
+ // Create a content node
+ NodeRef contentNodeRef = this.nodeService.createNode(
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_CONTENT).getChildRef();
+ assertFalse(this.nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE));
+ addContentToNode(contentNodeRef);
+ assertFalse(this.nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE));
+ addContentToNode(contentNodeRef);
+ assertTrue(this.nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE));
+
+ // Create a non content node, setting a property at the same time
+ Map props = new HashMap(1);
+ props.put(ContentModel.PROP_NAME, "testName");
+ NodeRef nodeRef2 = this.nodeService.createNode(
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_FOLDER,
+ props).getChildRef();
+ assertFalse(this.nodeService.hasAspect(nodeRef2, ContentModel.ASPECT_VERSIONABLE));
+ this.nodeService.setProperty(nodeRef2, ContentModel.PROP_NAME, "testName");
+ assertFalse(this.nodeService.hasAspect(nodeRef2, ContentModel.ASPECT_VERSIONABLE));
+ this.nodeService.setProperty(nodeRef2, ContentModel.PROP_NAME, "testName2");
+ assertTrue(this.nodeService.hasAspect(nodeRef2, ContentModel.ASPECT_VERSIONABLE));
+
+ TransactionUtil.executeInUserTransaction(this.transactionService, new TransactionUtil.TransactionWork