mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Fix AR-521: Constraints are inherited (added test to ensure) and overridable (new)
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2970 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -90,7 +90,14 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
resolveDependencies(query, namespaceDAO);
|
resolveDependencies(query, namespaceDAO);
|
||||||
|
|
||||||
// Phase 3: Resolve inheritance of values within class hierachy
|
// Phase 3: Resolve inheritance of values within class hierachy
|
||||||
resolveInheritance(query);
|
NamespacePrefixResolver localPrefixes = createLocalPrefixResolver(model, namespaceDAO);
|
||||||
|
resolveInheritance(query, localPrefixes, constraints);
|
||||||
|
|
||||||
|
// Phase 4: Resolve constraint dependencies
|
||||||
|
for (ConstraintDefinition def : constraints.values())
|
||||||
|
{
|
||||||
|
((M2ConstraintDefinition)def).resolveDependencies(query);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
@@ -220,10 +227,6 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
{
|
{
|
||||||
((M2ClassDefinition)def).resolveDependencies(query, prefixResolver, constraints);
|
((M2ClassDefinition)def).resolveDependencies(query, prefixResolver, constraints);
|
||||||
}
|
}
|
||||||
for (ConstraintDefinition def : constraints.values())
|
|
||||||
{
|
|
||||||
((M2ConstraintDefinition)def).resolveDependencies(query);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -232,7 +235,10 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
*
|
*
|
||||||
* @param query support for querying other items in model
|
* @param query support for querying other items in model
|
||||||
*/
|
*/
|
||||||
private void resolveInheritance(ModelQuery query)
|
private void resolveInheritance(
|
||||||
|
ModelQuery query,
|
||||||
|
NamespacePrefixResolver prefixResolver,
|
||||||
|
Map<QName, ConstraintDefinition> modelConstraints)
|
||||||
{
|
{
|
||||||
// Calculate order of class processing (root to leaf)
|
// Calculate order of class processing (root to leaf)
|
||||||
Map<Integer,List<ClassDefinition>> order = new TreeMap<Integer,List<ClassDefinition>>();
|
Map<Integer,List<ClassDefinition>> order = new TreeMap<Integer,List<ClassDefinition>>();
|
||||||
@@ -270,7 +276,7 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
{
|
{
|
||||||
for (ClassDefinition def : order.get(depth))
|
for (ClassDefinition def : order.get(depth))
|
||||||
{
|
{
|
||||||
((M2ClassDefinition)def).resolveInheritance(query);
|
((M2ClassDefinition)def).resolveInheritance(query, prefixResolver, modelConstraints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@ import junit.framework.TestCase;
|
|||||||
|
|
||||||
import org.alfresco.i18n.I18NUtil;
|
import org.alfresco.i18n.I18NUtil;
|
||||||
import org.alfresco.repo.dictionary.constraint.RegexConstraint;
|
import org.alfresco.repo.dictionary.constraint.RegexConstraint;
|
||||||
|
import org.alfresco.repo.dictionary.constraint.StringLengthConstraint;
|
||||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.Constraint;
|
import org.alfresco.service.cmr.dictionary.Constraint;
|
||||||
@@ -35,6 +36,7 @@ import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
|||||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||||
|
|
||||||
|
|
||||||
public class DictionaryDAOTest extends TestCase
|
public class DictionaryDAOTest extends TestCase
|
||||||
@@ -146,6 +148,38 @@ public class DictionaryDAOTest extends TestCase
|
|||||||
assertTrue("Expected type REGEX constraint", constraint instanceof RegexConstraint);
|
assertTrue("Expected type REGEX constraint", constraint instanceof RegexConstraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testConstraintsOverrideInheritance()
|
||||||
|
{
|
||||||
|
QName baseQName = QName.createQName(TEST_URL, "base");
|
||||||
|
QName fileQName = QName.createQName(TEST_URL, "file");
|
||||||
|
QName folderQName = QName.createQName(TEST_URL, "folder");
|
||||||
|
QName prop1QName = QName.createQName(TEST_URL, "prop1");
|
||||||
|
|
||||||
|
// get the base property
|
||||||
|
PropertyDefinition prop1Def = service.getProperty(baseQName, prop1QName);
|
||||||
|
assertNotNull(prop1Def);
|
||||||
|
List<ConstraintDefinition> prop1Constraints = prop1Def.getConstraints();
|
||||||
|
assertEquals("Incorrect number of constraints", 2, prop1Constraints.size());
|
||||||
|
assertTrue("Constraint instance incorrect", prop1Constraints.get(0).getConstraint() instanceof RegexConstraint);
|
||||||
|
assertTrue("Constraint instance incorrect", prop1Constraints.get(1).getConstraint() instanceof StringLengthConstraint);
|
||||||
|
|
||||||
|
// check the inherited property on folder (must be same as above)
|
||||||
|
prop1Def = service.getProperty(folderQName, prop1QName);
|
||||||
|
assertNotNull(prop1Def);
|
||||||
|
prop1Constraints = prop1Def.getConstraints();
|
||||||
|
assertEquals("Incorrect number of constraints", 2, prop1Constraints.size());
|
||||||
|
assertTrue("Constraint instance incorrect", prop1Constraints.get(0).getConstraint() instanceof RegexConstraint);
|
||||||
|
assertTrue("Constraint instance incorrect", prop1Constraints.get(1).getConstraint() instanceof StringLengthConstraint);
|
||||||
|
|
||||||
|
// check the overridden property on file (must be reverse of above)
|
||||||
|
prop1Def = service.getProperty(fileQName, prop1QName);
|
||||||
|
assertNotNull(prop1Def);
|
||||||
|
prop1Constraints = prop1Def.getConstraints();
|
||||||
|
assertEquals("Incorrect number of constraints", 2, prop1Constraints.size());
|
||||||
|
assertTrue("Constraint instance incorrect", prop1Constraints.get(0).getConstraint() instanceof StringLengthConstraint);
|
||||||
|
assertTrue("Constraint instance incorrect", prop1Constraints.get(1).getConstraint() instanceof RegexConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
public void testArchive()
|
public void testArchive()
|
||||||
{
|
{
|
||||||
QName testFileQName = QName.createQName(TEST_URL, "file");
|
QName testFileQName = QName.createQName(TEST_URL, "file");
|
||||||
|
@@ -204,7 +204,10 @@ import org.alfresco.service.namespace.QName;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*package*/ void resolveInheritance(ModelQuery query)
|
/*package*/ void resolveInheritance(
|
||||||
|
ModelQuery query,
|
||||||
|
NamespacePrefixResolver prefixResolver,
|
||||||
|
Map<QName, ConstraintDefinition> modelConstraints)
|
||||||
{
|
{
|
||||||
// Retrieve parent class
|
// Retrieve parent class
|
||||||
ClassDefinition parentClass = (parentName == null) ? null : query.getClass(parentName);
|
ClassDefinition parentClass = (parentName == null) ? null : query.getClass(parentName);
|
||||||
@@ -221,7 +224,9 @@ import org.alfresco.service.namespace.QName;
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inheritedProperties.put(def.getName(), new M2PropertyDefinition(this, def, override));
|
inheritedProperties.put(
|
||||||
|
def.getName(),
|
||||||
|
new M2PropertyDefinition(this, def, override, prefixResolver, modelConstraints));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,8 @@ package org.alfresco.repo.dictionary;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property Definition
|
* Property Definition
|
||||||
|
@@ -44,8 +44,7 @@ import org.alfresco.service.namespace.QName;
|
|||||||
private QName name;
|
private QName name;
|
||||||
private QName propertyTypeName;
|
private QName propertyTypeName;
|
||||||
private DataTypeDefinition dataType;
|
private DataTypeDefinition dataType;
|
||||||
private List<ConstraintDefinition> constraints = new ArrayList<ConstraintDefinition>(5);
|
private List<ConstraintDefinition> constraintDefs = Collections.emptyList();
|
||||||
private Map<QName, ConstraintDefinition> constraintsByQName = new HashMap<QName, ConstraintDefinition>(7);
|
|
||||||
|
|
||||||
/*package*/ M2PropertyDefinition(
|
/*package*/ M2PropertyDefinition(
|
||||||
ClassDefinition classDef,
|
ClassDefinition classDef,
|
||||||
@@ -64,10 +63,12 @@ import org.alfresco.service.namespace.QName;
|
|||||||
/*package*/ M2PropertyDefinition(
|
/*package*/ M2PropertyDefinition(
|
||||||
ClassDefinition classDef,
|
ClassDefinition classDef,
|
||||||
PropertyDefinition propertyDef,
|
PropertyDefinition propertyDef,
|
||||||
M2PropertyOverride override)
|
M2PropertyOverride override,
|
||||||
|
NamespacePrefixResolver prefixResolver,
|
||||||
|
Map<QName, ConstraintDefinition> modelConstraints)
|
||||||
{
|
{
|
||||||
this.classDef = classDef;
|
this.classDef = classDef;
|
||||||
this.m2Property = createOverriddenProperty(propertyDef, override);
|
this.m2Property = createOverriddenProperty(propertyDef, override, prefixResolver, modelConstraints);
|
||||||
this.name = propertyDef.getName();
|
this.name = propertyDef.getName();
|
||||||
this.dataType = propertyDef.getDataType();
|
this.dataType = propertyDef.getDataType();
|
||||||
this.propertyTypeName = this.dataType.getName();
|
this.propertyTypeName = this.dataType.getName();
|
||||||
@@ -100,15 +101,30 @@ import org.alfresco.service.namespace.QName;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construct constraints
|
// Construct constraints
|
||||||
for (M2Constraint constraint : m2Property.getConstraints())
|
constraintDefs = buildConstraints(
|
||||||
|
m2Property.getConstraints(),
|
||||||
|
this,
|
||||||
|
prefixResolver,
|
||||||
|
modelConstraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ConstraintDefinition> buildConstraints(
|
||||||
|
List<M2Constraint> m2constraints,
|
||||||
|
M2PropertyDefinition m2PropertyDef,
|
||||||
|
NamespacePrefixResolver prefixResolver,
|
||||||
|
Map<QName, ConstraintDefinition> modelConstraints)
|
||||||
|
{
|
||||||
|
List<ConstraintDefinition> constraints = new ArrayList<ConstraintDefinition>(5);
|
||||||
|
Map<QName, ConstraintDefinition> constraintsByQName = new HashMap<QName, ConstraintDefinition>(7);
|
||||||
|
for (M2Constraint constraint : m2constraints)
|
||||||
{
|
{
|
||||||
ConstraintDefinition def = new M2ConstraintDefinition(this, constraint, prefixResolver);
|
ConstraintDefinition def = new M2ConstraintDefinition(m2PropertyDef, constraint, prefixResolver);
|
||||||
QName qname = def.getName();
|
QName qname = def.getName();
|
||||||
if (constraintsByQName.containsKey(qname))
|
if (constraintsByQName.containsKey(qname))
|
||||||
{
|
{
|
||||||
throw new DictionaryException(
|
throw new DictionaryException(
|
||||||
"d_dictionary.property.err.duplicate_constraint_on_property",
|
"d_dictionary.property.err.duplicate_constraint_on_property",
|
||||||
def.getName().toPrefixString(), name.toPrefixString());
|
def.getName().toPrefixString(), m2PropertyDef.name.toPrefixString());
|
||||||
}
|
}
|
||||||
else if (modelConstraints.containsKey(qname))
|
else if (modelConstraints.containsKey(qname))
|
||||||
{
|
{
|
||||||
@@ -120,9 +136,10 @@ import org.alfresco.service.namespace.QName;
|
|||||||
constraints.add(def);
|
constraints.add(def);
|
||||||
modelConstraints.put(qname, def);
|
modelConstraints.put(qname, def);
|
||||||
}
|
}
|
||||||
|
// done
|
||||||
|
return constraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a property definition whose values are overridden
|
* Create a property definition whose values are overridden
|
||||||
*
|
*
|
||||||
@@ -130,7 +147,11 @@ import org.alfresco.service.namespace.QName;
|
|||||||
* @param override the overridden values
|
* @param override the overridden values
|
||||||
* @return the property definition
|
* @return the property definition
|
||||||
*/
|
*/
|
||||||
private M2Property createOverriddenProperty(PropertyDefinition propertyDef, M2PropertyOverride override)
|
private M2Property createOverriddenProperty(
|
||||||
|
PropertyDefinition propertyDef,
|
||||||
|
M2PropertyOverride override,
|
||||||
|
NamespacePrefixResolver prefixResolver,
|
||||||
|
Map<QName, ConstraintDefinition> modelConstraints)
|
||||||
{
|
{
|
||||||
M2Property property = new M2Property();
|
M2Property property = new M2Property();
|
||||||
|
|
||||||
@@ -161,6 +182,21 @@ import org.alfresco.service.namespace.QName;
|
|||||||
property.setMandatory(isOverrideMandatory == null ? propertyDef.isMandatory() : isOverrideMandatory);
|
property.setMandatory(isOverrideMandatory == null ? propertyDef.isMandatory() : isOverrideMandatory);
|
||||||
property.setMandatoryEnforced(isOverrideMandatoryEnforced);
|
property.setMandatoryEnforced(isOverrideMandatoryEnforced);
|
||||||
|
|
||||||
|
// inherit or override constraints
|
||||||
|
List<M2Constraint> overrideConstraints = override.getConstraints();
|
||||||
|
if (overrideConstraints != null)
|
||||||
|
{
|
||||||
|
constraintDefs = buildConstraints(
|
||||||
|
overrideConstraints,
|
||||||
|
(M2PropertyDefinition) propertyDef,
|
||||||
|
prefixResolver,
|
||||||
|
modelConstraints);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.constraintDefs = propertyDef.getConstraints();
|
||||||
|
}
|
||||||
|
|
||||||
// Copy all other properties as they are
|
// Copy all other properties as they are
|
||||||
property.setDescription(propertyDef.getDescription());
|
property.setDescription(propertyDef.getDescription());
|
||||||
property.setIndexed(propertyDef.isIndexed());
|
property.setIndexed(propertyDef.isIndexed());
|
||||||
@@ -323,6 +359,6 @@ import org.alfresco.service.namespace.QName;
|
|||||||
|
|
||||||
public List<ConstraintDefinition> getConstraints()
|
public List<ConstraintDefinition> getConstraints()
|
||||||
{
|
{
|
||||||
return Collections.unmodifiableList(constraints);
|
return constraintDefs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.dictionary;
|
package org.alfresco.repo.dictionary;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property override definition
|
* Property override definition
|
||||||
@@ -29,7 +31,7 @@ public class M2PropertyOverride
|
|||||||
private Boolean isMandatory;
|
private Boolean isMandatory;
|
||||||
private boolean isMandatoryEnforced = false;
|
private boolean isMandatoryEnforced = false;
|
||||||
private String defaultValue;
|
private String defaultValue;
|
||||||
|
private List<M2Constraint> constraints;
|
||||||
|
|
||||||
/*package*/ M2PropertyOverride()
|
/*package*/ M2PropertyOverride()
|
||||||
{
|
{
|
||||||
@@ -75,4 +77,8 @@ public class M2PropertyOverride
|
|||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<M2Constraint> getConstraints()
|
||||||
|
{
|
||||||
|
return constraints;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,10 +27,18 @@
|
|||||||
<parameter name="expression"><value>[A-Z]*</value></parameter>
|
<parameter name="expression"><value>[A-Z]*</value></parameter>
|
||||||
<parameter name="requiresMatch"><value>false</value></parameter>
|
<parameter name="requiresMatch"><value>false</value></parameter>
|
||||||
</constraint>
|
</constraint>
|
||||||
|
<constraint name="test:regex2" type="REGEX">
|
||||||
|
<parameter name="expression"><value>[a-z]*</value></parameter>
|
||||||
|
<parameter name="requiresMatch"><value>false</value></parameter>
|
||||||
|
</constraint>
|
||||||
<constraint name="test:stringLength1" type="LENGTH">
|
<constraint name="test:stringLength1" type="LENGTH">
|
||||||
<parameter name="minLength"><value>0</value></parameter>
|
<parameter name="minLength"><value>0</value></parameter>
|
||||||
<parameter name="maxLength"><value>256</value></parameter>
|
<parameter name="maxLength"><value>256</value></parameter>
|
||||||
</constraint>
|
</constraint>
|
||||||
|
<constraint name="test:stringLength2" type="LENGTH">
|
||||||
|
<parameter name="minLength"><value>0</value></parameter>
|
||||||
|
<parameter name="maxLength"><value>128</value></parameter>
|
||||||
|
</constraint>
|
||||||
<constraint name="test:minMax1" type="MINMAX">
|
<constraint name="test:minMax1" type="MINMAX">
|
||||||
<parameter name="minValue"><value>0</value></parameter>
|
<parameter name="minValue"><value>0</value></parameter>
|
||||||
<parameter name="maxValue"><value>256</value></parameter>
|
<parameter name="maxValue"><value>256</value></parameter>
|
||||||
@@ -132,8 +140,12 @@
|
|||||||
</associations>
|
</associations>
|
||||||
|
|
||||||
<overrides>
|
<overrides>
|
||||||
<property name="test:prop">
|
<property name="test:prop1">
|
||||||
<default>an overriden default value</default>
|
<default>an overriden default value</default>
|
||||||
|
<constraints>
|
||||||
|
<constraint ref="test:stringLength2"/>
|
||||||
|
<constraint ref="test:regex2"/>
|
||||||
|
</constraints>
|
||||||
</property>
|
</property>
|
||||||
</overrides>
|
</overrides>
|
||||||
</type>
|
</type>
|
||||||
|
@@ -77,6 +77,9 @@
|
|||||||
<value style="text" field="isMandatory" />
|
<value style="text" field="isMandatory" />
|
||||||
</structure>
|
</structure>
|
||||||
<value name="default" field="defaultValue" usage="optional"/>
|
<value name="default" field="defaultValue" usage="optional"/>
|
||||||
|
<structure name="constraints" usage="optional">
|
||||||
|
<collection field="constraints" item-type="org.alfresco.repo.dictionary.M2Constraint" factory="org.alfresco.repo.dictionary.M2Model.createList"/>
|
||||||
|
</structure>
|
||||||
</structure>
|
</structure>
|
||||||
</collection>
|
</collection>
|
||||||
</structure>
|
</structure>
|
||||||
|
Reference in New Issue
Block a user