mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Property constraint dictionary support
Constraint implementation support Regular expression constraint git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2547 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -26,6 +26,7 @@ import java.util.TreeMap;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
@@ -66,7 +67,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
private Map<QName, AspectDefinition> aspects = new HashMap<QName, AspectDefinition>();
|
||||
private Map<QName, PropertyDefinition> properties = new HashMap<QName, PropertyDefinition>();
|
||||
private Map<QName, AssociationDefinition> associations = new HashMap<QName, AssociationDefinition>();
|
||||
|
||||
private Map<QName, ConstraintDefinition> constraints = new HashMap<QName, ConstraintDefinition>();
|
||||
|
||||
/**
|
||||
* Construct
|
||||
@@ -82,11 +83,11 @@ import org.apache.commons.logging.LogFactory;
|
||||
// Phase 1: Construct model definitions from model entries
|
||||
// resolving qualified names
|
||||
this.model = model;
|
||||
constructDefinitions(model, dictionaryDAO, namespaceDAO);
|
||||
constructDefinitions(model, namespaceDAO);
|
||||
|
||||
// Phase 2: Resolve dependencies between model definitions
|
||||
ModelQuery query = new DelegateModelQuery(this, dictionaryDAO);
|
||||
resolveDependencies(query);
|
||||
resolveDependencies(query, namespaceDAO);
|
||||
|
||||
// Phase 3: Resolve inheritance of values within class hierachy
|
||||
resolveInheritance(query);
|
||||
@@ -111,10 +112,9 @@ import org.apache.commons.logging.LogFactory;
|
||||
* Construct compiled definitions
|
||||
*
|
||||
* @param model model definition
|
||||
* @param dictionaryDAO dictionary DAO
|
||||
* @param namespaceDAO namespace DAO
|
||||
*/
|
||||
private void constructDefinitions(M2Model model, DictionaryDAO dictionaryDAO, NamespaceDAO namespaceDAO)
|
||||
private void constructDefinitions(M2Model model, NamespaceDAO namespaceDAO)
|
||||
{
|
||||
NamespacePrefixResolver localPrefixes = createLocalPrefixResolver(model, namespaceDAO);
|
||||
|
||||
@@ -155,6 +155,18 @@ import org.apache.commons.logging.LogFactory;
|
||||
classes.put(def.getName(), def);
|
||||
aspects.put(def.getName(), def);
|
||||
}
|
||||
|
||||
// Construct Constraint Definitions
|
||||
for (M2Constraint constraint : model.getConstraints())
|
||||
{
|
||||
M2ConstraintDefinition def = new M2ConstraintDefinition(modelDefinition, null, constraint, localPrefixes);
|
||||
QName qname = def.getName();
|
||||
if (constraints.containsKey(qname))
|
||||
{
|
||||
throw new DictionaryException("Found duplicate constraint definition " + constraint.getName() + " (an aspect)");
|
||||
}
|
||||
constraints.put(qname, def);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,15 +208,21 @@ import org.apache.commons.logging.LogFactory;
|
||||
*
|
||||
* @param query support for querying other items in model
|
||||
*/
|
||||
private void resolveDependencies(ModelQuery query)
|
||||
private void resolveDependencies(ModelQuery query, NamespaceDAO namespaceDAO)
|
||||
{
|
||||
NamespacePrefixResolver prefixResolver = createLocalPrefixResolver(model, namespaceDAO);
|
||||
|
||||
for (DataTypeDefinition def : dataTypes.values())
|
||||
{
|
||||
((M2DataTypeDefinition)def).resolveDependencies(query);
|
||||
}
|
||||
for (ClassDefinition def : classes.values())
|
||||
{
|
||||
((M2ClassDefinition)def).resolveDependencies(query);
|
||||
((M2ClassDefinition)def).resolveDependencies(query, prefixResolver, constraints);
|
||||
}
|
||||
for (ConstraintDefinition def : constraints.values())
|
||||
{
|
||||
((M2ConstraintDefinition)def).resolveDependencies(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,4 +381,11 @@ import org.apache.commons.logging.LogFactory;
|
||||
return associations.get(name);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.impl.ModelQuery#getConstraint(QName)
|
||||
*/
|
||||
public ConstraintDefinition getConstraint(QName name)
|
||||
{
|
||||
return constraints.get(name);
|
||||
}
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ package org.alfresco.repo.dictionary;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
@@ -147,5 +148,17 @@ import org.alfresco.service.namespace.QName;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ModelQuery#getConstraint(QName)
|
||||
*/
|
||||
public ConstraintDefinition getConstraint(QName name)
|
||||
{
|
||||
ConstraintDefinition def = query.getConstraint(name);
|
||||
if (def == null)
|
||||
{
|
||||
def = delegate.getConstraint(name);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
@@ -144,7 +145,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
if (model == null)
|
||||
{
|
||||
// TODO: Load model from persistent store
|
||||
throw new DictionaryException("Model " + modelName + " does not exist");
|
||||
throw new DictionaryException("d_dictionary.model.err.no_model", modelName);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
@@ -226,6 +227,11 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
return (model == null) ? null : model.getProperty(propertyName);
|
||||
}
|
||||
|
||||
public ConstraintDefinition getConstraint(QName constraintQName)
|
||||
{
|
||||
CompiledModel model = getCompiledModelForNamespace(constraintQName.getNamespaceURI());
|
||||
return (model == null) ? null : model.getConstraint(constraintQName);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.impl.ModelQuery#getAssociation(org.alfresco.repo.ref.QName)
|
||||
@@ -288,7 +294,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
TypeDefinition typeDef = getType(type);
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new DictionaryException("Failed to create anonymous type as specified type " + type + " not found");
|
||||
throw new DictionaryException("d_dictionary.model.err.type_not_found", type);
|
||||
}
|
||||
Collection<AspectDefinition> aspectDefs = new ArrayList<AspectDefinition>();
|
||||
if (aspects != null)
|
||||
@@ -298,7 +304,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
AspectDefinition aspectDef = getAspect(aspect);
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new DictionaryException("Failed to create anonymous type as specified aspect " + aspect + " not found");
|
||||
throw new DictionaryException("d_dictionary.model.err.aspect_not_found", aspect);
|
||||
}
|
||||
aspectDefs.add(aspectDef);
|
||||
}
|
||||
|
@@ -21,7 +21,11 @@ import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.repo.dictionary.constraint.RegexConstraint;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.Constraint;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
|
||||
@@ -33,15 +37,20 @@ import org.alfresco.service.namespace.QName;
|
||||
|
||||
public class DictionaryDAOTest extends TestCase
|
||||
{
|
||||
|
||||
public static final String TEST_RESOURCE_MESSAGES = "alfresco/messages/dictionary-messages";
|
||||
|
||||
private static final String TEST_URL = "http://www.alfresco.org/test/dictionarydaotest/1.0";
|
||||
private static final String TEST_MODEL = "org/alfresco/repo/dictionary/dictionarydaotest_model.xml";
|
||||
private static final String TEST_BUNDLE = "org/alfresco/repo/dictionary/dictionarydaotest_model";
|
||||
private DictionaryService service;
|
||||
private DictionaryService service;
|
||||
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
// register resource bundles for messages
|
||||
I18NUtil.registerResourceBundle(TEST_RESOURCE_MESSAGES);
|
||||
|
||||
// Instantiate Dictionary Service
|
||||
NamespaceDAO namespaceDAO = new NamespaceDAOImpl();
|
||||
DictionaryDAOImpl dictionaryDAO = new DictionaryDAOImpl(namespaceDAO);
|
||||
@@ -90,34 +99,59 @@ public class DictionaryDAOTest extends TestCase
|
||||
|
||||
public void testLabels()
|
||||
{
|
||||
QName model = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "dictionarydaotest");
|
||||
QName model = QName.createQName(TEST_URL, "dictionarydaotest");
|
||||
ModelDefinition modelDef = service.getModel(model);
|
||||
assertEquals("Model Description", modelDef.getDescription());
|
||||
QName type = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "base");
|
||||
QName type = QName.createQName(TEST_URL, "base");
|
||||
TypeDefinition typeDef = service.getType(type);
|
||||
assertEquals("Base Title", typeDef.getTitle());
|
||||
assertEquals("Base Description", typeDef.getDescription());
|
||||
QName prop = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "prop1");
|
||||
QName prop = QName.createQName(TEST_URL, "prop1");
|
||||
PropertyDefinition propDef = service.getProperty(prop);
|
||||
assertEquals("Prop1 Title", propDef.getTitle());
|
||||
assertEquals("Prop1 Description", propDef.getDescription());
|
||||
QName assoc = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "assoc1");
|
||||
QName assoc = QName.createQName(TEST_URL, "assoc1");
|
||||
AssociationDefinition assocDef = service.getAssociation(assoc);
|
||||
assertEquals("Assoc1 Title", assocDef.getTitle());
|
||||
assertEquals("Assoc1 Description", assocDef.getDescription());
|
||||
QName datatype = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "datatype");
|
||||
QName datatype = QName.createQName(TEST_URL, "datatype");
|
||||
DataTypeDefinition datatypeDef = service.getDataType(datatype);
|
||||
assertEquals("Datatype Analyser", datatypeDef.getAnalyserClassName());
|
||||
}
|
||||
|
||||
public void testConstraints()
|
||||
{
|
||||
// get the constraints for a property without constraints
|
||||
QName propNoConstraintsQName = QName.createQName(TEST_URL, "fileprop");
|
||||
PropertyDefinition propNoConstraintsDef = service.getProperty(propNoConstraintsQName);
|
||||
assertNotNull("Property without constraints returned empty list", propNoConstraintsDef.getConstraints());
|
||||
|
||||
// get the constraints defined for the property
|
||||
QName prop1QName = QName.createQName(TEST_URL, "prop1");
|
||||
PropertyDefinition propDef = service.getProperty(prop1QName);
|
||||
List<ConstraintDefinition> constraints = propDef.getConstraints();
|
||||
assertNotNull("Null constraints list", constraints);
|
||||
assertEquals("Incorrect number of constraints", 1, constraints.size());
|
||||
|
||||
// check the individual constraints
|
||||
ConstraintDefinition constraintDef = constraints.get(0);
|
||||
assertTrue("Constraint anonymous name incorrect", constraintDef.getName().getLocalName().startsWith("prop1_anon"));
|
||||
// check that the constraint implementation is valid (it used a reference)
|
||||
Constraint constraint = constraintDef.getConstraint();
|
||||
assertNotNull("Reference constraint has no implementation", constraint);
|
||||
|
||||
// make sure it is the correct type of constraint
|
||||
assertTrue("Expected type REGEX constraint", constraint instanceof RegexConstraint);
|
||||
}
|
||||
|
||||
|
||||
public void testSubClassOf()
|
||||
{
|
||||
QName invalid = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "invalid");
|
||||
QName base = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "base");
|
||||
QName file = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "file");
|
||||
QName folder = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "folder");
|
||||
QName referenceable = QName.createQName("http://www.alfresco.org/test/dictionarydaotest/1.0", "referenceable");
|
||||
QName invalid = QName.createQName(TEST_URL, "invalid");
|
||||
QName base = QName.createQName(TEST_URL, "base");
|
||||
QName file = QName.createQName(TEST_URL, "file");
|
||||
QName folder = QName.createQName(TEST_URL, "folder");
|
||||
QName referenceable = QName.createQName(TEST_URL, "referenceable");
|
||||
|
||||
// Test invalid args
|
||||
try
|
||||
|
@@ -27,6 +27,7 @@ import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
@@ -166,7 +167,10 @@ import org.alfresco.service.namespace.QName;
|
||||
}
|
||||
|
||||
|
||||
/*package*/ void resolveDependencies(ModelQuery query)
|
||||
/*package*/ void resolveDependencies(
|
||||
ModelQuery query,
|
||||
NamespacePrefixResolver prefixResolver,
|
||||
Map<QName, ConstraintDefinition> modelConstraints)
|
||||
{
|
||||
if (parentName != null)
|
||||
{
|
||||
@@ -179,7 +183,7 @@ import org.alfresco.service.namespace.QName;
|
||||
|
||||
for (PropertyDefinition def : properties.values())
|
||||
{
|
||||
((M2PropertyDefinition)def).resolveDependencies(query);
|
||||
((M2PropertyDefinition)def).resolveDependencies(query, prefixResolver, modelConstraints);
|
||||
}
|
||||
for (AssociationDefinition def : associations.values())
|
||||
{
|
||||
|
74
source/java/org/alfresco/repo/dictionary/M2Constraint.java
Normal file
74
source/java/org/alfresco/repo/dictionary/M2Constraint.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract Property Constraint.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class M2Constraint
|
||||
{
|
||||
private String name;
|
||||
private String ref;
|
||||
private String type;
|
||||
private String description;
|
||||
private List<M2NamedValue> parameters = new ArrayList<M2NamedValue>(2);
|
||||
|
||||
/*package*/ M2Constraint()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getRef()
|
||||
{
|
||||
return ref;
|
||||
}
|
||||
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getDescription()
|
||||
{
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<M2NamedValue> getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
}
|
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.dictionary.constraint.RegexConstraint;
|
||||
import org.alfresco.service.cmr.dictionary.Constraint;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
import org.alfresco.service.namespace.NamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
|
||||
/**
|
||||
* Compiled Property Constraint
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
/*package*/ class M2ConstraintDefinition implements ConstraintDefinition
|
||||
{
|
||||
public static final String ERR_CYCLIC_REF = "d_dictionary.model.err.cyclic_ref";
|
||||
public static final String ERR_TYPE_AND_REF = "d_dictionary.constraint.err.type_and_ref";
|
||||
public static final String ERR_TYPE_OR_REF = "d_dictionary.constraint.err.type_or_ref";
|
||||
public static final String ERR_REF_NOT_FOUND = "d_dictionary.constraint.err.ref_not_found";
|
||||
public static final String ERR_ANON_NEEDS_PROPERTY = "d_dictionary.constraint.err.anon_needs_property";
|
||||
public static final String ERR_INVALID_TYPE = "d_dictionary.constraint.err.invalid_type";
|
||||
public static final String ERR_CONSTRUCT_FAILURE = "d_dictionary.constraint.err.construct_failure";
|
||||
|
||||
private static int anonPropCount = 0;
|
||||
|
||||
private ModelDefinition model;
|
||||
private NamespacePrefixResolver prefixResolver;
|
||||
private M2Constraint m2Constraint;
|
||||
private QName name;
|
||||
private Constraint constraint;
|
||||
private boolean resolving;
|
||||
|
||||
/*package*/ M2ConstraintDefinition(
|
||||
M2PropertyDefinition m2PropertyDef,
|
||||
M2Constraint m2Constraint,
|
||||
NamespacePrefixResolver prefixResolver)
|
||||
{
|
||||
this(m2PropertyDef.getModel(), m2PropertyDef, m2Constraint, prefixResolver);
|
||||
}
|
||||
|
||||
/*package*/ M2ConstraintDefinition(
|
||||
ModelDefinition modelDefinition,
|
||||
M2PropertyDefinition m2PropertyDef,
|
||||
M2Constraint m2Constraint,
|
||||
NamespacePrefixResolver prefixResolver)
|
||||
{
|
||||
this.model = modelDefinition;
|
||||
this.m2Constraint = m2Constraint;
|
||||
this.prefixResolver = prefixResolver;
|
||||
|
||||
String constraintName = m2Constraint.getName();
|
||||
if (constraintName == null)
|
||||
{
|
||||
// the constraint is anonymous, so it has to be defined within the context of a property
|
||||
if (m2PropertyDef == null)
|
||||
{
|
||||
throw new DictionaryException(ERR_ANON_NEEDS_PROPERTY);
|
||||
}
|
||||
// pick the name up from the property and some anonymous value
|
||||
String localName = m2PropertyDef.getName().getLocalName() + "_anon_" + (++anonPropCount);
|
||||
this.name = QName.createQName(m2PropertyDef.getName().getNamespaceURI(), localName);
|
||||
m2Constraint.setName(localName);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.name = QName.createQName(m2Constraint.getName(), prefixResolver);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ synchronized void resolveDependencies(ModelQuery query)
|
||||
{
|
||||
if (resolving)
|
||||
{
|
||||
throw new DictionaryException(ERR_CYCLIC_REF, name.toPrefixString());
|
||||
}
|
||||
// prevent circular references
|
||||
try
|
||||
{
|
||||
resolving = true;
|
||||
resolveInternal(query);
|
||||
}
|
||||
finally
|
||||
{
|
||||
resolving = false;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void resolveInternal(ModelQuery query)
|
||||
{
|
||||
if (constraint != null)
|
||||
{
|
||||
// already been resolved
|
||||
return;
|
||||
}
|
||||
String shortName = name.toPrefixString();
|
||||
String ref = m2Constraint.getRef();
|
||||
String type = m2Constraint.getType();
|
||||
if (ref != null && type != null)
|
||||
{
|
||||
throw new DictionaryException(ERR_TYPE_AND_REF, shortName);
|
||||
}
|
||||
else if (ref == null && type == null)
|
||||
{
|
||||
throw new DictionaryException(ERR_TYPE_OR_REF, shortName);
|
||||
}
|
||||
else if (ref != null)
|
||||
{
|
||||
// resolve the reference name
|
||||
QName qnameRef = QName.createQName(ref, prefixResolver);
|
||||
// ensure that the reference exists in the model
|
||||
M2ConstraintDefinition constraintDef = (M2ConstraintDefinition) query.getConstraint(qnameRef);
|
||||
if (constraintDef == null)
|
||||
{
|
||||
throw new DictionaryException(ERR_REF_NOT_FOUND, ref, shortName);
|
||||
}
|
||||
// make sure that the constraint definition has itself been resolved
|
||||
constraintDef.resolveDependencies(query);
|
||||
// just use the constraint provided by the referenced definition
|
||||
this.constraint = constraintDef.getConstraint();
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have to build the constraint from the type
|
||||
try
|
||||
{
|
||||
ConstraintType constraintType = ConstraintType.valueOf(type);
|
||||
constraint = constraintType.newInstance();
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
// try to establish it as a class
|
||||
try
|
||||
{
|
||||
Class clazz = Class.forName(type);
|
||||
constraint = (Constraint) clazz.newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException ee)
|
||||
{
|
||||
throw new DictionaryException(ERR_INVALID_TYPE, type, shortName);
|
||||
}
|
||||
catch (ClassCastException ee)
|
||||
{
|
||||
throw new DictionaryException(ERR_INVALID_TYPE, type, shortName);
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
throw new DictionaryException(ERR_CONSTRUCT_FAILURE, type, shortName);
|
||||
}
|
||||
}
|
||||
// property setters
|
||||
BeanWrapper beanWrapper = new BeanWrapperImpl(constraint);
|
||||
List<M2NamedValue> constraintNamedValues = m2Constraint.getParameters();
|
||||
for (M2NamedValue namedValue : constraintNamedValues)
|
||||
{
|
||||
beanWrapper.setPropertyValue(namedValue.getName(), namedValue.getValue());
|
||||
}
|
||||
// now initialize
|
||||
constraint.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getName()
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getName().toString();
|
||||
}
|
||||
|
||||
public ModelDefinition getModel()
|
||||
{
|
||||
return model;
|
||||
}
|
||||
|
||||
public QName getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public Constraint getConstraint()
|
||||
{
|
||||
return constraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Well-known constraint types
|
||||
*/
|
||||
public static enum ConstraintType
|
||||
{
|
||||
REGEX
|
||||
{
|
||||
@Override
|
||||
protected Constraint newInstance()
|
||||
{
|
||||
return new RegexConstraint();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return Returns the constraint implementation
|
||||
*/
|
||||
protected abstract Constraint newInstance();
|
||||
}
|
||||
}
|
@@ -50,7 +50,7 @@ public class M2Model
|
||||
private List<M2DataType> dataTypes = new ArrayList<M2DataType>();
|
||||
private List<M2Type> types = new ArrayList<M2Type>();
|
||||
private List<M2Aspect> aspects = new ArrayList<M2Aspect>();
|
||||
|
||||
private List<M2Constraint> constraints = new ArrayList<M2Constraint>();
|
||||
|
||||
private M2Model()
|
||||
{
|
||||
@@ -379,8 +379,13 @@ public class M2Model
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public List<M2Constraint> getConstraints()
|
||||
{
|
||||
return Collections.unmodifiableList(constraints);
|
||||
}
|
||||
|
||||
// Do not delete: referenced by m2binding.xml
|
||||
@SuppressWarnings("unused")
|
||||
private static List createList()
|
||||
{
|
||||
return new ArrayList();
|
||||
|
53
source/java/org/alfresco/repo/dictionary/M2NamedValue.java
Normal file
53
source/java/org/alfresco/repo/dictionary/M2NamedValue.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
/**
|
||||
* Definition of a named value that can be used for property injection.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class M2NamedValue
|
||||
{
|
||||
private String name;
|
||||
private String value;
|
||||
|
||||
|
||||
/*package*/ M2NamedValue()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return (name + "=" + value);
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the raw, unconverted value
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
@@ -16,6 +16,9 @@
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Property Definition
|
||||
@@ -37,7 +40,7 @@ public class M2Property
|
||||
private boolean isIndexedAtomically = true;
|
||||
private boolean isStoredInIndex = false;
|
||||
private boolean isTokenisedInIndex = true;
|
||||
|
||||
private List<M2Constraint> constraints;
|
||||
|
||||
/*package*/ M2Property()
|
||||
{
|
||||
@@ -192,5 +195,17 @@ public class M2Property
|
||||
{
|
||||
this.isTokenisedInIndex = isTokenisedInIndex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<M2Constraint> getConstraints()
|
||||
{
|
||||
if (constraints == null)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return constraints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,11 +16,18 @@
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.namespace.NamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
@@ -33,49 +40,85 @@ import org.alfresco.service.namespace.QName;
|
||||
/*package*/ class M2PropertyDefinition implements PropertyDefinition
|
||||
{
|
||||
private ClassDefinition classDef;
|
||||
private M2Property property;
|
||||
private M2Property m2Property;
|
||||
private QName name;
|
||||
private QName propertyTypeName;
|
||||
private DataTypeDefinition dataType;
|
||||
private List<ConstraintDefinition> constraints = new ArrayList<ConstraintDefinition>(5);
|
||||
private Map<QName, ConstraintDefinition> constraintsByQName = new HashMap<QName, ConstraintDefinition>(7);
|
||||
|
||||
|
||||
/*package*/ M2PropertyDefinition(ClassDefinition classDef, M2Property m2Property, NamespacePrefixResolver resolver)
|
||||
/*package*/ M2PropertyDefinition(
|
||||
ClassDefinition classDef,
|
||||
M2Property m2Property,
|
||||
NamespacePrefixResolver prefixResolver)
|
||||
{
|
||||
this.classDef = classDef;
|
||||
this.property = m2Property;
|
||||
this.m2Property = m2Property;
|
||||
|
||||
// Resolve Names
|
||||
this.name = QName.createQName(property.getName(), resolver);
|
||||
this.propertyTypeName = QName.createQName(property.getType(), resolver);
|
||||
this.name = QName.createQName(m2Property.getName(), prefixResolver);
|
||||
this.propertyTypeName = QName.createQName(m2Property.getType(), prefixResolver);
|
||||
}
|
||||
|
||||
|
||||
/*package*/ M2PropertyDefinition(ClassDefinition classDef, PropertyDefinition propertyDef, M2PropertyOverride override)
|
||||
/*package*/ M2PropertyDefinition(
|
||||
ClassDefinition classDef,
|
||||
PropertyDefinition propertyDef,
|
||||
M2PropertyOverride override)
|
||||
{
|
||||
this.classDef = classDef;
|
||||
this.property = createOverriddenProperty(propertyDef, override);
|
||||
this.m2Property = createOverriddenProperty(propertyDef, override);
|
||||
this.name = propertyDef.getName();
|
||||
this.dataType = propertyDef.getDataType();
|
||||
this.propertyTypeName = this.dataType.getName();
|
||||
}
|
||||
|
||||
|
||||
/*package*/ void resolveDependencies(ModelQuery query)
|
||||
/*package*/ void resolveDependencies(
|
||||
ModelQuery query,
|
||||
NamespacePrefixResolver prefixResolver,
|
||||
Map<QName, ConstraintDefinition> modelConstraints)
|
||||
{
|
||||
if (propertyTypeName == null)
|
||||
{
|
||||
throw new DictionaryException("Property type of property " + name.toPrefixString() + " must be specified");
|
||||
throw new DictionaryException(
|
||||
"d_dictionary.property.err.property_type_not_specified",
|
||||
name.toPrefixString());
|
||||
}
|
||||
dataType = query.getDataType(propertyTypeName);
|
||||
if (dataType == null)
|
||||
{
|
||||
throw new DictionaryException("Property type " + propertyTypeName.toPrefixString() + " of property " + name.toPrefixString() + " is not found");
|
||||
throw new DictionaryException(
|
||||
"d_dictionary.property.err.property_type_not_found",
|
||||
propertyTypeName.toPrefixString(), name.toPrefixString());
|
||||
}
|
||||
|
||||
// ensure content properties are not multi-valued
|
||||
if (propertyTypeName.equals(DataTypeDefinition.CONTENT) && isMultiValued())
|
||||
{
|
||||
throw new DictionaryException("Content properties must be single-valued");
|
||||
throw new DictionaryException("d_dictionary.property.err.single_valued_content");
|
||||
}
|
||||
|
||||
// Construct constraints
|
||||
for (M2Constraint constraint : m2Property.getConstraints())
|
||||
{
|
||||
ConstraintDefinition def = new M2ConstraintDefinition(this, constraint, prefixResolver);
|
||||
QName qname = def.getName();
|
||||
if (constraintsByQName.containsKey(qname))
|
||||
{
|
||||
throw new DictionaryException(
|
||||
"d_dictionary.property.err.duplicate_constraint_on_property",
|
||||
def.getName().toPrefixString(), name.toPrefixString());
|
||||
}
|
||||
else if (modelConstraints.containsKey(qname))
|
||||
{
|
||||
throw new DictionaryException(
|
||||
"d_dictionary.model.err.duplicate_constraint_on_model",
|
||||
def.getName().toPrefixString());
|
||||
}
|
||||
constraintsByQName.put(qname, def);
|
||||
constraints.add(def);
|
||||
modelConstraints.put(qname, def);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +196,7 @@ import org.alfresco.service.namespace.QName;
|
||||
String value = M2Label.getLabel(classDef.getModel(), "property", name, "title");
|
||||
if (value == null)
|
||||
{
|
||||
value = property.getTitle();
|
||||
value = m2Property.getTitle();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -167,7 +210,7 @@ import org.alfresco.service.namespace.QName;
|
||||
String value = M2Label.getLabel(classDef.getModel(), "property", name, "description");
|
||||
if (value == null)
|
||||
{
|
||||
value = property.getDescription();
|
||||
value = m2Property.getDescription();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -178,7 +221,7 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public String getDefaultValue()
|
||||
{
|
||||
return property.getDefaultValue();
|
||||
return m2Property.getDefaultValue();
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +248,7 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public boolean isMultiValued()
|
||||
{
|
||||
return property.isMultiValued();
|
||||
return m2Property.isMultiValued();
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +257,7 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public boolean isMandatory()
|
||||
{
|
||||
return property.isMandatory();
|
||||
return m2Property.isMandatory();
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +266,7 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public boolean isProtected()
|
||||
{
|
||||
return property.isProtected();
|
||||
return m2Property.isProtected();
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +275,7 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public boolean isIndexed()
|
||||
{
|
||||
return property.isIndexed();
|
||||
return m2Property.isIndexed();
|
||||
}
|
||||
|
||||
|
||||
@@ -241,7 +284,7 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public boolean isStoredInIndex()
|
||||
{
|
||||
return property.isStoredInIndex();
|
||||
return m2Property.isStoredInIndex();
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +293,7 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public boolean isIndexedAtomically()
|
||||
{
|
||||
return property.isIndexedAtomically();
|
||||
return m2Property.isIndexedAtomically();
|
||||
}
|
||||
|
||||
|
||||
@@ -259,7 +302,11 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public boolean isTokenisedInIndex()
|
||||
{
|
||||
return property.isTokenisedInIndex();
|
||||
return m2Property.isTokenisedInIndex();
|
||||
}
|
||||
|
||||
public List<ConstraintDefinition> getConstraints()
|
||||
{
|
||||
return Collections.unmodifiableList(constraints);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
@@ -81,6 +82,14 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public PropertyDefinition getProperty(QName name);
|
||||
|
||||
/**
|
||||
* Gets the specified property constraint
|
||||
*
|
||||
* @param name the qualified name of the property constraint
|
||||
* @return
|
||||
*/
|
||||
public ConstraintDefinition getConstraint(QName name);
|
||||
|
||||
/**
|
||||
* Gets the specified association
|
||||
*
|
||||
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.dictionary.constraint;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.Constraint;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
|
||||
/**
|
||||
* Base services for constraints.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public abstract class AbstractConstraint implements Constraint
|
||||
{
|
||||
public static final String ERR_PROP_NOT_SET = "d_dictionary.model.err.property_not_set";
|
||||
public static final String ERR_EVALUATE_EXCEPTION = "d_dictionary.model.err.evaluate_exception";
|
||||
|
||||
/**
|
||||
* @see #evaluateSingleValue(Object)
|
||||
* @see #evaluateCollection(Collection)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final void evaluate(Object value)
|
||||
{
|
||||
try
|
||||
{
|
||||
// check for collection
|
||||
if (value instanceof Collection)
|
||||
{
|
||||
Collection collection = (Collection) value;
|
||||
evaluateCollection(collection);
|
||||
}
|
||||
else
|
||||
{
|
||||
evaluateSingleValue(value);
|
||||
}
|
||||
}
|
||||
catch (DictionaryException e)
|
||||
{
|
||||
// this can go
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new DictionaryException(AbstractConstraint.ERR_EVALUATE_EXCEPTION, this, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only override if there is some specific evaluation that needs to be performed on the
|
||||
* collection as a whole.
|
||||
*
|
||||
* @param collection the collection of values to evaluate
|
||||
*
|
||||
* @see #evaluateSingleValue(Object)
|
||||
*/
|
||||
protected void evaluateCollection(Collection<Object> collection)
|
||||
{
|
||||
for (Object value : collection)
|
||||
{
|
||||
evaluateSingleValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for evaluation of properties. The value passed in will never be a
|
||||
* collection.
|
||||
*
|
||||
* @throws DictionaryException throw this when the evaluation fails
|
||||
*/
|
||||
protected abstract void evaluateSingleValue(Object value);
|
||||
}
|
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.dictionary.constraint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAOTest;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.dictionary.Constraint
|
||||
* @see org.alfresco.repo.dictionary.constraint.AbstractConstraint
|
||||
* @see org.alfresco.repo.dictionary.constraint.RegexConstraint
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class ConstraintsTest extends TestCase
|
||||
{
|
||||
@Override
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
// register resource bundles for messages
|
||||
I18NUtil.registerResourceBundle(DictionaryDAOTest.TEST_RESOURCE_MESSAGES);
|
||||
}
|
||||
|
||||
/**
|
||||
* ensure that the default handling of checks on collections will work
|
||||
*/
|
||||
public void testCollections() throws Exception
|
||||
{
|
||||
DummyConstraint constraint = new DummyConstraint();
|
||||
constraint.initialize();
|
||||
|
||||
List<Object> dummyObjects = new ArrayList<Object>(3);
|
||||
dummyObjects.add("ABC"); // correct
|
||||
dummyObjects.add("DEF"); // correct
|
||||
dummyObjects.add(this); // NO
|
||||
try
|
||||
{
|
||||
constraint.evaluate(dummyObjects);
|
||||
fail("Failed to detected constraint violation in collection");
|
||||
}
|
||||
catch (DictionaryException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
// check that the two strings were properly dealt with
|
||||
assertEquals("String values not checked", 2, constraint.tested.size());
|
||||
}
|
||||
|
||||
public void testRegexConstraint() throws Exception
|
||||
{
|
||||
RegexConstraint constraint = new RegexConstraint();
|
||||
constraint.setExpression("[A-Z]*");
|
||||
constraint.initialize();
|
||||
|
||||
// do some successful stuff
|
||||
constraint.evaluate("ABC");
|
||||
constraint.evaluate("DEF");
|
||||
|
||||
// now some failures
|
||||
try
|
||||
{
|
||||
constraint.evaluate("abc");
|
||||
fail("Regular expression evaluation should have failed: abc");
|
||||
}
|
||||
catch (DictionaryException e)
|
||||
{
|
||||
String msg = e.getMessage();
|
||||
assertFalse("I18N of constraint message failed", msg.startsWith("d_dictionary.constraint"));
|
||||
}
|
||||
|
||||
// now a case of passing in an object that could be a string
|
||||
constraint.evaluate(DummyEnum.ABC);
|
||||
constraint.evaluate(DummyEnum.DEF);
|
||||
try
|
||||
{
|
||||
constraint.evaluate(DummyEnum.abc);
|
||||
fail("Regular expression evaluation should have failed for enum: " + DummyEnum.abc);
|
||||
}
|
||||
catch (DictionaryException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private enum DummyEnum
|
||||
{
|
||||
ABC,
|
||||
DEF,
|
||||
abc;
|
||||
}
|
||||
|
||||
private class DummyConstraint extends AbstractConstraint
|
||||
{
|
||||
private List<Object> tested;
|
||||
|
||||
public void initialize()
|
||||
{
|
||||
tested = new ArrayList<Object>(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fails on everything but String values, which pass.
|
||||
* Null values cause runtime exceptions and all other failures are by
|
||||
* DictionaryException.
|
||||
*/
|
||||
@Override
|
||||
protected void evaluateSingleValue(Object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new NullPointerException("Null value in dummy test");
|
||||
}
|
||||
else if (value instanceof String)
|
||||
{
|
||||
tested.add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DictionaryException("Non-String value");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.dictionary.constraint;
|
||||
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
|
||||
/**
|
||||
* Constraint implementation that performs regular expression comparisons.
|
||||
* Where possible, the {@link org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter type converter}
|
||||
* will be used to first convert the value to a <code>String</code>, so the evaluation
|
||||
* will be against the value's <code>String</code> equivalent.
|
||||
*
|
||||
* @see java.lang.String#matches(java.lang.String)
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class RegexConstraint extends AbstractConstraint
|
||||
{
|
||||
public static final String CONSTRAINT_REGEX_NO_MATCH = "d_dictionary.constraint.regex.no_match";
|
||||
|
||||
private String expression;
|
||||
|
||||
/**
|
||||
* Set the regular expression used to evaluate string values
|
||||
* @param expression similar to the {@link String#matches(java.lang.String) argument
|
||||
*/
|
||||
public void setExpression(String expression)
|
||||
{
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public void initialize()
|
||||
{
|
||||
if (expression == null)
|
||||
{
|
||||
throw new DictionaryException(AbstractConstraint.ERR_PROP_NOT_SET, "expression");
|
||||
}
|
||||
}
|
||||
|
||||
public void evaluateSingleValue(Object value)
|
||||
{
|
||||
// convert the value to a String
|
||||
String valueStr = DefaultTypeConverter.INSTANCE.convert(String.class, value);
|
||||
boolean matches = valueStr.matches(expression);
|
||||
if (!matches)
|
||||
{
|
||||
throw new DictionaryException(RegexConstraint.CONSTRAINT_REGEX_NO_MATCH, value, expression);
|
||||
}
|
||||
}
|
||||
}
|
@@ -21,6 +21,12 @@
|
||||
</data-type>
|
||||
|
||||
</data-types>
|
||||
|
||||
<constraints>
|
||||
<constraint name="test:regex1" type="REGEX">
|
||||
<parameter name="expression">[A-Z]*</parameter>
|
||||
</constraint>
|
||||
</constraints>
|
||||
|
||||
<types>
|
||||
|
||||
@@ -34,6 +40,9 @@
|
||||
<type>d:text</type>
|
||||
<protected>true</protected>
|
||||
<default></default>
|
||||
<constraints>
|
||||
<constraint ref="test:regex1"/>
|
||||
</constraints>
|
||||
</property>
|
||||
</properties>
|
||||
|
||||
|
@@ -41,6 +41,10 @@
|
||||
</collection>
|
||||
</structure>
|
||||
|
||||
<structure name="constraints" usage="optional">
|
||||
<collection field="constraints" item-type="org.alfresco.repo.dictionary.M2Constraint" factory="org.alfresco.repo.dictionary.M2Model.createList"/>
|
||||
</structure>
|
||||
|
||||
<structure name="types" usage="optional">
|
||||
<collection field="types" item-type="org.alfresco.repo.dictionary.M2Type" factory="org.alfresco.repo.dictionary.M2Model.createList"/>
|
||||
</structure>
|
||||
@@ -102,6 +106,24 @@
|
||||
<value name="stored" field="isStoredInIndex" usage="optional"/>
|
||||
<value name="tokenised" field="isTokenisedInIndex" usage="optional"/>
|
||||
</structure>
|
||||
<structure name="constraints" usage="optional">
|
||||
<collection field="constraints" item-type="org.alfresco.repo.dictionary.M2Constraint" factory="org.alfresco.repo.dictionary.M2Model.createList"/>
|
||||
</structure>
|
||||
</mapping>
|
||||
|
||||
<mapping abstract="true" class="org.alfresco.repo.dictionary.M2NamedValue">
|
||||
<value style="attribute" name="name" field="name" />
|
||||
<value style="text" field="value"/>
|
||||
</mapping>
|
||||
|
||||
<mapping name="constraint" class="org.alfresco.repo.dictionary.M2Constraint">
|
||||
<value style="attribute" name="name" field="name" usage="optional"/>
|
||||
<value style="attribute" name="type" field="type" usage="optional"/>
|
||||
<value style="attribute" name="ref" field="ref" usage="optional"/>
|
||||
<value name="description" field="description" usage="optional"/>
|
||||
<collection field="parameters" factory="org.alfresco.repo.dictionary.M2Model.createList" usage="optional">
|
||||
<structure name="parameter" type="org.alfresco.repo.dictionary.M2NamedValue" />
|
||||
</collection>
|
||||
</mapping>
|
||||
|
||||
<mapping class="org.alfresco.repo.dictionary.M2ClassAssociation" abstract="true">
|
||||
|
Reference in New Issue
Block a user