/* * 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.Collections; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.ecore.EObject; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.ValidationPreferences; import org.teiid.designer.core.util.ModelVisitorProcessor; import org.teiid.designer.core.validation.ObjectValidationRule; 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; import org.teiid.designer.metamodels.core.ModelAnnotation; import org.teiid.designer.metamodels.core.ModelType; import org.teiid.designer.metamodels.relational.AccessPattern; 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.RelationalEntity; import org.teiid.designer.metamodels.relational.RelationalPlugin; import org.teiid.designer.metamodels.relational.Table; import org.teiid.designer.metamodels.relational.UniqueKey; import org.teiid.designer.metamodels.relational.util.RelationalUtil; /** * SiblingNameInSourceRule * * @since 8.0 */ public class SiblingNameInSourceRule implements ObjectValidationRule { private static final String nameInSourceFeatureName = RelationalPlugin.Util.getString("_UI_RelationalEntity_nameInSource_feature"); //$NON-NLS-1$ private static final String RULE_NAME = SiblingNameInSourceRule.class.getName(); /* * @See org.teiid.designer.core.validation.ObjectValidationRule#validate(org.eclipse.emf.ecore.EObject, org.teiid.designer.core.validation.ValidationContext) */ @Override public void validate(final EObject eObject, final ValidationContext context) { // nothing to validate if there are no siblings if(!shouldRun(eObject, context)) { return; } // get siblings to validate List siblings = getSiblingsForUniquenessCheck(eObject); if(siblings.isEmpty()) { return; } final int statusForCaseSensitive = getPreferenceStatus(context); final int statusForCaseInsensitive = statusForCaseSensitive == IStatus.ERROR ? IStatus.WARNING : statusForCaseSensitive; ValidationResults validationResults = new ValidationResults(siblings.size()); for(int i=0; i < siblings.size(); i++) { EObject siblingI = (EObject)siblings.get(i); String nameInSourceA = getNameInSource(siblingI); final ValidationResult result = validationResults.get(i,siblingI); if(!CoreStringUtil.isEmpty(nameInSourceA)) { for(int j=i+1; j < siblings.size(); j++) { EObject siblingJ = (EObject)siblings.get(j); String nameInSourceB = getNameInSource(siblings.get(j)); if(!CoreStringUtil.isEmpty(nameInSourceB)) { if(nameInSourceA.equals(nameInSourceB)) { // create validation problem and add it to the result final Object[] params = new Object[]{getName(siblingI),getName(siblingJ),nameInSourceFeatureName}; final String msg = RelationalPlugin.Util.getString("SiblingNameInSourceRule.failure_message_case_sensitive",params); //$NON-NLS-1$ ValidationProblem problem = new ValidationProblemImpl(0, statusForCaseSensitive,msg); problem.setHasPreference(context.hasPreferences()); result.addProblem(problem); // creating additinal validation results on other sibling // note this would create markers with duplicate messages but targets // will be differrent final ValidationResult resultJ = validationResults.get(j,siblingJ); ValidationProblem problemJ = new ValidationProblemImpl(0, statusForCaseSensitive,msg); problemJ.setHasPreference(context.hasPreferences()); resultJ.addProblem(problemJ); } else if(nameInSourceA.equalsIgnoreCase(nameInSourceB)) { // create validation problem and add it to the result final Object[] params = new Object[]{getName(siblingI),getName(siblingJ),nameInSourceFeatureName}; final String msg = RelationalPlugin.Util.getString("SiblingNameInSourceRule.failure_message_case_insensitive",params); //$NON-NLS-1$ ValidationProblem problem = new ValidationProblemImpl(0, statusForCaseInsensitive ,msg); problem.setHasPreference(context.hasPreferences()); result.addProblem(problem); // creating additinal validation results on other sibling // note this would create markers with duplicate messages but targets // will be differrent final ValidationResult resultJ = validationResults.get(j,siblingJ); ValidationProblem problemJ = new ValidationProblemImpl(0, statusForCaseInsensitive,msg); problemJ.setHasPreference(context.hasPreferences()); resultJ.addProblem(problemJ); } } } } // add the result to the context context.addResult(result); } } //############################################################################################################################ //# P R O T E C T E D M E T H O D S # //############################################################################################################################ protected class ValidationResults { private final ValidationResult[] results; public ValidationResults(final int size) { this.results = new ValidationResult[size]; } public ValidationResult get(final int index, final EObject object ) { ValidationResult result = this.results[index]; if ( result == null ) { result = new ValidationResultImpl(object); this.results[index] = result; } return result; } } protected int getPreferenceStatus(final ValidationContext context) { return context.getPreferenceStatus(ValidationPreferences.RELATIONAL_SIBLING_NAME_IN_SOURCE, IStatus.OK); } /** * 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 Catalog} and {@link Schema} instances</li> * <li>{@link BaseTable} and {@link View} instances</li> * <li>{@link Procedure} instances</li> * <li>{@link ProcedureColumn} instances</li> * <li>{@link AccessPattern} instances</li> * <li>{@link UniqueKey}, {@link ForeignKey} and {@link Index} instances</li> * <li></li> * <li></li> * </ul> * @see org.teiid.designer.core.validation.rules.StringNameRule#getSiblingsForUniquenessCheck(org.eclipse.emf.ecore.EObject) */ protected 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 Column ) { return RelationalUtil.findColumns(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 AccessPattern ) { if ( parent instanceof Table ) { return ((Table)parent).getAccessPatterns(); } } else if ( eObject instanceof LogicalRelationship ) { return RelationalUtil.findLogicalRelationships(parent, ModelVisitorProcessor.DEPTH_ONE); } return Collections.EMPTY_LIST; } //############################################################################################################################ //# P R I V A T E M E T H O D S # //############################################################################################################################ private String getNameInSource(final Object sibling) { if(sibling instanceof RelationalEntity) { RelationalEntity entity = (RelationalEntity) sibling; return entity.getNameInSource(); } return null; } private String getName(final Object sibling) { if(sibling instanceof RelationalEntity) { RelationalEntity entity = (RelationalEntity) sibling; return entity.getName(); } return ModelerCore.getModelEditor().getModelRelativePathIncludingModel((EObject) sibling).toString(); } private boolean shouldRun(final EObject eObject, final ValidationContext context) { if(getPreferenceStatus(context) == IStatus.OK) { return false; } // run the rule only for physical models try { ModelAnnotation modelAnnotation = ModelerCore.getModelEditor().getModelAnnotation(eObject); int modelType = modelAnnotation.getModelType().getValue(); if(modelType != ModelType.PHYSICAL) { return false; } } catch(Exception e) { RelationalPlugin.Util.log(IStatus.ERROR, e, e.getMessage()); } // 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, RULE_NAME+objType)) { return false; } context.recordRuleRun(eObject, RULE_NAME+objType); return true; } }