diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml index 50a33144f7..aa15434089 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml @@ -927,11 +927,15 @@ join alf_node_properties prop on (childNode.id = prop.node_id) where - parentNode.id = #nodeId# + parentNode.id = #parentNodeId# and prop.qname_id = #propertyQNameId# and prop.string_value = #value.stringValue# and prop.double_value = #value.doubleValue# and prop.long_value = #value.longValue# + + and prop.boolean_value = 1 + and prop.boolean_value = 0 + diff --git a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java index c65a461c53..c2d83aa186 100644 --- a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java @@ -2541,9 +2541,11 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO { switch (nodeValue.getPersistedType()) { + case 1: // Boolean case 3: // long case 5: // double case 6: // string + // no floats due to the range errors testing equality on a float. break; default: diff --git a/source/java/org/alfresco/repo/domain/node/ChildPropertyEntity.java b/source/java/org/alfresco/repo/domain/node/ChildPropertyEntity.java index 3a7f0d637b..19a25361a0 100644 --- a/source/java/org/alfresco/repo/domain/node/ChildPropertyEntity.java +++ b/source/java/org/alfresco/repo/domain/node/ChildPropertyEntity.java @@ -6,17 +6,17 @@ package org.alfresco.repo.domain.node; */ public class ChildPropertyEntity { - private Long nodeId; + private Long parentNodeId; private Long propertyQNameId; private NodePropertyValue value; - public void setNodeId(Long nodeId) + public void setParentNodeId(Long nodeId) { - this.nodeId = nodeId; + this.parentNodeId = nodeId; } - public Long getNodeId() + public Long getParentNodeId() { - return nodeId; + return parentNodeId; } public void setPropertyQNameId(Long propertyQNameId) { diff --git a/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java index 537f39aa37..3a6b4433d1 100644 --- a/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java @@ -1335,8 +1335,9 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl ChildPropertyEntity assocProp = new ChildPropertyEntity(); // Parent - assocProp.setNodeId(parentNodeId); + assocProp.setParentNodeId(parentNodeId); + // Property name Pair propName = qnameDAO.getQName(propertyQName); if(propName != null) diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 68d1d61c3a..38ae3bcd84 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -2222,6 +2222,18 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } } + private static List getChildAssocsByPropertyValueBannedProps = new ArrayList(); + static + { + getChildAssocsByPropertyValueBannedProps.add(ContentModel.PROP_NODE_DBID); + getChildAssocsByPropertyValueBannedProps.add(ContentModel.PROP_NODE_UUID); + getChildAssocsByPropertyValueBannedProps.add(ContentModel.PROP_NAME); + getChildAssocsByPropertyValueBannedProps.add(ContentModel.PROP_MODIFIED); + getChildAssocsByPropertyValueBannedProps.add(ContentModel.PROP_MODIFIER); + getChildAssocsByPropertyValueBannedProps.add(ContentModel.PROP_CREATED); + getChildAssocsByPropertyValueBannedProps.add(ContentModel.PROP_CREATOR); + } + @Override public List getChildAssocsByPropertyValue(NodeRef nodeRef, QName propertyQName, @@ -2231,6 +2243,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair nodePair = getNodePairNotNull(nodeRef); Long nodeId = nodePair.getFirst(); + // Check the QName is not one of the "special" system maintained ones. + + if(getChildAssocsByPropertyValueBannedProps.contains(propertyQName)) + { + throw new IllegalArgumentException("getChildAssocsByPropertyValue does not allow search of system maintaied properties: " + propertyQName); + } + final List results = new ArrayList(10); // We have a callback handler to filter results ChildAssocRefQueryCallback callback = new ChildAssocRefQueryCallback() diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java index 56b29b9c0f..7aa2a9d018 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java @@ -425,4 +425,121 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest throw e; } } + + /** + * Test Get Child Assocs By Property Value + * @throws Exception + */ + public void testGetChildAssocsByPropertyValue() throws Exception + { + Map assocRefs; + + assocRefs = buildNodeGraph(); + + ChildAssociationRef rootRef = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "root")); + ChildAssociationRef n1Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "root_p_n1")); + ChildAssociationRef n2Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "root_p_n2")); + + /** + * Positive test - get n1 and n2 by the value of a text property in this case PROP_SUBJECT which + * contains "Hello World" + */ + { + NodeRef parentNodeRef = n1Ref.getParentRef(); + NodeRef childNodeRef = n1Ref.getChildRef(); + assertTrue(nodeService.exists(parentNodeRef)); + assertTrue(nodeService.exists(childNodeRef)); + + String subject = "Hello World"; + nodeService.setProperty(n1Ref.getChildRef(), ContentModel.PROP_SUBJECT, subject); + List refs = nodeService.getChildAssocsByPropertyValue(parentNodeRef, ContentModel.PROP_SUBJECT, subject); + assertTrue("failed to read one assoc", refs.size() == 1); + assertTrue("content not correct", refs.contains(n1Ref)); + + // Now go for another two documents. + nodeService.setProperty(n2Ref.getChildRef(), ContentModel.PROP_SUBJECT, subject); + refs = nodeService.getChildAssocsByPropertyValue(parentNodeRef, ContentModel.PROP_SUBJECT, subject); + assertTrue("failed to read two assocs", refs.size() == 2); + assertTrue("content not correct", refs.contains(n1Ref)); + assertTrue("content not correct", refs.contains(n2Ref)); + } + + /** + * Positive tests of various types that should be accepted by the query + */ + { + NodeRef parentNodeRef = n1Ref.getParentRef(); + NodeRef childNodeRef = n1Ref.getChildRef(); + assertTrue(nodeService.exists(parentNodeRef)); + assertTrue(nodeService.exists(childNodeRef)); + + // integer + int count = 123; + nodeService.setProperty(n1Ref.getChildRef(), ContentModel.PROP_COUNTER, count); + List refs = nodeService.getChildAssocsByPropertyValue(parentNodeRef, ContentModel.PROP_COUNTER, count); + assertTrue("failed to read one assoc", refs.size() == 1); + assertTrue("content not correct", refs.contains(n1Ref)); + + // Double + Double alfLat = new Double(51.5216666); + Double alfLon = new Double(0.43); + nodeService.setProperty(n1Ref.getChildRef(), ContentModel.PROP_LATITUDE, alfLat); + refs = nodeService.getChildAssocsByPropertyValue(parentNodeRef, ContentModel.PROP_LATITUDE, alfLat); + assertTrue("failed to read one assoc", refs.size() == 1); + assertTrue("content not correct", refs.contains(n1Ref)); + + // float + // not implemeted due to float precision issues with float equals. + //float score = 1.3f; + //nodeService.setProperty(n1Ref.getChildRef(), ContentModel.PROP_RATING_SCORE, score); + //refs = nodeService.getChildAssocsByPropertyValue(parentNodeRef, ContentModel.PROP_RATING_SCORE, score); + //assertTrue("failed to read one assoc", refs.size() == 1); + //assertTrue("content not correct", refs.contains(n1Ref)); + + // Boolean TRUE + Boolean beauty = Boolean.TRUE; + nodeService.setProperty(n1Ref.getChildRef(), ContentModel.PROP_ENABLED, beauty); + assertTrue((Boolean)nodeService.getProperty(n1Ref.getChildRef(), ContentModel.PROP_ENABLED)); + refs = nodeService.getChildAssocsByPropertyValue(parentNodeRef, ContentModel.PROP_ENABLED, beauty); + assertTrue("failed to read one assoc", refs.size() == 1); + assertTrue("content not correct", refs.contains(n1Ref)); + + // Boolean FALSE + beauty = Boolean.FALSE; + nodeService.setProperty(n1Ref.getChildRef(), ContentModel.PROP_ENABLED, beauty); + assertTrue(!(Boolean)nodeService.getProperty(n1Ref.getChildRef(), ContentModel.PROP_ENABLED)); + refs = nodeService.getChildAssocsByPropertyValue(parentNodeRef, ContentModel.PROP_ENABLED, beauty); + assertTrue("failed to read one assoc", refs.size() == 1); + + } + + /** + * Negative test - invalid to search on sys:node-dbid + */ + try + { + List refs = nodeService.getChildAssocsByPropertyValue(n1Ref.getParentRef(), ContentModel.PROP_NODE_DBID, "Fail"); + fail("sys:node-dbid not rejected"); + } + catch (IllegalArgumentException ie) + { + // expect to go here + } + + /** + * Negative test - invalid to search on type MLText + */ + try + { + Serializable title = (String)nodeService.getProperty(n1Ref.getChildRef(), ContentModel.PROP_TITLE); + List refs = nodeService.getChildAssocsByPropertyValue(n1Ref.getParentRef(), ContentModel.PROP_NAME, title); + fail("MLText type not rejected"); + } + catch (IllegalArgumentException ie) + { + // expect to go here + } + + + } }