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:
Derek Hulley
2006-05-24 15:22:34 +00:00
parent 0cc08b2518
commit b9a95c2b31
8 changed files with 126 additions and 22 deletions

View File

@@ -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);
} }
} }
} }

View File

@@ -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");

View 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));
} }
} }
} }

View File

@@ -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

View File

@@ -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;
} }
} }

View File

@@ -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;
}
} }

View File

@@ -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>

View File

@@ -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>