/* * 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.metamodels.relational.aspects.validation.rules; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.teiid.designer.core.ValidationPreferences; import org.teiid.designer.core.util.ModelVisitorProcessor; import org.teiid.designer.core.validation.ValidationContext; import org.teiid.designer.core.validation.ValidationResult; import org.teiid.designer.core.validation.ValidationResultImpl; import org.teiid.designer.core.validation.rules.CoreValidationRulesUtil; import org.teiid.designer.core.validation.rules.StringNameRule; import org.teiid.designer.metamodels.relational.AccessPattern; import org.teiid.designer.metamodels.relational.Catalog; import org.teiid.designer.metamodels.relational.Column; import org.teiid.designer.metamodels.relational.ForeignKey; import org.teiid.designer.metamodels.relational.Index; import org.teiid.designer.metamodels.relational.LogicalRelationship; import org.teiid.designer.metamodels.relational.Procedure; import org.teiid.designer.metamodels.relational.ProcedureParameter; import org.teiid.designer.metamodels.relational.Schema; import org.teiid.designer.metamodels.relational.Table; import org.teiid.designer.metamodels.relational.UniqueKey; import org.teiid.designer.metamodels.relational.aspects.validation.RelationalStringNameValidator; import org.teiid.designer.metamodels.relational.util.RelationalUtil; /** * RelationalStringNameRule * * @since 8.0 */ public class RelationalStringNameRule extends StringNameRule { /** * Construct an instance of RelationalStringNameRule. * * @param featureID the feature id */ public RelationalStringNameRule( int featureID ) { super(featureID); } /** * This method groups siblings into the following domains, and chooses only those siblings that are in the same domain as the * supplied object. * <ul> * <li>{@link Schema} instances</li> * <li>{@link BaseTable} and {@link View} instances</li> * <li>{@link Procedure} instances</li> * <li>{@link Column} instances</li> * <li>{@link AccessPattern} instances</li> * <li>{@link UniqueKey}, {@link ForeignKey} and {@link Index} instances</li> * <li></li> * <li></li> * </ul> * */ @Override public List getSiblingsForUniquenessCheck( final EObject eObject ) { Object parent = eObject.eContainer(); if (parent == null) { parent = eObject.eResource(); } if (eObject instanceof Table) { return RelationalUtil.findTables(parent, ModelVisitorProcessor.DEPTH_ONE); } else if (eObject instanceof Procedure) { return RelationalUtil.findProcedures(parent, ModelVisitorProcessor.DEPTH_ONE); } else if (eObject instanceof ProcedureParameter) { return RelationalUtil.findProcedureParameters(parent, ModelVisitorProcessor.DEPTH_ONE); } else if (eObject instanceof Index) { return RelationalUtil.findIndexes(parent, ModelVisitorProcessor.DEPTH_ONE); } else if (eObject instanceof ForeignKey || eObject instanceof UniqueKey) { return RelationalUtil.findKeys(parent, ModelVisitorProcessor.DEPTH_ONE); } else if (eObject instanceof Column) { return RelationalUtil.findColumns(parent, ModelVisitorProcessor.DEPTH_ONE); } else if (eObject instanceof AccessPattern) { if (parent instanceof Table) { return ((Table)parent).getAccessPatterns(); } return new LinkedList(); } else if (eObject instanceof LogicalRelationship) { return RelationalUtil.findLogicalRelationships(parent, ModelVisitorProcessor.DEPTH_ONE); } else if (eObject instanceof Schema) { return RelationalUtil.findSchemas(parent, ModelVisitorProcessor.DEPTH_ONE); } else if (eObject instanceof Catalog) { return RelationalUtil.findCatalogs(parent, ModelVisitorProcessor.DEPTH_ONE); } return super.getSiblingsForUniquenessCheck(eObject); } /** * This method overrides super method to intercept the StringNameValidator() with a Relational version. This allows * relaxing the valid character set. * * * @see org.teiid.designer.core.validation.rules.StringNameRule#validate(EStructuralFeature, EObject, Object, ValidationContext) */ @Override public void validate( EStructuralFeature eStructuralFeature, EObject eObject, Object value, ValidationContext context ) { // check if the feature matches the given feature if (eStructuralFeature.getFeatureID() != getFeatureID()) { return; } // Check that the value is an instance of java.lang.String // otherwise we cannot apply this rule if (!(value instanceof String)) { return; } final int status = getPreferenceStatus(context); boolean restrictChars = false; if (status != IStatus.OK ) { restrictChars = true; } // validate the name final String name = (String)value; ValidationResult result = new ValidationResultImpl(eObject); if (validateCharacters()) { RelationalStringNameValidator validator = new RelationalStringNameValidator(eObject instanceof Table, restrictChars); CoreValidationRulesUtil.validateStringNameChars(result, name, validator, status); } //CoreValidationRulesUtil.validateForNonQuotedNameWithDelimeter(result, name); // add the result to the context context.addResult(result); // type of object this rule is being run on. String objType = eObject.eClass().getName(); // this rule is being run once per object type per parent if (!context.hasRunRule(eObject, getRuleName() + objType)) { if (validateUniqueness()) { List siblings = getSiblingsForUniquenessCheck(eObject); // For Source Procedures, duplicates are allowed. Remove duplicates from list // so that they will pass this validation rule if (eObject instanceof Procedure) { siblings = removeDuplicateSourceProcs(siblings); } else if (eObject instanceof ProcedureParameter) { siblings = removeDuplicateSourceProcParms(siblings); } // get delegates for proxys for performance // the uniqueness rule should only be run once per container CoreValidationRulesUtil.validateUniqueness(context, siblings, getFeatureID()); // set the rule has been run context.recordRuleRun(eObject, getRuleName() + objType); } } } /* * Remove duplicate named Source Procedures from the supplied list, if duplicates exist. * This allows the normal relational string name rule to pass for source procedures names. * @param siblings the supplied list of source procedures * @return the 'cleaned' list of source procedures */ private List removeDuplicateSourceProcs( List siblings ) { List resultProcs = new ArrayList(); // Result List List<String> sourceProcNames = new ArrayList<String>(); // Track source procedure names already found for (Object proc : siblings) { if (proc != null && proc instanceof Procedure) { Procedure theProc = (Procedure)proc; // If not a source function, add it to the results if (!theProc.isFunction()) { resultProcs.add(theProc); // Source Function - get its name. Only add first source proc with a given name } else { final EStructuralFeature eFeature = theProc.eClass().getEStructuralFeature(getFeatureID()); final String nameUpper = ((String)theProc.eGet(eFeature)).toUpperCase(); if (!sourceProcNames.contains(nameUpper)) { sourceProcNames.add(nameUpper); resultProcs.add(theProc); } } } } return resultProcs; } /* * Remove duplicate named Source Procedure Parameters from the supplied list, if duplicates exist. * This allows the normal relational string name rule to pass for source procedure param names. * @param siblings the supplied list of source procedure parameters * @return the 'cleaned' list of source procedure parameters */ private List removeDuplicateSourceProcParms( List siblings ) { List resultProcParams = new ArrayList(); // Result List List<String> sourceProcParamNames = new ArrayList<String>(); // Track source procedure param names already found for (Object procParam : siblings) { if (procParam != null && procParam instanceof ProcedureParameter) { ProcedureParameter theProcParam = (ProcedureParameter)procParam; // Source Function - get its name. Only add first source proc with a given name final EStructuralFeature eFeature = theProcParam.eClass().getEStructuralFeature(getFeatureID()); final String nameUpper = ((String)theProcParam.eGet(eFeature)).toUpperCase(); if (!sourceProcParamNames.contains(nameUpper)) { sourceProcParamNames.add(nameUpper); resultProcParams.add(theProcParam); } } } return resultProcParams; } protected int getPreferenceStatus(final ValidationContext context) { return context.getPreferenceStatus(ValidationPreferences.RELATIONAL_NAME_CHARACTER_RESTRICTION, IStatus.OK); } }