/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.core.validation.rules; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.ETypedElement; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.validation.StructuralFeatureValidationRule; import org.teiid.designer.core.validation.ValidationContext; import org.teiid.designer.core.validation.ValidationProblem; import org.teiid.designer.core.validation.ValidationProblemImpl; import org.teiid.designer.core.validation.ValidationResult; import org.teiid.designer.core.validation.ValidationResultImpl; /** * MultiplicityRule, this is a core rule that needs to be run for all features, this rule checks the multiplicity of a feature * with the upper and lower bounds of multiplicity allowed for that feature. * * @since 8.0 */ public class MultiplicityRule implements StructuralFeatureValidationRule { private static final String NONE_STRING = ModelerCore.Util.getString("MultiplicityRule.NO_VALUE_STRING"); //$NON-NLS-1$ private static final String ONE_VALUE_STRING = ModelerCore.Util.getString("MultiplicityRule.ONE_VALUE_STRING"); //$NON-NLS-1$ public MultiplicityRule() { } /* (non-Javadoc) * @See org.teiid.designer.core.validation.StructuralFeatureValidationRule#validate(org.eclipse.emf.ecore.EStructuralFeature, org.eclipse.emf.ecore.EObject, java.lang.Object, org.teiid.designer.core.validation.ValidationContext) */ @Override public void validate( EStructuralFeature eStructuralFeature, EObject eObject, Object value, ValidationContext context ) { // get the upper and lower bounds on this feature int lowerBound = eStructuralFeature.getLowerBound(); int upperBound = eStructuralFeature.getUpperBound(); // get the total number og references for this feature int featureReferences = 0; if (value instanceof EList) { EList eList = (EList)value; featureReferences = eList.size(); } else if (value != null) { featureReferences = 1; } // Compare the lower and upper bounds with the actual final boolean lowerViolated = lowerBound != ETypedElement.UNBOUNDED_MULTIPLICITY && featureReferences < lowerBound; final boolean upperViolated = upperBound != ETypedElement.UNBOUNDED_MULTIPLICITY && featureReferences > upperBound; if (lowerViolated || upperViolated) { String msg = null; // Handle the case when lowerBound == upperBound == 1 if (lowerBound == 1 && upperBound == 1) { final String featureName = eStructuralFeature.getName(); msg = ModelerCore.Util.getString("MultiplicityRule.Missing_value", featureName); //$NON-NLS-1$ } else { // Get the parameter names for the message ... final String featureName = eStructuralFeature.getName(); final String className = ModelerCore.getMetamodelRegistry().getMetaClassLabel(eObject.eClass()); String oppositeName = null; boolean containment = false; if (eStructuralFeature instanceof EReference) { final EReference eRef = (EReference)eStructuralFeature; // this reference final EReference oppositeRef = eRef.getEOpposite(); // opposite reference if (oppositeRef != null) { oppositeName = oppositeRef.getContainerClass().getName(); containment = oppositeRef.isContainment(); } } String actual = NONE_STRING; if (featureReferences == 0) { actual = NONE_STRING; } else if (featureReferences == 1) { actual = ONE_VALUE_STRING; } else { actual = ModelerCore.Util.getString("MultiplicityRule.MULTI_VALUE_STRING", featureReferences); //$NON-NLS-1$ } // Figure out which message to use ... if (lowerViolated) { if (oppositeName != null) { if (containment) { if (upperBound == ETypedElement.UNBOUNDED_MULTIPLICITY) { final Object[] params = new Object[] {className, new Integer(lowerBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.The_METACLASSNAME_must_contain_LOWERBOUND_or_more_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } else { final Object[] params = new Object[] {className, new Integer(lowerBound), new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.The_METACLASSNAME_must_contain_between_LOWERBOUND_and_UPPERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } } else {// No containment ... if (upperBound == ETypedElement.UNBOUNDED_MULTIPLICITY) { final Object[] params = new Object[] {className, new Integer(lowerBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.The_METACLASSNAME_must_reference_LOWERBOUND_or_more_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } else { final Object[] params = new Object[] {className, new Integer(lowerBound), new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.The_METACLASSNAME_must_reference_between_LOWERBOUND_and_UPPERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } } } else { // There is no opposite (and thus no containment) ... if (upperBound == ETypedElement.UNBOUNDED_MULTIPLICITY) { final Object[] params = new Object[] {new Integer(lowerBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.There_must_be_LOWERBOUND_or_more_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } else { final Object[] params = new Object[] {new Integer(lowerBound), new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.There_must_be_between_LOWERBOUND_and_UPPERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } } } else if (upperViolated) { if (oppositeName != null) { if (containment) { if (lowerBound == 0) { final Object[] params = new Object[] {className, new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.The_METACLASSNAME_must_contain_no_more_than_UPPERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } else { final Object[] params = new Object[] {className, new Integer(lowerBound), new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.The_METACLASSNAME_must_contain_between_LOWERBOUND_and_UPPERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } } else {// No containment ... if (lowerBound == 0) { final Object[] params = new Object[] {className, new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.The_METACLASSNAME_must_reference_no_more_than_UPPERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } else { final Object[] params = new Object[] {className, new Integer(lowerBound), new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.The_METACLASSNAME_must_reference_between_LOWERBOUND_and_UPPERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } } } else { // There is no opposite (and thus no containment) ... if (lowerBound == 0) { final Object[] params = new Object[] {new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.There_must_be_less_than_LOWERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } else { final Object[] params = new Object[] {new Integer(lowerBound), new Integer(upperBound), featureName, actual}; msg = ModelerCore.Util.getString("MultiplicityRule.There_must_be_between_LOWERBOUND_and_UPPERBOUND_FEATURENAME_when_there_are_ACTUAL", params); //$NON-NLS-1$ } } } } CoreArgCheck.isNotNull(msg); // create validation problem and addit to the resuls ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR, msg); ValidationResult result = new ValidationResultImpl(eObject); result.addProblem(problem); context.addResult(result); } } }