/* * 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 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(); } }