/*
* 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.transformation.aspects.validation.rules;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
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.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.mapping.Mapping;
import org.eclipse.emf.mapping.MappingRoot;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.ValidationPreferences;
import org.teiid.designer.core.container.Container;
import org.teiid.designer.core.metamodel.aspect.AspectManager;
import org.teiid.designer.core.metamodel.aspect.sql.SqlAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlProcedureAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlTableAspect;
import org.teiid.designer.core.resource.EmfResource;
import org.teiid.designer.core.types.DatatypeConstants;
import org.teiid.designer.core.types.DatatypeManager;
import org.teiid.designer.core.util.ModelContents;
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.metadata.runtime.MetadataRecord;
import org.teiid.designer.metadata.runtime.TableRecord;
import org.teiid.designer.metamodels.core.ModelAnnotation;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.function.ScalarFunction;
import org.teiid.designer.metamodels.relational.BaseTable;
import org.teiid.designer.metamodels.relational.Column;
import org.teiid.designer.metamodels.relational.Procedure;
import org.teiid.designer.metamodels.relational.ProcedureParameter;
import org.teiid.designer.metamodels.relational.ProcedureResult;
import org.teiid.designer.metamodels.relational.RelationalPlugin;
import org.teiid.designer.metamodels.relational.Table;
import org.teiid.designer.metamodels.relational.util.RelationalUtil;
import org.teiid.designer.metamodels.transformation.SqlTransformation;
import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.TransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.TreeMappingRoot;
import org.teiid.designer.metamodels.transformation.impl.MappingClassImpl;
import org.teiid.designer.metamodels.transformation.impl.MappingClassSetImpl;
import org.teiid.designer.metamodels.webservice.Operation;
import org.teiid.designer.metamodels.xml.XmlDocument;
import org.teiid.designer.metamodels.xml.XmlRoot;
import org.teiid.designer.metamodels.xml.impl.XmlDocumentImpl;
import org.teiid.designer.query.IQueryFactory;
import org.teiid.designer.query.IQueryService;
import org.teiid.designer.query.sql.ICommandCollectorVisitor;
import org.teiid.designer.query.sql.IElementCollectorVisitor;
import org.teiid.designer.query.sql.IFunctionCollectorVisitor;
import org.teiid.designer.query.sql.IGroupCollectorVisitor;
import org.teiid.designer.query.sql.IPredicateCollectorVisitor;
import org.teiid.designer.query.sql.lang.ICommand;
import org.teiid.designer.query.sql.lang.ICompareCriteria;
import org.teiid.designer.query.sql.lang.IExpression;
import org.teiid.designer.query.sql.lang.ILanguageObject;
import org.teiid.designer.query.sql.lang.IOption;
import org.teiid.designer.query.sql.lang.IQuery;
import org.teiid.designer.query.sql.symbol.IElementSymbol;
import org.teiid.designer.query.sql.symbol.IFunction;
import org.teiid.designer.query.sql.symbol.IGroupSymbol;
import org.teiid.designer.transformation.TransformationPlugin;
import org.teiid.designer.transformation.metadata.TransformationMetadata;
import org.teiid.designer.transformation.util.AttributeMappingHelper;
import org.teiid.designer.transformation.util.SqlMappingRootCache;
import org.teiid.designer.transformation.util.TransformationHelper;
import org.teiid.designer.transformation.validation.SqlTransformationResult;
import org.teiid.designer.transformation.validation.TransformationValidationResult;
import org.teiid.designer.transformation.validation.TransformationValidator;
import org.teiid.designer.type.IDataTypeManagerService;
import org.teiid.designer.udf.IFunctionLibrary;
import org.teiid.designer.udf.IFunctionLibrary.FunctionName;
import org.teiid.designer.udf.UdfManager;
/**
* SqlTransformationMappingRootValidationRule
*
* @since 8.0
*/
public class SqlTransformationMappingRootValidationRule implements ObjectValidationRule {
private IQueryService getQueryService() {
return ModelerCore.getTeiidQueryService();
}
private IQueryFactory getQueryFactory() {
return getQueryService().createQueryFactory();
}
private IGroupCollectorVisitor getGroupCollectorVisitor() {
return getQueryService().getGroupCollectorVisitor(true);
}
/*
* @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 validationContext ) {
CoreArgCheck.isInstanceOf(SqlTransformationMappingRoot.class, eObject);
SqlTransformationMappingRoot transRoot = (SqlTransformationMappingRoot)eObject;
// Check to see if the target is tagged as a Global Temp Table
EObject target = transRoot.getTarget();
if( target instanceof BaseTable && RelationalUtil.isGlobalTempTable(target)) {
return; // DO NOTHING SQL can be empty
}
// create a validation result for the virtual group
ValidationResult validationResult = new ValidationResultImpl(transRoot, transRoot.getTarget());
// validate the mapping root, to see if it has one output and at least one input
validateMapping(transRoot, validationResult);
// validate sources nd targets on the mapping root
validateSourcesAndTargets(transRoot, validationResult);
// validate the mapping inputs checking for circular dependencies
validMappingInputDependencies(transRoot, validationResult);
// check the updatability of the virtual group in relation to its physical couterparts
// also check updateability in relation to update/insert/delete transform definition
validateUpdatability(transRoot, validationResult);
// valid sqltransformation in the mapping root
final TransformationValidator validator = new TransformationValidator(transRoot, validationContext, true, true);
validateSqlTransformation(transRoot, validationResult, validator, validationContext);
// if target is web service (Operation), validate input document's root element does not have a mapping class
validateInputDocumentForWebService(transRoot, validationResult);
// add the result to the context
validationContext.addResult(validationResult);
}
private void validateInputDocumentForWebService( final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult ) {
if (validationResult.isFatalObject(transRoot)) {
return;
}
EObject target = transRoot.getTarget();
if (!(target instanceof Operation)) {
return;
}
List sources = transRoot.getInputs();
for (final Iterator iter = sources.iterator(); iter.hasNext();) {
EObject source = (EObject)iter.next();
if (source instanceof XmlDocument) {
XmlDocument xmlDoc = (XmlDocument)source;
XmlRoot rootElement = xmlDoc.getRoot();
ModelContents mdlContents = ((EmfResource)source.eResource()).getModelContents();
Iterator contentIter = mdlContents.getTransformations(source).iterator();
if (!contentIter.hasNext()) {
return;
}
// get the mapping root associated with the transformation
while (contentIter.hasNext()) {
MappingRoot mappingRoot = (MappingRoot)contentIter.next();
if (mappingRoot != null && mappingRoot instanceof TreeMappingRoot) {
Iterator outputRootElementsIter = mappingRoot.getOutputs().iterator();
while (outputRootElementsIter.hasNext()) {
if (rootElement.equals(outputRootElementsIter.next())) {
ValidationProblem problem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.xml_doc_mapped_at_root_for_web_service")); //$NON-NLS-1$
validationResult.addProblem(problem);
return;
}
}
}
}
}
}
}
/**
* Check if the target of a mapping root can accept the sources on the sql transformation and also if the sources on the
* transformation can be added to for the given target.
* @param transRoot the mapping root (cannot be <code>null</code>)
* @param validationResult the result to add any validation errors to (cannot be <code>null</code>)
*
* @since 4.3
*/
public void validateSourcesAndTargets( final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult ) {
EObject target = transRoot.getTarget();
CoreArgCheck.isNotNull(target);
final Container container = ModelerCore.getContainer(transRoot);
if (container == null) {
return;
}
// if the target is a proxy try to resolve
if (target.eIsProxy()) {
target = EcoreUtil.resolve(target, container);
// still does not resolve, just return there will be other
// validation errors
if (target.eIsProxy()) {
return;
}
}
SqlAspect targetSqlAspect = org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.getSqlAspect(target);
if (targetSqlAspect == null
|| !(targetSqlAspect instanceof SqlTableAspect || targetSqlAspect instanceof SqlProcedureAspect)) {
ValidationProblem typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.no_valid_target")); //$NON-NLS-1$
validationResult.addProblem(typeProblem);
return;
}
List sources = transRoot.getInputs();
for (final Iterator iter = sources.iterator(); iter.hasNext();) {
EObject source = (EObject)iter.next();
// if the target is a proxy try to resolve
if (source.eIsProxy()) {
source = EcoreUtil.resolve(source, container);
// still does not resolve, just return there will be other
// validation errors
if (source.eIsProxy()) {
return;
}
}
SqlAspect sourceSqlAspect = org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.getSqlAspect(source);
boolean isFunction = source instanceof ScalarFunction;
if( !isFunction && (sourceSqlAspect == null ||
!(sourceSqlAspect instanceof SqlTableAspect || sourceSqlAspect instanceof SqlProcedureAspect)) ) {
ValidationProblem typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.no_valid_source")); //$NON-NLS-1$
validationResult.addProblem(typeProblem);
return;
}
if( !isFunction ) {
boolean isValidSource = true;
if (targetSqlAspect instanceof SqlTableAspect) {
isValidSource = ((SqlTableAspect)targetSqlAspect).canAcceptTransformationSource(target, source);
} else if (targetSqlAspect instanceof SqlProcedureAspect) {
isValidSource = ((SqlProcedureAspect)targetSqlAspect).canAcceptTransformationSource(target, source);
}
if (!isValidSource) {
String targetName = targetSqlAspect.getName(target);
String sourceName = sourceSqlAspect.getName(source);
ValidationProblem typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.invalid_source_for_target", sourceName, targetName)); //$NON-NLS-1$
validationResult.addProblem(typeProblem);
return;
}
boolean isValidTarget = true;
if (sourceSqlAspect instanceof SqlTableAspect) {
isValidTarget = ((SqlTableAspect)sourceSqlAspect).canBeTransformationSource(source, target);
} else if (sourceSqlAspect instanceof SqlProcedureAspect) {
isValidTarget = ((SqlProcedureAspect)sourceSqlAspect).canBeTransformationSource(source, target);
}
if (!isValidTarget) {
String targetName = targetSqlAspect.getName(target);
String sourceName = sourceSqlAspect.getName(source);
ValidationProblem typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.invalid_target_for_source", targetName, sourceName)); //$NON-NLS-1$
validationResult.addProblem(typeProblem);
return;
}
}
}
}
/**
* Check the inputs to the transform for circular dependencies to the tranformation target 1) ERROR -> If an input, in the
* chain of tranformation inputs, is the tranformation target
*/
private void validMappingInputDependencies( final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult ) {
if (validationResult.isFatalObject(transRoot)) {
return;
}
final Collection inputs = this.getMappingInputs(transRoot, true);
final EObject target = transRoot.getTarget();
for (Iterator iter = inputs.iterator(); iter.hasNext();) {
EObject source = (EObject)iter.next();
if (source != null && source == target) {
Object[] params = new Object[] {ModelerCore.getModelEditor().getModelRelativePathIncludingModel(source)};
String msg = TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.A_circular_dependency_exists_between_this_tranformation_and_the_source_group_0_1", params); //$NON-NLS-1$
ValidationProblem typeProblem = new ValidationProblemImpl(0, IStatus.ERROR, msg);
validationResult.addProblem(typeProblem);
}
}
}
/**
* Check the number of source groups and the number of target groups to the transformation mapping root. 1) ERROR -> If the
* transformation has more or less than one target.
*/
private void validateMapping( final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult ) {
if (validationResult.isFatalObject(transRoot)) {
return;
}
Collection outputs = transRoot.getOutputs();
if (outputs.size() < 1) {
String modelName = ModelerCore.getModelEditor().getModelName(transRoot).toString();
ValidationProblem problem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.Sql_transformation_in_the_model_{0},_has_no_target_tables/groups._1", modelName)); //$NON-NLS-1$
validationResult.addProblem(problem);
} else if (outputs.size() > 1) {
String modelName = ModelerCore.getModelEditor().getModelName(transRoot).toString();
ValidationProblem problem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.Sql_transformation_in_the_model_{0},_cannot_not_have_multiple_target_tables/groups._2", modelName)); //$NON-NLS-1$
validationResult.addProblem(problem);
} else {
EObject output = (EObject)outputs.iterator().next();
for (final Iterator inputIter = transRoot.getInputs().iterator(); inputIter.hasNext();) {
if (output == inputIter.next()) {
String msg = TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.The_virtual_group_{0}_cannot_be_involved_as_an_input_to_the_transformation_defining_it._1", TransformationHelper.getSqlEObjectName(output)); //$NON-NLS-1$
ValidationProblem failureProblem = new ValidationProblemImpl(0, IStatus.ERROR, msg);
validationResult.addProblem(failureProblem);
}
}
}
}
/**
* Validate parameters, resultSet and the sql that defines a update procedure. 1) Error -> INSERT procedure is trying to
* insert against the same virtual group 2) Error -> UPDATE procedure is trying to update against the same virtual group 3)
* Error -> DELETE procedure is trying to delete against the same virtual group 4) Warn -> If INSERT procedure does not
* contain a single INSERT ICommand. 5) Warn -> If HAS/TRANSLATE criteria constructs are used in INSERT procedures. 6) Warn ->
* If UPDATE procedure does not contain a single UPDATE ICommand. 7) Warn -> If DELETE procedure does not contain a single
* DELETE ICommand.
*/
private void validateUpdateProcedures( final TransformationValidationResult transformResult,
final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult,
final ValidationContext validationContext) {
if (validationResult.isFatalObject(transRoot)) {
return;
}
EObject target = transRoot.getTarget();
if (!(target instanceof Table) || !((Table)target).isSupportsUpdate()) {
return;
}
// Adding changes to check if "User Default" is checked for each update procedure
// IF NOT, then we don't want to validate this SQL and create Problems.
SqlTransformation transform = (SqlTransformation)transRoot.getHelper();
if (!transform.isInsertSqlDefault() && transformResult.hasInsertResult()) {
// validate insert procedure
ICommand insertCommand = transformResult.getInsertResult().getCommand();
if (insertCommand != null) {
// check if any of the commands are of type insert
validateSubCommands(insertCommand, ICommand.TYPE_INSERT, transRoot, validationResult, validationContext);
}
}
if (!transform.isUpdateSqlDefault() && transformResult.hasUpdateResult()) {
// validate update procedure
ICommand updateCommand = transformResult.getUpdateResult().getCommand();
if (updateCommand != null) {
// check if any of the commands are of type update
validateSubCommands(updateCommand, ICommand.TYPE_UPDATE, transRoot, validationResult, validationContext);
}
}
if (!transform.isDeleteSqlDefault() && transformResult.hasDeleteResult()) {
// validate delete procedure
ICommand deleteCommand = transformResult.getDeleteResult().getCommand();
if (deleteCommand != null) {
// check if any of the commands are of type delete
validateSubCommands(deleteCommand, ICommand.TYPE_DELETE, transRoot, validationResult, validationContext);
}
}
}
/**
* Validate the subcommands.
*
* @param superCmd The super command to validate
* @param subCmdType Pass the subcommand type to check something in the subcommand in the context of the super ICommand.
* @param transRoot The mapping root of the transformation
*/
private void validateSubCommands( final ICommand command,
final int subCmdType,
final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult,
final ValidationContext validationContext) {
ValidationProblem typeProblem = null;
// flag sets to true, if desired type of cmd is found for
// the super command
boolean foundDesiredSubCmd = false;
// get all the sub commands and iterate through them
ICommandCollectorVisitor commandCollectorVisitor = getQueryService().getCommandCollectorVisitor();
final Collection commands = commandCollectorVisitor.findCommands(command);
// get the target for the transformation
EObject target = transRoot.getTarget();
for (final Iterator cmdIter = commands.iterator(); cmdIter.hasNext();) {
ICommand subCommand = (ICommand)cmdIter.next();
int currentCmdType = subCommand.getType();
// if subcommand type is samme as that expected for super command
if (currentCmdType == subCmdType) {
foundDesiredSubCmd = true;
}
switch (currentCmdType) {
case ICommand.TYPE_QUERY:
if (subCommand instanceof IQuery) {
validateQuery((IQuery)subCommand, transRoot, validationResult, validationContext);
}
break;
case ICommand.TYPE_INSERT:
if (containsTarget(subCommand, target)) {
// create validation problem and addition to the results
typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.The_insert_procedure_for_the_virtualGroup_{0},_is_trying_to_execute_an_insert_against_itself._1", TransformationHelper.getSqlEObjectName(target))); //$NON-NLS-1$
}
break;
case ICommand.TYPE_UPDATE:
if (containsTarget(subCommand, target)) {
// create validation problem and addition to the results
typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.The_update_procedure_for_the_virtualGroup_{0},_is_trying_to_execute_an_update_against_itself._2", TransformationHelper.getSqlEObjectName(target))); //$NON-NLS-1$
}
break;
case ICommand.TYPE_DELETE:
if (containsTarget(subCommand, target)) {
// create validation problem and addition to the results
typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.The_delete_procedure_for_the_virtualGroup_{0},_is_trying_to_execute_an_delete_against_itself._3", TransformationHelper.getSqlEObjectName(target))); //$NON-NLS-1$
}
break;
default:
break;
}
// create validation problem and addition to the results
validationResult.addProblem(typeProblem);
// abort we found an error
if (typeProblem != null && typeProblem.getSeverity() == IStatus.ERROR) {
return;
}
// for each of the subcommand, validate its subcommands
validateSubCommands(subCommand, ICommand.TYPE_UNKNOWN, transRoot, validationResult, validationContext);
}
// if we do care abpout the subcommand type for the super command
// or desired subcommand is not found for the super command
if (subCmdType != ICommand.TYPE_UNKNOWN && !foundDesiredSubCmd) {
switch (subCmdType) {
case ICommand.TYPE_INSERT:
// create validation problem and addition to the results
typeProblem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.The_insert_procedure_for_the_virtualGroup_{0}_does____not_execute_an_insert._1", TransformationHelper.getSqlEObjectName(target))); //$NON-NLS-1$
break;
case ICommand.TYPE_UPDATE:
// create validation problem and addition to the results
typeProblem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.The_update_procedure_for_the_virtualGroup_{0}_does____not_execute_an_update._2", TransformationHelper.getSqlEObjectName(target))); //$NON-NLS-1$
break;
case ICommand.TYPE_DELETE:
// create validation problem and addition to the results
typeProblem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.The_delete_procedure_for_the_virtualGroup_{0}_does____not_execute_an_delete._3", TransformationHelper.getSqlEObjectName(target))); //$NON-NLS-1$
break;
default:
break;
}
validationResult.addProblem(typeProblem);
}
}
/**
* Check if any of the target group represented by the EObject is used in the given ICommand.
*/
private boolean containsTarget( final ICommand command,
final EObject target ) {
String targetName = TransformationHelper.getSqlEObjectFullName(target);
String targetUUID = TransformationHelper.getSqlEObjectUUID(target);
for (final Iterator grpIter = getGroupCollectorVisitor().findGroups(command).iterator(); grpIter.hasNext();) {
IGroupSymbol group = (IGroupSymbol)grpIter.next();
if (group.getName().equalsIgnoreCase(targetUUID) || group.getName().equalsIgnoreCase(targetName)) {
return true;
}
}
return false;
}
/**
* Validate parameters, resultSet and the sql that defines a virtual procedure. 1) Error -> If Procedure does not return a
* Result. 2) Error -> If the procedure defines parameters other than IN parameters. 3) Warn -> If the procedure's parameters
* are not used in the sql defining the procedure 4) Error -> If the command defining a procedure is an update procedure. 5)
* Error - > If the command defining proc is an update, the proc should have a result with one column of type int.
*/
private void validateVirtualProcedures( final ICommand command,
final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult ) {
if (validationResult.isFatalObject(transRoot)) {
return;
}
EObject target = transRoot.getTarget();
if (!(target instanceof Procedure)) {
return;
}
// target of the mapping root is a procedure
Procedure procTrgt = (Procedure)target;
// command type
int cmdType = command.getType();
// get the resultSet on the procedure
ProcedureResult procResult = procTrgt.getResult();
if (procResult == null && cmdType != ICommand.TYPE_UPDATE_PROCEDURE) {
// create validation problem and additional to the results
ValidationProblem typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.Virtual_stored_procedures_should_always_return_a_resultSet._1")); //$NON-NLS-1$
validationResult.addProblem(typeProblem);
return;
}
// Check whether any of the parameters are used in the SQL transformation ...
// 1. Accumulate the short names of the elements in the SQL ...
// final boolean useDeepIteration = true; // fix for defect 10879
final Collection elements = getElementsIncludeParameters(command);
final Collection upperSymbolNames = new HashSet(elements.size());
for (final Iterator elmntIter = elements.iterator(); elmntIter.hasNext();) {
final IElementSymbol symbol = (IElementSymbol)elmntIter.next();
final String symbolUpperName = AttributeMappingHelper.getSymbolFullName(symbol).toUpperCase();
upperSymbolNames.add(symbolUpperName);
}
// 2. Iterate over the parameters and verify they are used ...
// iterate over the parameters
Collection parameters = procTrgt.getParameters();
// set to true if there are no parameters
boolean paramUsed = parameters.isEmpty();
for (final Iterator paramIter = parameters.iterator(); paramIter.hasNext();) {
ProcedureParameter param = (ProcedureParameter)paramIter.next();
// check if any of the parameters are used in the SQL transform defining the
// procedure
// Check the parameter name; only need to do this if no parameters have been used
if (!paramUsed) {
// Get the SQL aspect for the parameter ...
final SqlAspect sqlAspect = AspectManager.getSqlAspect(param);
if (sqlAspect != null) {
final String paramName = sqlAspect.getFullName(param);
if (paramName != null) {
final String paramUpperName = paramName.toUpperCase();
if (upperSymbolNames.contains(paramUpperName)) {
paramUsed = true;
}
}
}
}
}
if (!paramUsed) {
// create validation problem and additional to the results
ValidationProblem typeProblem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.Sql_Transform_defining_the_virtual_procedure_{0}_does_not_use_any_of_the_parameters_defined_on_the_procedure._1", procTrgt.getName())); //$NON-NLS-1$
validationResult.addProblem(typeProblem);
}
// If it is update command then result should have one column of type 'int'
if (cmdType == ICommand.TYPE_INSERT || cmdType == ICommand.TYPE_UPDATE || cmdType == ICommand.TYPE_DELETE) {
Collection columns = procResult.getColumns();
String typeName = null;
if (columns.size() == 1) {
Column column = (Column)columns.iterator().next();
EObject columnType = column.getType();
if (columnType == null) {
// there is already a validation error
return;
}
final DatatypeManager dtMgr = ModelerCore.getDatatypeManager(column, true);
typeName = dtMgr.getName(columnType);
}
if (typeName == null || !typeName.equals(DatatypeConstants.BuiltInNames.INT)) {
// create validation problem and additional to the results
ValidationProblem typeProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.Virtual_stored_procedures_defined_by_an_Insert,_Update_or_Delete_statement_must_define_return_a_resultSet_with_one_column_of_type_int._4")); //$NON-NLS-1$
validationResult.addProblem(typeProblem);
}
}
}
private Collection getElementsIncludeParameters( ILanguageObject obj ) {
if (obj == null) {
return Collections.EMPTY_LIST;
}
IElementCollectorVisitor elementCollectorVisitor = getQueryService().getElementCollectorVisitor(true);
return elementCollectorVisitor.findElements(obj, true);
}
/**
* Check if the virtual group is updatable, atleast one of its source groups that define the virtual group is updatable. 1)
* ERROR - > If the virtual group is updatable, then its transformation should include atleast one updatable source.
*/
private void validateUpdatability( final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult ) {
if (validationResult.isFatalObject(transRoot)) {
return;
}
Collection inputs = transRoot.getInputs();
Collection outputs = transRoot.getOutputs();
if (outputs.isEmpty() || inputs.isEmpty()) {
return;
}
EObject targetObj = (EObject)outputs.iterator().next();
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isUpdatableGroup(targetObj)) {
boolean updatable = false;
for (final Iterator inIter = inputs.iterator(); inIter.hasNext();) {
EObject sourceObj = (EObject)inIter.next();
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isUpdatableGroup(sourceObj)
|| org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isProcedure(sourceObj)) {
updatable = true;
break;
}
}
if (!updatable) {
ValidationProblem problem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.The_transformation_defining_an_updatable_virtual_group_should_be_include_atleast_one_updatable_source_group._1", TransformationHelper.getSqlEObjectName(targetObj))); //$NON-NLS-1$
validationResult.addProblem(problem);
}
}
}
/**
* Validates the SqlTransformation by doing parsing/resolution/validation of the sql query on the transformation. If the query
* is found to be valid additional validation checks are applied on the query which would result is warnings. 1) ERROR -> If
* the sql defining the transformation, ie not parsable, resolvable or validatable. 2) ERROR -> Updateable virtual group,
* allows insert/update/delete but does not specify transformation
*/
private void validateSqlTransformation( final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult,
final TransformationValidator validator,
final ValidationContext validationContext ) {
if (validationResult.isFatalObject(transRoot)) {
return;
}
EObject target = transRoot.getTarget();
// User defined functions do not need SQL and shouldn't be validated
if( !validator.shouldValidate()) return;
String targetName = ModelerCore.getModelEditor().getName(target);
// Check if sql is empty
String selectSQL = SqlMappingRootCache.getSelectSql(transRoot);
if( selectSQL == null) {
int pref = validationContext.getPreferenceStatus(ValidationPreferences.RELATIONAL_EMPTY_TRANSFORMATIONS, IStatus.ERROR);
if (pref != IStatus.OK) {
final String msg = TransformationPlugin.Util.getString(
"SqlTransformationMappingRootValidationRule.No_sql_defined_for_{0}", targetName); //$NON-NLS-1$
ValidationProblem problem = new ValidationProblemImpl(0, pref, msg);
validationResult.addProblem(problem);
return;
}
}
TransformationValidationResult transformResult = validator.validateTransformation();
// get target group/procedure
// validate further only if transformation is valid
if (!transformResult.isValid()) {
//If the target is virtual procedure, and isFunction - we dont need a transformation - so ignore transformation problems
if(target instanceof Procedure) {
if( ((Procedure)target).isFunction() ) {
return;
}
}
Collection statuses = null;
// if has a invalid select collect status
SqlTransformationResult selectResult = transformResult.getSelectResult();
if (selectResult != null && !selectResult.isValidatable()) {
Collection selectStatuses = selectResult.getStatusList();
if (selectStatuses != null) statuses = selectStatuses;
}
// if has a invalid insert collect status
SqlTransformationResult insertResult = transformResult.getInsertResult();
if (insertResult != null && !insertResult.isValidatable()) {
Collection insertStatuses = insertResult.getStatusList();
if (insertStatuses != null) {
if (statuses == null) {
statuses = insertStatuses;
} else {
statuses.addAll(insertStatuses);
}
}
}
// if has a invalid update collect status
SqlTransformationResult updateResult = transformResult.getUpdateResult();
if (updateResult != null && !updateResult.isValidatable()) {
Collection updateStatuses = updateResult.getStatusList();
if (updateStatuses != null) {
if (statuses == null) {
statuses = updateStatuses;
} else {
statuses.addAll(updateStatuses);
}
}
}
// if has a invalid delete collect status
SqlTransformationResult deleteResult = transformResult.getDeleteResult();
if (deleteResult != null && !deleteResult.isValidatable()) {
Collection deleteStatuses = deleteResult.getStatusList();
if (deleteStatuses != null) {
if (statuses == null) {
statuses = deleteStatuses;
} else {
statuses.addAll(deleteStatuses);
}
}
}
// collect statuses on tranformation result
Collection transformStatuses = transformResult.getStatusList();
if (transformStatuses != null) {
if (statuses == null) {
statuses = transformStatuses;
} else {
statuses.addAll(transformStatuses);
}
}
// create validation problems for all validation statuses
if (statuses != null) {
for (final Iterator statusIter = statuses.iterator(); statusIter.hasNext();) {
// create validation problem and add it to the results
ValidationProblem failureProblem = new ValidationProblemImpl((IStatus)statusIter.next());
validationResult.addProblem(failureProblem);
}
}
return;
} else if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isUpdatableGroup(target)) {
// no Insert/Update/Delete transform but the table is updatable
// furthur validation checks on the update procedure.
validateUpdateProcedures(transformResult, transRoot, validationResult, validationContext);
}
SqlTransformationResult selectResult = transformResult.getSelectResult();
// apply validation furtur validation checks on the valid Select query
if (selectResult != null) {
ICommand command = selectResult.getCommand();
if (command != null) {
if (command instanceof IQuery) {
validateQuery((IQuery)command, transRoot, validationResult, validationContext);
}
validateSubCommands(command, ICommand.TYPE_UNKNOWN, transRoot, validationResult, validationContext);
}
if (!validationResult.isFatalObject(transRoot)) {
// compare the projected symbols from command with the columns
ProjectSymbolsValidationHelper projRule = new ProjectSymbolsValidationHelper();
projRule.validateProjectedSymbols(command, transRoot, validationResult);
// validate params, resultSet and sql on a virtual procedure.
validateVirtualProcedures(command, transRoot, validationResult);
// validate mapping class transformation
MappingClassTransformationValidationHelper rule = new MappingClassTransformationValidationHelper();
rule.validate(command, transRoot, validationResult);
}
// if there is a string function (SUBSTRING, LOCATE, and INSERT), warn the user that it is one based
int pref = validationContext.getPreferenceStatus(ValidationPreferences.CORE_STRING_FUNCTIONS_ONE_BASED, IStatus.WARNING);
if (pref != IStatus.OK) {
IFunctionCollectorVisitor functionCollectorVisitor = getQueryService().getFunctionCollectorVisitor(true);
Collection<IFunction> functions = functionCollectorVisitor.findFunctions(command, true);
Iterator iter = functions.iterator();
while (iter.hasNext()) {
IFunction function = (IFunction)iter.next();
String functionName = function.getName().toUpperCase();
if ("SUBSTRING".equals(functionName) || "LOCATE".equals(functionName) || "INSERT".equals(functionName)) {//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
ValidationProblem stringFunctionWarning = new ValidationProblemImpl(
0,
pref,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.STRING_BASED_FUNCTION_ONE_BASED")); //$NON-NLS-1$
stringFunctionWarning.setHasPreference(validationContext.hasPreferences());
validationResult.addProblem(stringFunctionWarning);
break;
}
}
}
}
}
/**
* Apply additional validation checks on query in the command defining the transform. 1) WARNING - > If there is a cross join
* involved in the sql. 2) WARNING -> IF there is a join involved between elements of differrent types.
*/
private void validateQuery( final IQuery query,
final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult,
final ValidationContext validationContext) {
IElementCollectorVisitor elementCollectorVisitor = getQueryService().getElementCollectorVisitor(true);
IPredicateCollectorVisitor predicateCollectorVisitor = getQueryService().getPredicateCollectorVisitor();
// apply additional validation checks for queries
Collection predicates = predicateCollectorVisitor.findPredicates(query);
Collection groups = getGroupCollectorVisitor().findGroups(query);
if (predicates.isEmpty() && groups.size() > 1) {
// There are no predicates but there are groups
// (this is the trivial case)
/* Check whether this validation problem should be ignored */
int pref = validationContext.getPreferenceStatus(ValidationPreferences.POSSIBLE_CROSS_JOIN, IStatus.WARNING);
if (pref != IStatus.OK) {
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
pref,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.6", getNamesForGroupSymbols(groups))); //$NON-NLS-1$
validationResult.addProblem(warningProblem);
// added to append xml document parent info.
appendDocumentLocation(transRoot, validationResult);
}
} else if (groups.size() > 1) {
// Make sure that all the groups appear in at least one join predicate,
// (note there might be predicates that are not join predicates).
// Otherwise warn of a possible cross join.
// A join predicate must be of the form "GroupA.ElementA = GroupB.ElementB".
// collection groups that are joined
List allJoins = new ArrayList();
IFunctionLibrary functionLibrary = UdfManager.getInstance().getFunctionLibrary();
for (final Iterator predicateIter = predicates.iterator(); predicateIter.hasNext();) {
Object predicate = predicateIter.next();
if (predicate instanceof ICompareCriteria) {
ICompareCriteria compare = (ICompareCriteria)predicate;
// collect all the groups involved in this join
Collection groupsInJoin = new HashSet();
for (final Iterator elementIter = elementCollectorVisitor.findElements(compare).iterator(); elementIter.hasNext();) {
IElementSymbol element = (IElementSymbol)elementIter.next();
IGroupSymbol group = element.getGroupSymbol();
if (group == null && element.isExternalReference()) {
String elementFullName = element.getName();
int grpIndex = elementFullName.indexOf(element.getShortName());
String groupName = elementFullName.substring(0, grpIndex - 1);
group = getQueryFactory().createGroupSymbol(groupName);
}
if (group != null) {
groupsInJoin.add(group);
}
}
// only if multiple groups are involved is it a join
if (groupsInJoin.size() > 1) {
allJoins.add(groupsInJoin);
}
if (compare.getOperator() == ICompareCriteria.EQ) {
IExpression leftExpression = compare.getLeftExpression();
IExpression rightExpression = compare.getRightExpression();
// in case of CAST/CONVERT functions get the elementsymbol in the function
// and compare types
if (leftExpression != null && leftExpression instanceof IFunction) {
IFunction leftFunction = (IFunction)leftExpression;
String descriptorName = leftFunction.getFunctionDescriptor().getName();
if (leftFunction.isImplicit()
&& descriptorName != null
&& (descriptorName.equals(functionLibrary.getFunctionName(FunctionName.CONVERT)) ||
descriptorName.equals(functionLibrary.getFunctionName(FunctionName.CAST)))) {
leftExpression = leftFunction.getArg(0);
}
}
if (rightExpression != null && rightExpression instanceof IFunction) {
IFunction rightFunction = (IFunction)rightExpression;
String descriptorName = rightFunction.getFunctionDescriptor().getName();
if (rightFunction.isImplicit()
&& descriptorName != null
&& (descriptorName.equals(functionLibrary.getFunctionName(FunctionName.CONVERT)) ||
descriptorName.equals(functionLibrary.getFunctionName(FunctionName.CAST)))) {
rightExpression = rightFunction.getArg(0);
}
}
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
if (leftExpression instanceof IElementSymbol && rightExpression instanceof IElementSymbol) {
Class leftDataType = leftExpression.getType();
Class rightDataType = rightExpression.getType();
if (!leftDataType.equals(rightDataType)) {
Object[] params = new Object[] {compare, service.getDataTypeName(leftDataType),
service.getDataTypeName(rightDataType)};
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.Join_type_mismatch_in_crit", params)); //$NON-NLS-1$
validationResult.addProblem(warningProblem);
// added to append xml document parent info.
appendDocumentLocation(transRoot, validationResult);
}
}
}
}
}
// based on transitive property check if the groups in the various
// joins are joined i.e if a join b and b join c then a is joined to c or a,b,c are joined
// accumulated the groups thus joined in a collection
// collection of all the groups joined
Collection groupsJoined = new HashSet();
if (allJoins.size() == 1) {
groupsJoined.addAll((Collection)allJoins.get(0));
} else {
for (int i = 0; i < allJoins.size(); i++) {
Collection join1 = (Collection)allJoins.get(i);
for (int j = i + 1; j < allJoins.size(); j++) {
Collection join2 = (Collection)allJoins.get(j);
// check if groups in join2 are in join1
for (final Iterator grpIter = join2.iterator(); grpIter.hasNext();) {
IGroupSymbol joinGrp = (IGroupSymbol)grpIter.next();
// all groups in join1 and join2 are joined together
if (join1.contains(joinGrp)) {
groupsJoined.addAll(join1);
groupsJoined.addAll(join2);
break;
}
}
}
}
}
// check if existing joins have all groups involved in the query
if (!groupsJoined.containsAll(groups)) { // there are still unjoined groups
groups.removeAll(groupsJoined);
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.6", getNamesForGroupSymbols(groups))); //$NON-NLS-1$
validationResult.addProblem(warningProblem);
// added to append xml document parent info.
appendDocumentLocation(transRoot, validationResult);
}
}
// validate the option if any
validateOption(query, transRoot, validationResult);
}
/**
* This method is added to append the xml document model parent node info in case of a warning accures. MyDefect 155885
*
* @since 4.2
*/
private void appendDocumentLocation( final SqlTransformationMappingRoot transRoot,
final ValidationResult validationResult ) {
String docName = getDocumentName(transRoot);
if (docName != null) {
validationResult.setLocationPath(docName + "/" + validationResult.getLocationPath()); //$NON-NLS-1$
}
}
/**
* This method provide the xml document parent node name.
*
* @since 4.2
*/
private String getDocumentName( final SqlTransformationMappingRoot transRoot ) {
String docName = null;
Object mappingClassImpl;
Object mappingClassSetImpl;
Object xmlDocumentImpl;
try {
mappingClassImpl = transRoot.getTarget();
if (mappingClassImpl instanceof MappingClassImpl) {
mappingClassSetImpl = ((MappingClassImpl)mappingClassImpl).eContainer();
if (mappingClassSetImpl instanceof MappingClassSetImpl) {
xmlDocumentImpl = ((MappingClassSetImpl)mappingClassSetImpl).getTarget();
if (xmlDocumentImpl instanceof XmlDocumentImpl) {
docName = ((XmlDocumentImpl)xmlDocumentImpl).getName();
}
}
}
} catch (Exception ex) {
TransformationPlugin.Util.log(IStatus.WARNING, ex, ex.getMessage());
}
return docName;
}
private Collection getNamesForGroupSymbols( final Collection groups ) {
Collection groupNames = new HashSet(groups.size());
for (final Iterator iter = groups.iterator(); iter.hasNext();) {
IGroupSymbol grpSyb = (IGroupSymbol)iter.next();
Object metadataID = grpSyb.getMetadataID();
if (metadataID != null && metadataID instanceof MetadataRecord) {
groupNames.add(((MetadataRecord)metadataID).getFullName());
} else {
groupNames.add(grpSyb.getName());
}
}
return groupNames;
}
/**
* Validate that the groups used in OPTION MAKEDEP and NOCACHE clause are physical groups used in the transformation or any of
* the tranformations it depends on.
*
* @since 4.2
*/
private void validateOption( final ICommand command,
final SqlTransformationMappingRoot root,
final ValidationResult result ) {
IOption option = command.getOption();
if (option == null) {
return;
}
// Validate the Option dependent groups
validateDepOptionGroups(option.getDependentGroups(), root, result);
// Validate the Option not dependent groups
validateDepOptionGroups(option.getNotDependentGroups(), root, result);
// Validate the Option NoCache groups
validateOptionNoCacheGrps(command, root, result);
}
/**
* Validate that the groups used in OPTION MAKEDEP/MAKENOTDEP clause are physical groups used in the transformation or any of
* the tranformations it depends on. 1) Warning -> Group name in MAKEDEP/MAKENOTDEP clause not fully qualified indicating it
* may be alias.
*
* @since 4.2
*/
private void validateDepOptionGroups( final Collection<String> groupNames,
final SqlTransformationMappingRoot root,
final ValidationResult result ) {
if (groupNames == null || groupNames.isEmpty()) {
return;
}
for (String groupName : groupNames) {
// check if the group name specified is a fully qualified name
// if it is not a fully qualified name, its
// probably an alias name
if (groupName.indexOf(TransformationMetadata.DELIMITER_CHAR) < 0) {
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.0", groupName)); //$NON-NLS-1$
result.addProblem(warningProblem);
// warn an alias is being used
continue;
}
/*
* As part of Case 5595 I am removing the code that used to generate an error
* when the group in a MAKEDEP clause was a virtual group.
*
*/
}
}
/**
* Validate that the groups used in OPTION NOCACHE caluse are physical groups used in the transformation or any of the
* tranformations it depends on. 1) Warning -> Group name in NOCACHE clause not fully qualified indicating it may be alias. 2)
* Error -> Group used in the NOCACHE clause is a virtual group 3) Error -> Could not find the group in NOCACHE clause in any
* dependent transformation
*
* @since 4.2
*/
private void validateOptionNoCacheGrps( final ICommand command,
final SqlTransformationMappingRoot root,
final ValidationResult result ) {
IOption option = command.getOption();
if (option == null || !option.isNoCache()) {
return;
}
Collection groups = getGroupCollectorVisitor().findGroups(command);
// names of groups specified in NO cACHE clause
Collection<String> noCacheGroups = option.getNoCacheGroups();
boolean hasMaterializedGroups = false;
if (noCacheGroups != null) {
for (String groupName : noCacheGroups) {
boolean foundMaterializedMatch = false;
// collections of short and group names that match the
// names of noCacheGroup
Collection shortNamesMatched = new LinkedList();
Collection partialNamesMatched = new LinkedList();
Collection aliasNamesMatched = new LinkedList();
// compare the name against against the names of materialized virtual groups
for (final Iterator grpIter = groups.iterator(); grpIter.hasNext();) {
IGroupSymbol grpSymbol = (IGroupSymbol)grpIter.next();
Object metadataID = grpSymbol.getMetadataID();
if (metadataID != null && metadataID instanceof TableRecord) {
TableRecord record = (TableRecord)metadataID;
String tableFullName = record.getFullName();
String tableShortName = record.getName();
String aliasName = grpSymbol.getDefinition() != null ? grpSymbol.getName() : null;
boolean isMaterialized = record.isMaterialized();
if (isMaterialized) {
hasMaterializedGroups = true;
}
// if full name match found, break out and continue
// with the other groups in the NO OPTION clause
if (isMaterialized && groupName.equalsIgnoreCase(tableFullName)) {
foundMaterializedMatch = true;
break;
} else if (groupName.equalsIgnoreCase(tableShortName)) {
if (!shortNamesMatched.contains(groupName.toUpperCase())) {
shortNamesMatched.add(groupName.toUpperCase());
if (isMaterialized) {
foundMaterializedMatch = true;
}
} else {
// ambiguous case
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.7", groupName)); //$NON-NLS-1$
result.addProblem(warningProblem);
return;
}
} else if (aliasName != null && groupName.equalsIgnoreCase(aliasName)) {
if (!aliasNamesMatched.contains(groupName.toUpperCase())) {
aliasNamesMatched.add(groupName.toUpperCase());
if (isMaterialized) {
foundMaterializedMatch = true;
}
} else {
// ambiguous case
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.8", groupName)); //$NON-NLS-1$
result.addProblem(warningProblem);
return;
}
} else if (CoreStringUtil.endsWithIgnoreCase(tableFullName, groupName)) {
if (!partialNamesMatched.contains(tableFullName.toUpperCase())) {
partialNamesMatched.add(tableFullName.toUpperCase());
if (isMaterialized) {
foundMaterializedMatch = true;
}
} else {
// ambiguous case
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.11", groupName)); //$NON-NLS-1$
result.addProblem(warningProblem);
return;
}
}
}
}
if (!foundMaterializedMatch) {
// group name does not match any materialized group names
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
IStatus.ERROR,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.9", groupName)); //$NON-NLS-1$
result.addProblem(warningProblem);
return;
}
}
}
if (!hasMaterializedGroups && (noCacheGroups == null || noCacheGroups.isEmpty())) {
ValidationProblem warningProblem = new ValidationProblemImpl(
0,
IStatus.WARNING,
TransformationPlugin.Util.getString("SqlTransformationMappingRootValidationRule.10")); //$NON-NLS-1$
result.addProblem(warningProblem);
return;
}
}
// / HELPER METHODS
private Collection getMappingInputs( final SqlTransformationMappingRoot root,
final boolean recursive ) {
if (root != null) {
Collection result = new HashSet();
Collection visitedMappings = new HashSet();
addInputsToCollection(root, result, visitedMappings, recursive);
return result;
}
return Collections.EMPTY_SET;
}
private void addInputsToCollection( final Mapping mapping,
final Collection result,
final Collection visitedMappings,
final boolean recursive ) {
if (mapping != null) {
// Make sure we do not visit the same Mapping more than once
if (visitedMappings.contains(mapping)) {
return;
}
visitedMappings.add(mapping);
result.addAll(mapping.getInputs());
if (!recursive) {
return;
}
// Iterate over the transformation inputs looking for inputs from virtual models
for (final Iterator iter = mapping.getInputs().iterator(); iter.hasNext();) {
final EObject input = (EObject)iter.next();
final Container container = ModelerCore.getContainer(mapping);
final Resource resource = ModelerCore.getModelEditor().findResource(container, input);
if (resource instanceof EmfResource) {
final EmfResource emfResource = (EmfResource)resource;
final ModelAnnotation model = emfResource.getModelAnnotation();
// If the input to the transformation is from a virtual model then
// we need to accumulate its inputs ...
if (model != null && model.getModelType() == ModelType.VIRTUAL_LITERAL) {
final ModelContents contents = emfResource.getModelContents();
final Collection xforms = contents.getTransformations(input);
for (final Iterator iterator = xforms.iterator(); iterator.hasNext();) {
final TransformationMappingRoot mappingRoot = (TransformationMappingRoot)iterator.next();
addInputsToCollection(mappingRoot, result, visitedMappings, recursive);
}
}
}
}
}
}
}