/*
* 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.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EObject;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.designer.core.ModelerCore;
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.SqlColumnAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlColumnSetAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlProcedureAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlTableAspect;
import org.teiid.designer.core.query.QueryValidationResult;
import org.teiid.designer.core.query.QueryValidator;
import org.teiid.designer.core.types.DatatypeManager;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.metamodels.relational.Procedure;
import org.teiid.designer.metamodels.transformation.MappingClass;
import org.teiid.designer.metamodels.transformation.SqlAlias;
import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.StagingTable;
import org.teiid.designer.metamodels.xml.XmlDocument;
import org.teiid.designer.query.IQueryFactory;
import org.teiid.designer.query.IQueryService;
import org.teiid.designer.query.metadata.IMetadataID;
import org.teiid.designer.query.metadata.IQueryMetadataInterface;
import org.teiid.designer.query.sql.IFunctionCollectorVisitor;
import org.teiid.designer.query.sql.ISQLConstants;
import org.teiid.designer.query.sql.lang.ICommand;
import org.teiid.designer.query.sql.lang.IExpression;
import org.teiid.designer.query.sql.lang.IQuery;
import org.teiid.designer.query.sql.lang.ISetQuery;
import org.teiid.designer.query.sql.lang.util.CommandHelper;
import org.teiid.designer.query.sql.symbol.IConstant;
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.TransformationMetadataFactory;
import org.teiid.designer.transformation.validation.TransformationValidator;
import org.teiid.designer.type.IDataTypeManagerService;
import org.teiid.designer.type.IDataTypeManagerService.DataTypeName;
import org.teiid.designer.udf.IFunctionDescriptor;
import org.teiid.designer.udf.IFunctionLibrary;
import org.teiid.designer.udf.IFunctionLibrary.FunctionName;
import org.teiid.designer.udf.UdfManager;
/**
* TransformationMappingHelper This class is responsible for handling mapping changes and source / target changes, in response to
* SQL changes.
*
* @since 8.0
*/
public class TransformationMappingHelper implements ISQLConstants {
private static final TransformationMappingHelper INSTANCE = new TransformationMappingHelper();
//private static final String TYPE_FEATURE = "type"; //$NON-NLS-1$
// private static final String ADD_ATTRIBUTES_TXN_DESCRIPTION = TransformationPlugin.Util.getString("TransformationMappingHelper.addAttributesTransactionDescription"); //$NON-NLS-1$
// private static final String ADD_ATTRIBUTES_BEGIN_ERROR = TransformationPlugin.Util.getString("TransformationMappingHelper.addAttributesBeginTransactionError"); //$NON-NLS-1$
// private static final String ADD_ATTRIBUTES_COMMIT_ERROR = TransformationPlugin.Util.getString("TransformationMappingHelper.addAttributesCommitTransactionError"); //$NON-NLS-1$
// private static final String RECONCILE_MAPPINGS_TXN_DESCRIPTION = TransformationPlugin.Util.getString("TransformationMappingHelper.reconcileMappingsTransactionDescription"); //$NON-NLS-1$
// private static final String RECONCILE_MAPPINGS_BEGIN_ERROR = TransformationPlugin.Util.getString("TransformationMappingHelper.reconcileMappingsBeginTransactionError"); //$NON-NLS-1$
// private static final String RECONCILE_MAPPINGS_COMMIT_ERROR = TransformationPlugin.Util.getString("TransformationMappingHelper.reconcileMappingsCommitTransactionError"); //$NON-NLS-1$
private static final boolean NOT_SIGNIFICANT = false;
private static final boolean IS_UNDOABLE = true;
public static final int TRANSFORMATION_CHANGED = 10;
public static final int TRANSFORMATION_UNCHANGED = 20;
private static final IStatus TRANSFORMATION_OK_CHANGED = new Status(
IStatus.OK,
TransformationPlugin.PLUGIN_ID,
TRANSFORMATION_CHANGED,
"internal: transformation parsed successfully, changes were applied", null); //$NON-NLS-1$
private static final IStatus TRANSFORMATION_OK_UNCHANGED = new Status(
IStatus.OK,
TransformationPlugin.PLUGIN_ID,
TRANSFORMATION_UNCHANGED,
"internal: transformation parsed successfully, no changes applied", null); //$NON-NLS-1$
private static final IStatus TRANSFORMATION_ISSUE = new Status(
IStatus.WARNING,
TransformationPlugin.PLUGIN_ID,
TRANSFORMATION_UNCHANGED,
"internal: transformation has warnings, no changes applied", null); //$NON-NLS-1$
private static boolean createTargetAttributes = true;
/**
* Get the SqlTransformationMappingHelper instance for this VM.
*
* @return the singleton instance for this VM; never null
*/
public static TransformationMappingHelper getInstance() {
return INSTANCE;
}
/**
* reconcile the mapping root inputs / attributes / etc to conform to the SQL strings
*
* @param transMappingRoot the transformation mapping root object.
* @param source the source of the transaction; may be null
*/
public static void reconcileMappingsOnSqlChange( EObject transMappingRoot,
Object source ) {
if (TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) {
// If source is null, use this Helper as the source
if (source == null) {
source = getInstance();
}
boolean isValid = SqlMappingRootCache.isSelectValid(transMappingRoot);
// --------------------------------------------------------------
// If the Query is Valid, continue
// --------------------------------------------------------------
if (isValid || TransformationHelper.isEmptySelect(transMappingRoot)) {
// Check whether Target Virtual Group is Locked
boolean isLocked = TransformationHelper.isTargetGroupLocked(transMappingRoot);
// start txn
boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Update Atribute Mappings", source); //$NON-NLS-1$
boolean succeeded = false;
try {
// Reconcile the mapping sources to the supplied command
reconcileSources(transMappingRoot, source);
// Reconcile VirtualGroup Target Only if unlocked
if (!isLocked && shouldCreateTargetAttributes()) {
reconcileTargetAttributes(transMappingRoot, source);
}
// Update the attributeMappings
AttributeMappingHelper.updateAttributeMappings(transMappingRoot, source);
succeeded = true;
} finally {
// if we started the txn, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
if (requiredStart) {
SqlMappingRootCache.invalidateSelectStatus(transMappingRoot, true, source);
}
}
}
}
/**
* Compares the query Target Group Attributes with the SQL command projected Symbols. A status array with three boolean values
* is returned. The array elements are (1) The number of target attributes is equal to the number of projected symbols (2) The
* number of attributes/symbols is equal AND names are the same (ignoring case). (3) The number of attributes/symbols is equal
* AND types are the same
*
* @param transMappingRoot the Transformation MappingRoot object
* @param type the command type
* @return the status array
*/
public static boolean[] compareQueryTargetAndSQLOutput( EObject transMappingRoot,
int type ) {
// Must be a QueryCommand, or there are no projected Symbols.
boolean sizesMatch = false;
boolean namesMatch = false;
boolean typesMatch = false;
if (transMappingRoot != null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) {
// ----------------------------------------------------------
// Get the Reconciler Target Group for the Query MetaObject
// ----------------------------------------------------------
EObject targetGroup = TransformationHelper.getTransformationTarget(transMappingRoot);
// ------------------------------------------------------------
// Compare Target Group attribute size to SQL Output Size
// ------------------------------------------------------------
if (targetGroup != null) {
// Get attributes that arent in an AccessPattern
// List attributes = TransformationHelper.getTransformationTargetAttributesNotInAccessPattern(transMappingRoot);
List attributes = TransformationHelper.getTransformationTargetAttributes(transMappingRoot);
// Get the Command for the supplied Type
ICommand command = TransformationHelper.getCommand(transMappingRoot, type);
// Get the list of names for the Select
List sqlNames = TransformationSqlHelper.getProjectedSymbolNames(command);
// check number of projected symbols for select - if zero, mark as failed
if (sqlNames.size() == 0 && !(targetGroup instanceof Procedure) && type == QueryValidator.SELECT_TRNS) {
sizesMatch = false;
// check number of Virtual Group Elems vs. number of projected symbols.
} else if (sqlNames.size() == attributes.size()) {
sizesMatch = true;
}
// if sizes match, check names and types
if (sizesMatch) {
// ----------------------------------------------------------
// Compare names
// ----------------------------------------------------------
List attributeNames = getAttributeNames(attributes);
namesMatch = allStringsMatch(sqlNames, attributeNames);
// ----------------------------------------------------------
// Compare types
// ----------------------------------------------------------
if (TransformationHelper.isValid(transMappingRoot, type)) {
// Get the list of SQL Symbols
List sqlSyms = CommandHelper.getProjectedSymbols(command);
// Compare the types
typesMatch = allTypesMatch(sqlSyms, attributes);
}
}
}
}
boolean[] result = {sizesMatch, namesMatch, typesMatch};
return result;
}
/**
* Determine if a supplied command output is reconciled with the transformation target group. This allows us to pull only one
* query from a UNION instead of looking at the whole mappingRoot command. The argument list includes a boolean which
* indicates whether the names are required to match. This is because queries other than the first in a UNION do not need to
* match names with the target - just the number of args and the types.
*
* @param transMappingRoot the transformation mappingroot object
* @param command the Command to compare the query MetaObject to
* @param nameMatchReqd 'true' if names must match, 'false' if not.
* @return 'true' if the reconciled, 'false' if not
*/
public static boolean targetAndCommandReconcile( EObject transMappingRoot,
ICommand command,
boolean nameMatchReqd ) {
// Must be a QueryCommand, or there are no projected Symbols.
boolean sizesMatch = false;
boolean namesMatch = false;
boolean typesMatch = false;
boolean areReconciled = false;
if (transMappingRoot != null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) {
// ----------------------------------------------------------
// Get the Reconciler Target Group for the Query MetaObject
// ----------------------------------------------------------
EObject targetGroup = TransformationHelper.getTransformationTarget(transMappingRoot);
// ------------------------------------------------------------
// Compare Target Group attribute size to SQL Output Size
// ------------------------------------------------------------
if (targetGroup != null) {
// Get attributes that arent in an AccessPattern
List attributes = TransformationHelper.getTransformationTargetAttributes(transMappingRoot);
// Get the list of names for the Select
List<String> sqlNames = TransformationSqlHelper.getProjectedSymbolNames(command);
// check number of Virtual Group Elems vs. number of projected symbols.
if (sqlNames.size() == attributes.size()) {
sizesMatch = true;
}
if (sizesMatch) {
// ----------------------------------------------------------
// Compare names
// ----------------------------------------------------------
List attributeNames = getTargetAttributeNames(transMappingRoot);
namesMatch = allStringsMatch(sqlNames, attributeNames);
// ----------------------------------------------------------
// Compare types
// ----------------------------------------------------------
if (commandValid(transMappingRoot, command)) {
// Get the list of SQL Symbols
List sqlSyms = CommandHelper.getProjectedSymbols(command);
// Compare the types
typesMatch = allTypesMatch(sqlSyms, attributes);
}
}
}
}
if (nameMatchReqd && sizesMatch && namesMatch && typesMatch) {
areReconciled = true;
} else if (!nameMatchReqd && sizesMatch && typesMatch) {
areReconciled = true;
}
return areReconciled;
}
/**
* Compares a SingleElementSymbol and an attribute to see if their types match.
*
* @param seSymbol the SingleElementSymbol
* @param attribute the EObject attribute
* @return 'true' if the types match, 'false' if not
*/
public static boolean typesMatch( IExpression seSymbol,
EObject attribute ) {
boolean typesMatch = false;
if (seSymbol != null && attribute != null) {
Class symType = seSymbol.getType();
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
if (symType != null && (symType == service.getDefaultDataClass(DataTypeName.NULL) || RuntimeTypeConverter.isExplicitMatch(seSymbol, attribute))) {
typesMatch = true;
}
}
return typesMatch;
}
/**
* Compares a List of SingleElementSymbols and a List of attributes to see if all their types match.
*
* @param symbolList the List of SingleElementSymbols
* @param attributeList the List of EObject attributes
* @return 'true' if all types match, 'false' if not
*/
private static boolean allTypesMatch( List symbolList,
List attributeList ) {
if (symbolList != null && attributeList != null && symbolList.size() == attributeList.size()) {
for (int i = 0; i < symbolList.size(); i++) {
IExpression seSymbol = (IExpression)symbolList.get(i);
EObject attr = (EObject)attributeList.get(i);
if (!typesMatch(seSymbol, attr)) {
return false;
}
}
}
return true;
}
/**
* Compares two Lists of strings to see if they all match (ignoring 'case').
*
* @param list1 the first list of names
* @param list1 the second list of names
* @return 'true' if all strings match, 'false' if not
*/
private static boolean allStringsMatch( List list1,
List list2 ) {
if (list1 != null && list2 != null && list1.size() == list2.size()) {
for (int i = 0; i < list1.size(); i++) {
String str1 = (String)list1.get(i);
String str2 = (String)list2.get(i);
if (!str1.equalsIgnoreCase(str2)) {
return false;
}
}
return true;
}
return false;
}
/**
* determine if the supplied command is valid
*
* @param command the Command
* @return 'true' if the command is valid, 'false' if not
*/
private static boolean commandValid( EObject transMappingRoot,
ICommand command ) {
boolean isCommandValid = false;
// If command is not resolved, attempt to resolve it.
if (!command.isResolved()) {
QueryValidator validator = new TransformationValidator((SqlTransformationMappingRoot)transMappingRoot);
QueryValidationResult result = validator.validateSql(command.toString(), QueryValidator.SELECT_TRNS, false);
if (result.isValidatable()) {
isCommandValid = true;
}
} else {
isCommandValid = true;
}
return isCommandValid;
}
// This method attempts to reconcile the transformation mapping sources to match
// the supplied sql
public static boolean reconcileSources( final EObject transMappingRoot,
Object source ) {
boolean success = false;
// If source is null, then use this Helper as the source
if (source == null) {
source = getInstance();
}
boolean isValid = SqlMappingRootCache.isSelectValid(transMappingRoot);
// --------------------------------------------------------------
// If the Query is Valid, continue
// --------------------------------------------------------------
if (isValid && !isReadOnly(transMappingRoot)) {
// start txn
boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Reconcile Sources", source); //$NON-NLS-1$
boolean succeeded = false;
try {
// Defect 20912 - added code to check for orphaned inputs or aliases
TransformationHelper.reconcileInputsAndAliases(transMappingRoot);
List allCommands = new ArrayList();
ICommand selectCommand = SqlMappingRootCache.getSelectCommand(transMappingRoot);
allCommands.add(selectCommand);
// Include sources for INS/UPD/DEL transformations also.
EObject target = TransformationHelper.getTransformationTarget(transMappingRoot);
if (TransformationHelper.tableSupportsUpdate(target)) {
if (TransformationHelper.isInsertAllowed(transMappingRoot)
&& SqlMappingRootCache.isInsertValid(transMappingRoot)) {
allCommands.add(SqlMappingRootCache.getInsertCommand(transMappingRoot));
}
if (TransformationHelper.isUpdateAllowed(transMappingRoot)
&& SqlMappingRootCache.isUpdateValid(transMappingRoot)) {
allCommands.add(SqlMappingRootCache.getUpdateCommand(transMappingRoot));
}
if (TransformationHelper.isDeleteAllowed(transMappingRoot)
&& SqlMappingRootCache.isDeleteValid(transMappingRoot)) {
allCommands.add(SqlMappingRootCache.getDeleteCommand(transMappingRoot));
}
}
// Get the Command Lookup GroupSymbols that arent in the mapping
IQueryMetadataInterface metadata = TransformationMetadataFactory.getInstance().getModelerMetadata(transMappingRoot,
false);
List<EObjectAlias> symbolsToAdd = new ArrayList<EObjectAlias>();
List<EObjectAlias> symbolsIncluded = new ArrayList<EObjectAlias>();
Iterator commandIter = allCommands.iterator();
while (commandIter.hasNext()) {
ICommand command = (ICommand)commandIter.next();
getEObjectAliases(transMappingRoot, command, symbolsToAdd, symbolsIncluded, metadata);
}
// All Aliases
List allAliases = new LinkedList(TransformationHelper.getAllSqlAliases(transMappingRoot));
// Remove the extra aliases
Iterator iter = allAliases.iterator();
while (iter.hasNext()) {
SqlAlias sqlAlias = (SqlAlias)iter.next();
if (!sqlAliasInGroupSymbolList(sqlAlias, symbolsIncluded)) {
EObject sqlEObj = sqlAlias.getAliasedObject();
String sqlAliasName = sqlAlias.getAlias();
TransformationHelper.removeSourceAlias(transMappingRoot, sqlEObj, sqlAliasName, true, source);
}
}
// add aliases for the Group symbols
for (EObjectAlias eObjectAlias : symbolsToAdd) {
TransformationHelper.addSqlAlias(transMappingRoot, eObjectAlias.object, eObjectAlias.name, true, source);
}
succeeded = true;
} finally {
// if we started the txn, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
} else if (TransformationHelper.isEmptySelect(transMappingRoot)) {
// start txn
boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Reconcile Sources", source); //$NON-NLS-1$
boolean succeeded = false;
try {
TransformationHelper.removeAllSourcesAndAliases(transMappingRoot, true, source);
succeeded = true;
} finally {
// if we started the txn, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
}
return success;
}
static class EObjectAlias {
EObject object;
String name;
public EObjectAlias(EObject object, String name) {
super();
this.object = object;
this.name = name;
}
}
private static void getEObjectAliases( EObject transMappingRoot,
ICommand command,
List<EObjectAlias> toAdd,
List<EObjectAlias> included,
IQueryMetadataInterface metadata ) {
// Get the GroupSymbols from the SQL command (duplicates removed)
Collection<IGroupSymbol> sqlGroupSymbols = TransformationSqlHelper.getGroupSymbols(command);
IQueryService queryService = ModelerCore.getTeiidQueryService();
IQueryFactory factory = queryService.createQueryFactory();
IFunctionCollectorVisitor functionCollectorVisitor = queryService.getFunctionCollectorVisitor(true);
Collection<IFunction> functions = functionCollectorVisitor.findFunctions(command, true);
// Get the SqlAliases for the mapping
List mappingAliases = TransformationHelper.getAllSqlAliases(transMappingRoot);
List<EObjectAlias> allAliases = new ArrayList<EObjectAlias>();
for (IFunction function : functions) {
IFunctionDescriptor fd = function.getFunctionDescriptor();
if (fd == null) {
continue;
}
IFunctionLibrary functionLibrary = UdfManager.getInstance().getFunctionLibrary();
if (fd.getName().equalsIgnoreCase(functionLibrary.getFunctionName(FunctionName.LOOKUP))) {
IExpression[] args = function.getArgs();
// First arg of the lookup is the group
if (args[0] instanceof IConstant) {
String groupName = (String)((IConstant)args[0]).getValue();
try {
Object metadataID = metadata.getGroupID(groupName);
IGroupSymbol symbol = factory.createGroupSymbol(groupName);
symbol.setMetadataID(metadataID);
if (!TransformationSqlHelper.containsGroupSymbol(sqlGroupSymbols, symbol)) {
sqlGroupSymbols.add(symbol);
}
} catch (Exception e) {
String message = TransformationPlugin.Util.getString("TransformationSqlHelper.groupIDNotFoundError", //$NON-NLS-1$
groupName);
TransformationPlugin.Util.log(IStatus.WARNING, e, message);
}
}
}
}
// Check each IGroupSymbol against the mapping SqlAliases. If not there add to result list
Iterator iter = sqlGroupSymbols.iterator();
while (iter.hasNext()) {
IGroupSymbol gSymbol = (IGroupSymbol)iter.next();
// If group symbol not in alias list, add to result list
if ((gSymbol.getMetadataID() instanceof IMetadataID) && !gSymbol.isProcedure()) {
continue;
}
// Get the Group EObject and Name
EObject groupEObj = TransformationSqlHelper.getGroupSymbolEObject(gSymbol);
String groupName = TransformationSqlHelper.getGroupSymbolShortName(gSymbol);
if (groupEObj == null || groupName == null) {
continue;
}
allAliases.add(new EObjectAlias(groupEObj, groupName));
}
for (EObjectAlias eObjectAlias : allAliases) {
if (!inAliasList(eObjectAlias, mappingAliases)) {
toAdd.add(eObjectAlias);
} else {
included.add(eObjectAlias);
}
}
}
/**
* Determine if IGroupSymbol is represented in the SqlAlias List.
*
* @param gSymbol the GroupSymbol
* @param sqlAliases the SqlAlias List
* @return 'true' if the sqlAlias List contains the groupSymbol, 'false' if not.
*/
private static boolean inAliasList( EObjectAlias alias,
List sqlAliases ) {
boolean inSqlList = false;
// Look for corresponding SqlAlias
Iterator iter = sqlAliases.iterator();
while (iter.hasNext()) {
SqlAlias sqlAlias = (SqlAlias)iter.next();
EObject aEObj = sqlAlias.getAliasedObject();
String aName = sqlAlias.getAlias();
if (aEObj != null && aName != null && aEObj.equals(alias.object) && aName.equalsIgnoreCase(alias.name)) {
inSqlList = true;
break;
}
}
return inSqlList;
}
/**
* Determine if IGroupSymbol is represented in the SqlAlias List.
*
* @param sqlAlias the SqlAlias
* @param objects
* @return 'true' if the group Symbol List contains the sqlAlias, 'false' if not.
*/
private static boolean sqlAliasInGroupSymbolList( SqlAlias sqlAlias,
Collection<EObjectAlias> objects ) {
boolean inGroupSymbolList = false;
// Get the SqlAlias info
EObject aliasEObj = sqlAlias.getAliasedObject();
String aliasName = sqlAlias.getAlias();
for (EObjectAlias eObjectAlias : objects) {
if (eObjectAlias.object.equals(aliasEObj) && eObjectAlias.name.equalsIgnoreCase(aliasName)) {
inGroupSymbolList = true;
break;
}
}
return inGroupSymbolList;
}
/**
* Reconcile the Query Select symbols with the existing Virtual Target attributes. If reconcile is possible, the target
* attributes will be created / reordered to match the SQL projected symbols. If the target Virtual Group is locked, no action
* will be taken. If it cannot be reconciled without user assistance, returns false.
*
* @param transMappingRoot the transformation mapping root.
* @param reconcileMappingClassTarget 'true' if auto-reconcile of MappingClass target is desired, 'false' if not.
* @param source txn source
* @return an OK status if reconcile was successful, a WARNING status if not. The code of the status will indicate whether any
* changes were made, via MAPPING_CHANGED or MAPPING_NOT_CHANGED
*/
public static IStatus reconcileTargetAttributes( EObject transMappingRoot,
boolean reconcileMappingClassTarget,
Object txnSource ) {
boolean success = false;
boolean changed = false;
// Do not reconcile if the target Group is Locked
if (!TransformationHelper.isTargetGroupLocked(transMappingRoot)) {
// If source is null, then use this Helper as the source
if (txnSource == null) {
txnSource = getInstance();
}
// Get the Target for this MappingRoot
EObject targetGroup = TransformationHelper.getTransformationTarget(transMappingRoot);
// If the target is a MappingClass, check reconcile flag before auto-reconciling.
// StagingTable passes thru
if (targetGroup instanceof MappingClass && !(targetGroup instanceof StagingTable) && !reconcileMappingClassTarget) {
return TRANSFORMATION_ISSUE;
}
// Check whether the mappingRoot source is XML Document - special handling
boolean hasXMLDocSource = false;
List sources = TransformationHelper.getTransformationSources(transMappingRoot);
if (sources.size() == 1 && sources.get(0) instanceof XmlDocument) {
hasXMLDocSource = true;
}
boolean isValid = SqlMappingRootCache.isSelectValid(transMappingRoot);
ICommand validCommand = null;
if (isValid) {
validCommand = SqlMappingRootCache.getSelectCommand(transMappingRoot);
}
// Target was found
if (targetGroup != null && validCommand != null) {
// start txn
boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT,
IS_UNDOABLE,
"Reconcile Target Attributes", txnSource); //$NON-NLS-1$
boolean succeeded = false;
try {
// Get the attribute Short Names
List currentTargetAttrNames = getTargetAttributeNames(transMappingRoot);
// Get projected symbol names. If target is Procedure ResultSet, dont use inputParams
List projectedSymbolNames = TransformationSqlHelper.getProjectedSymbolUniqueNames(validCommand);
int nCurrentTargetAttrs = currentTargetAttrNames.size();
int nProjectedSymbols = projectedSymbolNames.size();
// Number of Virtual Target attributes is more than the projected symbols
// Dont remove attributes, just modify query if there's name conflict
if (nProjectedSymbols < nCurrentTargetAttrs) {
// Modify query if there's a name conflict
resetSelectSqlOnNameConflict(validCommand, transMappingRoot, true, txnSource);
return TRANSFORMATION_ISSUE;
}
// --------------------- BML 3/21/07 --------------------------
// Defect 23839 - Modifications to do additional up-front checks to see if working on attribute mappings
// is necessary or not.
// Get the list of matchedNames between the two Lists
boolean namesMatch = compareLists(currentTargetAttrNames, projectedSymbolNames, true);
// If lists are a complete match, we're done.
if (!namesMatch) {
List matchedNames = getMatchedNames(currentTargetAttrNames, projectedSymbolNames);
// Get the list of unMatchedNames in the VirtualGroup
List unmatchedVirtualNames = removeNames(currentTargetAttrNames, matchedNames);
if (unmatchedVirtualNames.size() != 0) {
// Modify query if there's a name conflict
resetSelectSqlOnNameConflict(validCommand, transMappingRoot, true, txnSource);
return TRANSFORMATION_ISSUE;
}
// Get the list of Extra Names in the Select List
List extraSymbolNames = removeNames(projectedSymbolNames, matchedNames);
// Add the New Elements to the Target Group
if (extraSymbolNames.size() != 0) {
//create a resultset if none exists
if (TransformationHelper.isSqlProcedure(targetGroup)) {
SqlProcedureAspect procAspect = (SqlProcedureAspect)AspectManager.getSqlAspect(targetGroup);
EObject rs = (EObject)procAspect.getResult(targetGroup);
if (rs == null) {
targetGroup = TransformationHelper.createProcResultSet(targetGroup);
}
}
// Get the Map of ProjectedSymbol Name to the corresponding EObject (if exists)
Map eObjectMap = TransformationSqlHelper.getProjectedSymbolAndProcInputEObjects(validCommand);
addTargetAttributes(extraSymbolNames, eObjectMap, targetGroup, txnSource);
changed = true;
}
}
// Modify query if there's a name conflict
resetSelectSqlOnNameConflict(validCommand, transMappingRoot, true, txnSource);
// Ensure that the ordering is correct
// If it is NOT, then and only then do we call orderGroupAttributes()
if (attributesOutOfOrder(targetGroup, projectedSymbolNames)) {
changed = orderGroupAttributes(targetGroup, projectedSymbolNames) || changed;
}
// Set attribute types
// Get the Map of ProjectedSymbol Name to the corresponding MetaObject
Map symbolTypeMap = TransformationSqlHelper.getProjectedSymbolAndProcInputUniqueTypes(validCommand);
changed = setGroupAttributeTypes(targetGroup, symbolTypeMap) || changed;
// Set lengths if not mappingClass attributes
if (!(targetGroup instanceof MappingClass)) {
// Get the Map of ProjectedSymbol Name to the lengths for Strings (-1) if not Datatype
Map symbolLengthMap = TransformationSqlHelper.getProjectedSymbolAndProcInputLengths(validCommand,
hasXMLDocSource);
// Set attribute lengths for String datatypes
changed = setGroupAttributeLengths(targetGroup, symbolLengthMap) || changed;
}
// Update the attribute mappings
changed = AttributeMappingHelper.updateAttributeMappings(transMappingRoot, txnSource) || changed;
succeeded = true;
} finally {
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
if (changed && requiredStart) {
SqlMappingRootCache.invalidateSelectStatus(transMappingRoot, true, txnSource);
}
success = true;
}
}
IStatus rv;
if (success) {
rv = (changed) ? TRANSFORMATION_OK_CHANGED : TRANSFORMATION_OK_UNCHANGED;
} else {
rv = TRANSFORMATION_ISSUE;
} // endif
return rv;
}
/**
* Reconcile the Query Select symbols with the existing Virtual Target attributes. If reconcile is possible, the target
* attributes will be created / reordered to match the SQL projected symbols. If the target Virtual Group is locked, no action
* will be taken. If it cannot be reconciled without user assistance, returns false. This method will not auto-reconcile the
* target, if the target is a MappingClass.
*
* @param transMappingRoot the transformation mapping root.
* @param source txn source
* @return an OK status if reconcile was successful, a WARNING status if not. The code of the status will indicate whether any
* changes were made, via MAPPING_CHANGE or MAPPING_NO_CHANGE
*/
public static IStatus reconcileTargetAttributes( EObject transMappingRoot,
Object txnSource ) {
return reconcileTargetAttributes(transMappingRoot, false, txnSource);
}
/**
* Determine if any of the supplied objects are Procedures
*
* @param objList the list of objects
* @return 'true' if any of the supplied objects are SqlProcedures, 'false' if not.
*/
public static boolean hasProcedure( List objList ) { // NO_UCD
boolean hasProcedure = false;
// determine if any of the supplied objects are procedures
Iterator iter = objList.iterator();
while (iter.hasNext()) {
Object source = iter.next();
if (TransformationHelper.isSqlProcedure(source)) {
hasProcedure = true;
break;
}
}
return hasProcedure;
}
/**
* Get an ordered List of the Current Target Group Attribute Names
*
* @param the transformation mapping root
* @return the ordered list of attribute names
*/
public static List getTargetAttributeNames( EObject transMappingRoot ) {
List attributes = TransformationHelper.getTransformationTargetAttributes(transMappingRoot);
return getAttributeNames(attributes);
}
/**
* Get the names for the supplied attributes list
*
* @param attributes the list of attributes
* @return the list of attribute names
*/
public static List getAttributeNames( List attributes ) {
List attributeNames = new ArrayList();
Iterator iter = attributes.iterator();
while (iter.hasNext()) {
EObject attr = (EObject)iter.next();
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isColumn(attr)) {
// Handle special case when transformation target is WebService Operation
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isXmlDocument(attr)) {
attributeNames.add("xml"); //$NON-NLS-1$
} else {
SqlColumnAspect columnAspect = (SqlColumnAspect)AspectManager.getSqlAspect(attr);
attributeNames.add(columnAspect.getName(attr));
}
}
}
return attributeNames;
}
/**
* Get the names which occur in both lists, ignoring the case of the string.
*
* @param list1 the first list of Strings
* @param list2 the second list of Strings
* @return the list of strings which match between the lists
*/
private static List getMatchedNames( List list1,
List list2 ) {
List newList = new ArrayList();
Iterator list1Iter = list1.iterator();
// Iterate list1, look for match in list2
while (list1Iter.hasNext()) {
String list1Str = (String)list1Iter.next();
if (list1Str != null) {
Iterator list2Iter = list2.iterator();
while (list2Iter.hasNext()) {
String list2Str = (String)list2Iter.next();
if (list1Str.equalsIgnoreCase(list2Str)) {
newList.add(list1Str);
break;
}
}
}
}
return newList;
}
/**
* Remove the names in the removeList from the list.
*
* @param list the list of Strings to remove from
* @param removeList the list of Strings to remove
* @return the original list of strings minus the removeList
*/
private static List removeNames( List list,
List removeList ) {
// create a copy of the original list to work with
List newList = new ArrayList(list);
// Iterate the working list, remove items if match is found
Iterator removeIter = removeList.iterator();
while (removeIter.hasNext()) {
String removeStr = (String)removeIter.next();
Iterator newListIter = newList.iterator();
while (newListIter.hasNext()) {
String listName = (String)newListIter.next();
if (listName != null && listName.equalsIgnoreCase(removeStr)) {
newListIter.remove();
break;
}
}
}
return newList;
}
/**
* This method will reset the Select SQL strings when there is a name conflict with the projected symbol short names.
*
* @param queryCommand the query Command object
* @return the modified Query language object
*/
public static void resetSelectSqlOnNameConflict( ICommand command,
EObject transMappingRoot,
boolean isSignificant,
Object source ) {
// Modify query select if necessary
if (command != null && command instanceof IQuery && TransformationSqlHelper.hasProjectedSymbolNameConflict(command)) {
IQuery newQuery = TransformationSqlHelper.createQueryFixNameConflicts((IQuery)command, false);
// Set the SQL Statement
if (newQuery != null) {
TransformationHelper.setSelectSqlString(transMappingRoot, newQuery.toString(), isSignificant, source);
}
}
}
/**
* Create the Target Attributes with the provided names
*
* @param targetEObject the target EObject to add the attributes to
* @param attributeNames a list of the attributeNames (correspond to map keys), in the correct order
* @param isSignificant significance flag for undo
* @param source the source for the transaction
*/
public static void addTargetAttributes( final EObject targetEObject,
final List attributeNames,
final Object source ) {
if (targetEObject != null && attributeNames != null && !attributeNames.isEmpty()) {
// start txn
boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Add Target Attributes", source); //$NON-NLS-1$
boolean succeeded = false;
try {
// ---------------------------------------------------------
// Iterate thru the supplied list, creating new attributes
// ---------------------------------------------------------
String attrName = null;
// Object typeObj = null;
// Iterate on the attributeNames
Iterator iter = attributeNames.iterator();
while (iter.hasNext()) {
// Name of the attribute to create
attrName = (String)iter.next();
// Get the descriptor for a SqlColumn from the target
org.eclipse.emf.common.command.Command paramToCreate = getSqlColumnDescriptor(targetEObject);
// Object to determine type
// typeObj = objectTypeMap.get(attrName);
if (paramToCreate != null) {
// Create a new Attribute with the specified name
try {
EObject newEObject = ModelerCore.getModelEditor().createNewChildFromCommand(targetEObject,
paramToCreate);
ModelerCore.getModelEditor().rename(newEObject, attrName);
} catch (ModelerCoreException theException) {
String message = TransformationPlugin.Util.getString("TransformationMappingHelper.errorCreatingAttribute", //$NON-NLS-1$
attrName);
TransformationPlugin.Util.log(IStatus.ERROR, theException, message);
}
}
}
succeeded = true;
} finally {
// if we started the txn, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
}
}
private static org.eclipse.emf.common.command.Command getSqlColumnDescriptor( EObject targetEObject ) {
org.eclipse.emf.common.command.Command colDescriptor = null;
// ------------------------------------------------
// Get the Descriptor for ColumnAspect
// ------------------------------------------------
// Get the valid descriptors that can be added under the targetEObject
Collection descriptors = null;
try {
descriptors = ModelerCore.getModelEditor().getNewChildCommands(targetEObject);
} catch (ModelerCoreException e) {
String message = TransformationPlugin.Util.getString("TransformationMappingHelper.getChildDescriptorError", //$NON-NLS-1$
targetEObject.toString());
TransformationPlugin.Util.log(IStatus.ERROR, e, message);
return null;
}
// Use the first ColumnAspect found
Iterator iter = descriptors.iterator();
while (iter.hasNext()) {
colDescriptor = (org.eclipse.emf.common.command.Command)iter.next();
EObject eObj = (EObject)colDescriptor.getResult().iterator().next();
// If the descriptor is a ColumnAspect, stop
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isColumn(eObj)) {
break;
}
}
return colDescriptor;
}
/**
* Create the Target Attributes using the names/ordering provided in the attributeNames list. If there is a source EObject
* provided in the sourceEObject Map, then transfer its properties to the new Target Attribute.
*
* @param attributeNames a list of the attributeNames (correspond to map keys), in the correct order
* @param sourceEObjMap the map of attribute names (keys) to EObject (values)
* @param targetEObject the target EObject to add the attributes to
* @param isSignificant significance flag for undo
* @param source the source for the transaction
*/
public static void addTargetAttributes( final List attributeNames,
final Map sourceEObjectMap,
final EObject targetEObject,
final Object txnSource ) {
if (targetEObject != null && attributeNames != null && !attributeNames.isEmpty()) {
// start txn
boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Add Target Attributes", txnSource); //$NON-NLS-1$
boolean succeeded = false;
try {
// ---------------------------------------------------------
// Iterate thru the supplied list, creating new attributes
// ---------------------------------------------------------
String attrName = null;
// Iterate on the attributeNames
Iterator iter = attributeNames.iterator();
while (iter.hasNext()) {
// Name of the attribute to create
attrName = (String)iter.next();
// Get the descriptor for a SqlColumn from the target
org.eclipse.emf.common.command.Command paramToCreate = getSqlColumnDescriptor(targetEObject);
// Source EObject for transfer of properties
EObject srcEObj = (EObject)sourceEObjectMap.get(attrName);
// Create a new Attribute with the specified name and properties
try {
EObject newEObject = ModelerCore.getModelEditor().createNewChildFromCommand(targetEObject, paramToCreate);
ModelerCore.getModelEditor().rename(newEObject, attrName);
// Transfer properties if src EObj exists
TransformationHelper.transferSqlColumnProperties(newEObject, srcEObj, txnSource);
} catch (ModelerCoreException e) {
String message = TransformationPlugin.Util.getString("TransformationMappingHelper.createNewAttrError", //$NON-NLS-1$
targetEObject.toString());
TransformationPlugin.Util.log(IStatus.ERROR, e, message);
}
}
succeeded = true;
} finally {
// if we started the txn, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
}
}
// Get an ordered List of the Current Target Group Attribute Names
public static void removeTargetAttributes( Object mappingRoot,
List attributes,
final boolean isSignificant,
final Object source ) {
// --------------------- BML 3/21/07 --------------------------
// Defect 23839 - refactored this method a little to use SqlAspects directly instead of calling all TransformationHelper
// methods. It's more efficient to do this.
// start Txn
boolean requiredStart = ModelerCore.startTxn(isSignificant, IS_UNDOABLE, "Add Target Attributes", source); //$NON-NLS-1$
boolean succeeded = false;
try {
SqlTransformationMappingRoot transMappingRoot = null;
if (TransformationHelper.isSqlTransformationMappingRoot(mappingRoot)) {
transMappingRoot = (SqlTransformationMappingRoot)mappingRoot;
}
EObject virtualTarget = TransformationHelper.getTransformationTarget(transMappingRoot);
SqlAspect theTargetAspect = AspectManager.getSqlAspect(virtualTarget);
List deleteList = new ArrayList();
if (theTargetAspect instanceof SqlTableAspect || theTargetAspect instanceof SqlColumnSetAspect) {
// Get the current virtual target attributes
List columns = null;
if (theTargetAspect instanceof SqlTableAspect) {
columns = ((SqlTableAspect)theTargetAspect).getColumns(virtualTarget);
} else if (theTargetAspect instanceof SqlColumnSetAspect) {
columns = ((SqlColumnSetAspect)theTargetAspect).getColumns(virtualTarget);
}
// Add the attributes to the delete list
if(columns!=null) {
Iterator colIter = columns.iterator();
while (colIter.hasNext()) {
EObject attr = (EObject)colIter.next();
SqlAspect theChildAspect = AspectManager.getSqlAspect(attr);
if (theChildAspect instanceof SqlColumnAspect) {
if (containsName(attributes, ((SqlColumnAspect)theChildAspect).getName(attr))) {
deleteList.add(attr);
}
}
}
}
}
if (deleteList.size() > 0) {
// Delete the list of eObjects
try {
ModelerCore.getModelEditor().delete(deleteList);
} catch (ModelerCoreException e) {
String message = TransformationPlugin.Util.getString("TransformationMappingHelper.errorDeletingAttributes"); //$NON-NLS-1$
TransformationPlugin.Util.log(IStatus.ERROR, e, message);
}
}
succeeded = true;
} finally {
// if we started the txn, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
return;
}
private static boolean containsName( List attributes,
String name ) {
// --------------------- BML 3/21/07 --------------------------
// Defect 23839 - utilizing SqlAspects directly instead of using TransformationHelper methods. More efficient.
boolean contains = false;
Iterator iter = attributes.iterator();
while (iter.hasNext()) {
EObject eObj = (EObject)iter.next();
SqlAspect theAspect = AspectManager.getSqlAspect(eObj);
if (theAspect != null && theAspect instanceof SqlColumnAspect) {
String objName = ((SqlColumnAspect)theAspect).getName(eObj);
if (objName.equalsIgnoreCase(name)) {
contains = true;
break;
}
}
}
return contains;
}
public static EObject getListAttrByName( List attributes,
String name ) { // NO_UCD
// --------------------- BML 3/21/07 --------------------------
// Defect 23839 - utilizing SqlAspects directly instead of using TransformationHelper methods. More efficient.
EObject result = null;
Iterator iter = attributes.iterator();
while (iter.hasNext()) {
EObject eObj = (EObject)iter.next();
SqlAspect theAspect = AspectManager.getSqlAspect(eObj);
if (theAspect != null && theAspect instanceof SqlColumnAspect) {
String objName = ((SqlColumnAspect)theAspect).getName(eObj);
if (objName.equalsIgnoreCase(name)) {
result = eObj;
break;
}
}
}
return result;
}
/**
* Order the groups attributes to match the SQL projected symbol names
*
* @param transMappingRoot the SqlTransformationMappingRoot
*/
public static boolean orderGroupAttributes( final EObject transMappingRoot,
boolean requiresValidSelect,
ICommand modifiedCommand ) {
// Do nothing if the target Group is Locked
if (!TransformationHelper.isTargetGroupLocked(transMappingRoot)) {
boolean isValid = true;
if (requiresValidSelect) isValid = SqlMappingRootCache.isSelectValid(transMappingRoot);
ICommand validCommand = null;
if (isValid) {
validCommand = SqlMappingRootCache.getSelectCommand(transMappingRoot);
// Get the Target for this MappingRoot
EObject targetGroup = TransformationHelper.getTransformationTarget(transMappingRoot);
List<String> projectedSymbolNames = null;
if (modifiedCommand != null && validCommand instanceof ISetQuery) {
projectedSymbolNames = TransformationSqlHelper.getProjectedSymbolUniqueNames(modifiedCommand);
} else {
// Get the list of proposed unique names for the ProjectedSymbols
projectedSymbolNames = TransformationSqlHelper.getProjectedSymbolUniqueNames(validCommand);
}
// Order the target attributes
return orderGroupAttributes(targetGroup, projectedSymbolNames);
}
}
return false;
}
/**
* Order the groups attributes in the order of the supplied list of names.
*
* @param groupEObject the group that contains the attributes to reorder.
* @param attrNames a list of attribute names in the correct order.
*/
private static boolean orderGroupAttributes( final EObject groupEObject,
final List attrNames ) {
// Get the list of current SqlColumn index positions
List columnIndices = getColumnIndices(groupEObject);
boolean attributeMoved = false;
if (columnIndices.size() == attrNames.size()) {
for (int i = 0; i < attrNames.size(); i++) {
String name = (String)attrNames.get(i);
boolean wasMoved = moveAttribute(groupEObject, name, ((Integer)columnIndices.get(i)).intValue());
if (wasMoved) attributeMoved = wasMoved;
}
}
return attributeMoved;
}
/**
* Determines whether or not a a list of source "attributes" are represented by the sql column attributes for a target group
*
* @param groupEObject
* @param attrNames
* @return
* @since 5.0
*/
private static boolean attributesOutOfOrder( final EObject groupEObject,
final List attrNames ) {
List children = groupEObject.eContents();
int iSqlColumn = 0;
for (int i = 0; i < children.size(); i++) {
EObject nextChild = (EObject)children.get(i);
if (TransformationHelper.isSqlColumn(nextChild)) {
String targetChildName = ModelerCore.getModelEditor().getName(nextChild);
String sourceAttrName = (String)attrNames.get(iSqlColumn++);
// Only do the move if the names match and its at the wrong index
if (targetChildName != null && !targetChildName.equalsIgnoreCase(sourceAttrName)) {
return true;
}
}
}
return false;
}
/**
* Set the attribute types for the supplied group, using the supplied type map. An attribute type will only be set if it is
* null. Will not be changed if it has previously been set. The map is name (key) to type object (value) map.
*
* @param groupEObject the group that contains the attributes to reorder.
* @param attrTypemap the map to use in setting the group attribute types
* @return true if any data was changed.
*/
private static boolean setGroupAttributeTypes( final EObject groupEObject,
final Map attrTypeMap ) {
// --------------------- BML 3/21/07 --------------------------
// Defect 23839 - refactored a little to move the attrTypeMap.get() call to AFTER we've determined that the type does not
// exist. This should improve speed by eliminated ALL calls to get for a table where all column datatypes are already
// set.
boolean changed = false;
List children = groupEObject.eContents();
Iterator iter = children.iterator();
while (iter.hasNext()) {
EObject child = (EObject)iter.next();
SqlAspect theAspect = AspectManager.getSqlAspect(child);
if (theAspect != null && theAspect instanceof SqlColumnAspect) {
String colName = theAspect.getName(child);
// Only set the datatype if it has not already been set
EObject dtype = ((SqlColumnAspect)theAspect).getDatatype(child);
if (dtype == null) {
Object theType = attrTypeMap.get(colName);
if (theType != null) {
setAttributeType(child, theType);
changed = true;
}
}
}
}
return changed;
}
/**
* Set the attribute lengths for the supplied group, using the supplied type map. The map is name (key) to length integer
* (value) map.
*
* @param groupEObject the group that contains the attributes to set lengths
* @param attrLengthMap the map to use in setting the group attribute lengths
* @return true if any data was changed.
*/
public static boolean setGroupAttributeLengths( final EObject groupEObject,
final Map attrLengthMap ) {
// --------------------- BML 3/21/07 --------------------------
// Defect 23839 - refactored a little to move the attrTypeMap.get() call to AFTER we've determined that the type does not
// exist. This should improve speed by eliminated ALL calls to get for a table where all column datatypes are already
// set.
boolean changed = false;
if (attrLengthMap != null && !attrLengthMap.isEmpty()) {
List children = groupEObject.eContents();
Iterator iter = children.iterator();
while (iter.hasNext()) {
EObject child = (EObject)iter.next();
SqlAspect theAspect = AspectManager.getSqlAspect(child);
if (theAspect != null && theAspect instanceof SqlColumnAspect) {
String targetColName = theAspect.getName(child);
// Current length for the attribute
int currentLength = ((SqlColumnAspect)theAspect).getLength(child);
// Only set it if it hasn't been set yet
if (currentLength <= 0 && attrLengthMap.get(targetColName) != null) {
// New length
int length = ((Integer)attrLengthMap.get(targetColName)).intValue();
if (length != -1 && length != currentLength) {
if (((SqlColumnAspect)theAspect).canSetLength()) {
setAttributeLength(child, length);
changed = true;
}
}
}
}
}
}
return changed;
}
/**
* Get a list of index locations of the Columns in the supplied group EObject
*
* @param groupEObject the supplied group
* @return the List of column index positions for the supplied group.
*/
private static List getColumnIndices( EObject groupEObject ) {
List columnIndices = new ArrayList();
List children = groupEObject.eContents();
for (int i = 0; i < children.size(); i++) {
if (TransformationHelper.isSqlColumn(children.get(i))) {
columnIndices.add(new Integer(i));
}
}
return columnIndices;
}
/**
* Move a child attribute to a specific index
*
* @param attrName the name of the child attribute to move
* @param newIndex the index to place the element at
*/
private static boolean moveAttribute( EObject groupEObject,
String attrName,
int newIndex ) {
List children = groupEObject.eContents();
boolean moved = false;
// Go through the child list and move to the desired index
Iterator iter = children.iterator();
int index = 0;
while (iter.hasNext()) {
EObject eObj = (EObject)iter.next();
if (TransformationHelper.isSqlColumn(eObj)) {
String currentAttrName = TransformationHelper.getSqlEObjectName(eObj);
// Only do the move if the names match and its at the wrong index
if (currentAttrName.equalsIgnoreCase(attrName)) {
// Move the Element if at wrong index
// ----------------------------------------
if (newIndex != index) {
try {
ModelerCore.getModelEditor().move(groupEObject, eObj, newIndex);
moved = true;
} catch (ModelerCoreException err) {
String message = TransformationPlugin.Util.getString("TransformationMappingHelper.moveTargetAttrError", //$NON-NLS-1$
groupEObject.toString());
TransformationPlugin.Util.log(IStatus.ERROR, err, message);
}
break;
}
}
}
index++;
}
return moved;
}
/**
* Set the type on the supplied attribute EObject. The type object should be 1) Datatype 2) java Class 3) null
*
* @param attrEObject the attribute EObject
* @param typeObj the new attribute type
*/
private static void setAttributeType( EObject attrEObject,
Object typeObj ) {
if (TransformationHelper.isSqlColumn(attrEObject)) {
// Get new datatype for the supplied typeObj
EObject newDatatype = getDatatype(typeObj);
// Current datatype for the attribute
EObject currentDatatype = TransformationHelper.getSqlColumnDatatype(attrEObject);
// If new datatype is different that current, set it
if ((newDatatype == null && currentDatatype != null) || (newDatatype != null && !newDatatype.equals(currentDatatype))) {
TransformationHelper.setSqlColumnDatatype(attrEObject, newDatatype, getInstance());
}
}
}
/**
* Set the length on the supplied attribute EObject. The type object should be
*
* @param attrEObject the attribute EObject
* @param length the new attribute length
*/
private static void setAttributeLength( EObject attrEObject,
int newLength ) {
if (TransformationHelper.isSqlColumn(attrEObject)) {
// Current length for the attribute
int currentLength = TransformationHelper.getSqlColumnLength(attrEObject);
// If new datatype is different that current, set it
if (newLength != currentLength) {
TransformationHelper.setSqlColumnLength(attrEObject, newLength, getInstance());
}
}
}
/**
* Get the appropriate Datatype, given a "type" Object. The type Object will be one of 1) Datatype 2) java Class 3) null
*
* @param typeObj Object from which to determine the Datatype
* @return the Datatype for the supplied object
*/
private static EObject getDatatype( Object typeObj ) {
EObject datatype = null;
// ------------------------------------------------------
// Set the element type according to the supplied type
// ------------------------------------------------------
if (typeObj != null) {
// ------------------------------------------------
// Supplied type is a Datatype, just return it
// ------------------------------------------------
if (typeObj instanceof EObject) {
final EObject eObject = (EObject)typeObj;
final DatatypeManager dtMgr = ModelerCore.getDatatypeManager(eObject, true);
if (dtMgr.isSimpleDatatype(eObject)) {
datatype = (EObject)typeObj;
}
} else if (typeObj instanceof Class) {
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
// check for the NullType
if (((Class)typeObj).getSimpleName().equals(service.getDataTypeClass(null).getSimpleName())) {
// convert the NullType constant to the String type
typeObj = String.class;
}
// Get the runtime type for the java Class
String runtimeTypeName = service.getDataTypeName((Class)typeObj);
datatype = getDefaultDatatypeForRuntimeTypeName(runtimeTypeName);
}
}
return datatype;
}
public static EObject getDefaultDatatypeForRuntimeTypeName( String runtimeTypeName ) {
EObject datatype = null;
// Get the default Datatype for this runtime type
EObject typeEObj = null;
try {
typeEObj = ModelerCore.getWorkspaceDatatypeManager().getDefaultDatatypeForRuntimeTypeName(runtimeTypeName);
} catch (ModelerCoreException e) {
String message = TransformationPlugin.Util.getString("TransformationMappingHelper.errorFindingDefaultType", //$NON-NLS-1$
runtimeTypeName);
TransformationPlugin.Util.log(IStatus.ERROR, e, message);
}
if (typeEObj != null) {
final DatatypeManager dtMgr = ModelerCore.getDatatypeManager(typeEObj, true);
if (dtMgr.isSimpleDatatype(typeEObj)) {
return typeEObj;
}
}
return datatype;
}
/**
* Indicates if the given <code>EObject</code> is contained within a read-only resource.
*
* @param theEObject the object being checked
* @return <code>true</code> if the object is read-only; <code>false</code> otherwise.
*/
private static boolean isReadOnly( EObject theEObject ) {
// consider it read-only until proven otherwise
boolean result = true;
if (theEObject != null) {
ModelResource modelResource = ModelerCore.getModelEditor().findModelResource(theEObject);
if (modelResource != null) {
result = ModelUtil.isIResourceReadOnly(modelResource.getResource());
} else {
// outside workspace
result = false;
}
}
return result;
}
/**
* Determines if the lists of strings contain equal strings
*
* @param strings1
* @param strings2
* @param ignoreCase
* @return
* @since 5.0
*/
public static boolean compareLists( List strings1,
List strings2,
boolean ignoreCase ) {
int size1 = strings1.size();
int size2 = strings2.size();
if (size1 != size2) {
return false;
}
for (int i = 0; i < size1; i++) {
if (ignoreCase) {
if (!((String)strings1.get(i)).equals(strings2.get(i))) {
return false;
}
} else {
if (!((String)strings1.get(i)).equalsIgnoreCase((String)strings2.get(i))) {
return false;
}
}
}
return true;
}
public static boolean shouldCreateTargetAttributes() {
return createTargetAttributes;
}
public static void setCreateTargetAttributes( boolean theCreateTargetAttributes ) {
createTargetAttributes = theCreateTargetAttributes;
}
}