/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco * * Alfresco is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Alfresco is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ package org.alfresco.repo.dictionary; import java.util.ArrayList; import java.util.Collection; 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.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.QName; import org.alfresco.util.EqualsHelper; /** * Compiled Property Definition * * @author David Caruana */ /*package*/ class M2PropertyDefinition implements PropertyDefinition { private ClassDefinition classDef; private M2Property m2Property; private QName name; private QName propertyTypeName; private DataTypeDefinition dataType; private List constraintDefs = Collections.emptyList(); /*package*/ M2PropertyDefinition( ClassDefinition classDef, M2Property m2Property, NamespacePrefixResolver prefixResolver) { this.classDef = classDef; this.m2Property = m2Property; // Resolve Names this.name = QName.createQName(m2Property.getName(), prefixResolver); this.propertyTypeName = QName.createQName(m2Property.getType(), prefixResolver); } /*package*/ M2PropertyDefinition( ClassDefinition classDef, PropertyDefinition propertyDef, M2PropertyOverride override, NamespacePrefixResolver prefixResolver, Map modelConstraints) { this.classDef = classDef; this.m2Property = createOverriddenProperty(propertyDef, override, prefixResolver, modelConstraints); this.name = propertyDef.getName(); this.dataType = propertyDef.getDataType(); this.propertyTypeName = this.dataType.getName(); } /*package*/ void resolveDependencies( ModelQuery query, NamespacePrefixResolver prefixResolver, Map modelConstraints) { if (propertyTypeName == null) { throw new DictionaryException( "d_dictionary.property.err.property_type_not_specified", name.toPrefixString()); } dataType = query.getDataType(propertyTypeName); if (dataType == null) { 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("d_dictionary.property.err.single_valued_content"); } // Construct constraints constraintDefs = buildConstraints( m2Property.getConstraints(), this, prefixResolver, modelConstraints); } private static List buildConstraints( List m2constraints, M2PropertyDefinition m2PropertyDef, NamespacePrefixResolver prefixResolver, Map modelConstraints) { List constraints = new ArrayList(5); Map constraintsByQName = new HashMap(7); for (M2Constraint constraint : m2constraints) { ConstraintDefinition def = new M2ConstraintDefinition(m2PropertyDef, constraint, prefixResolver); QName qname = def.getName(); if (constraintsByQName.containsKey(qname)) { throw new DictionaryException( "d_dictionary.property.err.duplicate_constraint_on_property", def.getName().toPrefixString(), m2PropertyDef.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); } // done return constraints; } /** * Create a property definition whose values are overridden * * @param propertyDef the property definition to override * @param override the overridden values * @return the property definition */ private M2Property createOverriddenProperty( PropertyDefinition propertyDef, M2PropertyOverride override, NamespacePrefixResolver prefixResolver, Map modelConstraints) { M2Property property = new M2Property(); property.setOverride(true); // Process Default Value String defaultValue = override.getDefaultValue(); property.setDefaultValue(defaultValue == null ? propertyDef.getDefaultValue() : defaultValue); // Process Mandatory Value Boolean isOverrideMandatory = override.isMandatory(); boolean isOverrideMandatoryEnforced = override.isMandatoryEnforced(); if (isOverrideMandatory != null && propertyDef.isMandatory()) { // the override specified whether the property should be mandatory or not // check that the mandatory enforcement is not relaxed if (!isOverrideMandatory) { throw new DictionaryException( "d_dictionary.property.err.cannot_relax_mandatory", propertyDef.getName().toPrefixString()); } else if (!isOverrideMandatoryEnforced && propertyDef.isMandatoryEnforced()) { throw new DictionaryException( "d_dictionary.property.err.cannot_relax_mandatory_enforcement", propertyDef.getName().toPrefixString()); } } property.setMandatory(isOverrideMandatory == null ? propertyDef.isMandatory() : isOverrideMandatory); property.setMandatoryEnforced(isOverrideMandatoryEnforced); // inherit or override constraints List 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 property.setDescription(propertyDef.getDescription()); property.setIndexed(propertyDef.isIndexed()); property.setIndexedAtomically(propertyDef.isIndexedAtomically()); property.setMultiValued(propertyDef.isMultiValued()); property.setProtected(propertyDef.isProtected()); property.setStoredInIndex(propertyDef.isStoredInIndex()); property.setTitle(propertyDef.getTitle()); property.setIndexTokenisationMode(propertyDef.getIndexTokenisationMode()); return property; } /** * @see #getName() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("Name: " + getName() + "\n"); sb.append("Title: " + getTitle() + "\n"); sb.append("Description: " + getDescription() + "\n"); sb.append("Default Value: " + getDefaultValue() + "\n"); sb.append("DataType Name: " + getDataType().getName() + "\n"); sb.append("ContainerClass Name: " + getContainerClass().getName() + "\n"); sb.append("isMultiValued: " + isMultiValued() + "\n"); sb.append("isMandatory: " + isMandatory() + "\n"); sb.append("isMandatoryEnforced: " + isMandatoryEnforced() + "\n"); sb.append("isProtected: " + isProtected() + "\n"); sb.append("isIndexed: " + isIndexed() + "\n"); sb.append("isStoredInIndex: " + isStoredInIndex() + "\n"); sb.append("isIndexedAtomically: " + isIndexedAtomically() + "\n"); sb.append("indexTokenisationMode: " + getIndexTokenisationMode() + "\n"); return sb.toString(); } /* (non-Javadoc) * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getModel() */ public ModelDefinition getModel() { return classDef.getModel(); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#getName() */ public QName getName() { return name; } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#getTitle() */ public String getTitle() { String value = M2Label.getLabel(classDef.getModel(), "property", name, "title"); if (value == null) { value = m2Property.getTitle(); } return value; } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#getDescription() */ public String getDescription() { String value = M2Label.getLabel(classDef.getModel(), "property", name, "description"); if (value == null) { value = m2Property.getDescription(); } return value; } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#getDefaultValue() */ public String getDefaultValue() { return m2Property.getDefaultValue(); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#getPropertyType() */ public DataTypeDefinition getDataType() { return dataType; } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#getContainerClass() */ public ClassDefinition getContainerClass() { return classDef; } /* * (non-Javadoc) * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isOverride() */ public boolean isOverride() { return m2Property.isOverride(); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#isMultiValued() */ public boolean isMultiValued() { return m2Property.isMultiValued(); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#isMandatory() */ public boolean isMandatory() { return m2Property.isMandatory(); } public boolean isMandatoryEnforced() { return m2Property.isMandatoryEnforced(); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#isProtected() */ public boolean isProtected() { return m2Property.isProtected(); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#isIndexed() */ public boolean isIndexed() { if(m2Property.isIndexed() == null) { return true; } else { return m2Property.isIndexed(); } } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#isStoredInIndex() */ public boolean isStoredInIndex() { if(m2Property.isStoredInIndex() == null) { return false; } else { return m2Property.isStoredInIndex(); } } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#isIndexedAtomically() */ public boolean isIndexedAtomically() { if(m2Property.isIndexedAtomically() == null) { return true; } else { return m2Property.isIndexedAtomically(); } } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.PropertyDefinition#isTokenisedInIndex() */ public IndexTokenisationMode getIndexTokenisationMode() { if(m2Property.getIndexTokenisationMode() == null) { return IndexTokenisationMode.TRUE; } else { return m2Property.getIndexTokenisationMode(); } } /* (non-Javadoc) * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getConstraints() */ public List getConstraints() { return constraintDefs; } /* package */ M2ModelDiff diffProperty(PropertyDefinition propDef) { M2ModelDiff modelDiff = null; boolean isUpdated = false; boolean isUpdatedIncrementally = false; if (this == propDef) { modelDiff = new M2ModelDiff(name, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED); return modelDiff; } // check name - cannot be null if (! name.equals(propDef.getName())) { isUpdated = true; } // check title if (! EqualsHelper.nullSafeEquals(getTitle(), propDef.getTitle(), false)) { isUpdatedIncrementally = true; } // check description if (! EqualsHelper.nullSafeEquals(getDescription(), propDef.getDescription(), false)) { isUpdatedIncrementally = true; } // check default value if (! EqualsHelper.nullSafeEquals(getDefaultValue(), propDef.getDefaultValue(), false)) { isUpdatedIncrementally = true; } // check datatype qname (TODO check datatype defs separately) if (! EqualsHelper.nullSafeEquals(getDataType().getName(), propDef.getDataType().getName())) { isUpdated = true; } // check container class qname if (! EqualsHelper.nullSafeEquals(getContainerClass().getName(), propDef.getContainerClass().getName())) { isUpdated = true; } // check multi-valued if (isMultiValued() != propDef.isMultiValued()) { isUpdated = true; } // check mandatory if (isMandatory() != propDef.isMandatory()) { isUpdated = true; } // check mandatory enforced if (isMandatoryEnforced() != propDef.isMandatoryEnforced()) { isUpdated = true; } // check protected if (isProtected() != propDef.isProtected()) { isUpdated = true; } // // property indexing - is index enabled -> stored, atomic, tokenized (true, false, both) // // // true // false // both // // if (isIndexed() != propDef.isIndexed()) { isUpdatedIncrementally = true; } if (isStoredInIndex() != propDef.isStoredInIndex()) { isUpdatedIncrementally = true; } if (isIndexedAtomically() != propDef.isIndexedAtomically()) { isUpdatedIncrementally = true; } if (! EqualsHelper.nullSafeEquals(getIndexTokenisationMode().toString(), propDef.getIndexTokenisationMode().toString(), false)) { isUpdatedIncrementally = true; } // check override if (isOverride() != propDef.isOverride()) { isUpdated = true; } // TODO - check prop constraints (inline and referenced) if (isUpdated) { modelDiff = new M2ModelDiff(name, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UPDATED); } else if (isUpdatedIncrementally) { modelDiff = new M2ModelDiff(name, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UPDATED_INC); } else { modelDiff = new M2ModelDiff(name, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED); } return modelDiff; } /*package*/ static Collection diffPropertyLists(Collection previousProperties, Collection newProperties) { List modelDiffs = new ArrayList(); for (PropertyDefinition previousProperty : previousProperties) { boolean found = false; for (PropertyDefinition newProperty : newProperties) { if (newProperty.getName().equals(previousProperty.getName())) { modelDiffs.add(((M2PropertyDefinition)previousProperty).diffProperty(newProperty)); found = true; break; } } if (! found) { modelDiffs.add(new M2ModelDiff(previousProperty.getName(), M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_DELETED)); } } for (PropertyDefinition newProperty : newProperties) { boolean found = false; for (PropertyDefinition previousProperty : previousProperties) { if (newProperty.getName().equals(previousProperty.getName())) { found = true; break; } } if (! found) { modelDiffs.add(new M2ModelDiff(newProperty.getName(), M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_CREATED)); } } return modelDiffs; } }