/* * 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.EventObject; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.ecore.EObject; import org.teiid.core.designer.event.EventObjectListener; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.query.QueryValidator; import org.teiid.designer.core.refactor.ModelResourceCollectorVisitor; import org.teiid.designer.core.validation.ValidationContext; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.metamodels.transformation.SqlTransformation; import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot; import org.teiid.designer.query.sql.ISQLConstants; import org.teiid.designer.query.sql.lang.ICommand; import org.teiid.designer.runtime.spi.ITeiidServer; import org.teiid.designer.runtime.spi.ITeiidServerVersionListener; import org.teiid.designer.runtime.version.spi.ITeiidServerVersion; import org.teiid.designer.transformation.TransformationPlugin; import org.teiid.designer.transformation.validation.SqlTransformationResult; import org.teiid.designer.transformation.validation.TransformationValidator; /** * SqlMappingRootCache * * @since 8.0 */ public class SqlMappingRootCache implements ISQLConstants { // Caches for each command type private static HashMap selectSqlCache = new HashMap(); private static HashMap insertSqlCache = new HashMap(); private static HashMap updateSqlCache = new HashMap(); private static HashMap deleteSqlCache = new HashMap(); /** List of listeners registered for cache events */ private static List eventListeners; private static final SqlMappingRootCache INSTANCE = new SqlMappingRootCache(); private static ITeiidServerVersionListener teiidServerVersionListener; static { teiidServerVersionListener = new ITeiidServerVersionListener() { @Override public void serverChanged(ITeiidServer server) { // Nothing to do } @Override public void versionChanged(ITeiidServerVersion version) { /* * Invalidate the cache since the models are no longer valid due to the change * of server version. The models contain LanguageObjects which are not common * between runtime clients. */ invalidateCache(); } }; ModelerCore.addTeiidServerVersionListener(teiidServerVersionListener); } /** * Get the SqlMappingRootCache instance for this VM. * @return the singleton instance for this VM; never null */ public static SqlMappingRootCache getInstance() { return INSTANCE; } /** * Invalidate the entire cache for all command types and all transformation mappings roots */ public static void invalidateCache() { getCache(QueryValidator.SELECT_TRNS).clear(); getCache(QueryValidator.INSERT_TRNS).clear(); getCache(QueryValidator.UPDATE_TRNS).clear(); getCache(QueryValidator.DELETE_TRNS).clear(); } /** * Invalidate the SELECT Status, if it exists in the cache. This means that the next * time status is requested, the query will need to be parsed/resolved/validated. */ public static void invalidateSelectStatus(final Object transMappingRoot, final boolean notifyListeners, final Object source) { invalidateSelectStatus(transMappingRoot, notifyListeners, source, false); } /** * Invalidate the SELECT Status, if it exists in the cache. This means that the next * time status is requested, the query will need to be parsed/resolved/validated. */ public static void invalidateSelectStatus(final Object transMappingRoot, final boolean notifyListeners, final Object source, boolean overwriteDirty) { invalidateStatus(transMappingRoot,QueryValidator.SELECT_TRNS,notifyListeners,source,overwriteDirty); } /** * Invalidate the INSERT Status, if it exists in the cache. This means that the next * time status is requested, the query will need to be parsed/resolved/validated. */ public static void invalidateInsertStatus(final Object transMappingRoot, final boolean notifyListeners, final Object source) { invalidateStatus(transMappingRoot,QueryValidator.INSERT_TRNS,notifyListeners,source,false); } /** * Invalidate the UPDATE Status, if it exists in the cache. This means that the next * time status is requested, the query will need to be parsed/resolved/validated. */ public static void invalidateUpdateStatus(final Object transMappingRoot, final boolean notifyListeners, final Object source) { invalidateStatus(transMappingRoot,QueryValidator.UPDATE_TRNS,notifyListeners,source,false); } /** * Invalidate the DELETE Status, if it exists in the cache. This means that the next * time status is requested, the query will need to be parsed/resolved/validated. */ public static void invalidateDeleteStatus(final Object transMappingRoot, final boolean notifyListeners, final Object source) { invalidateStatus(transMappingRoot,QueryValidator.DELETE_TRNS,notifyListeners,source,false); } public static void invalidateStatus(final Object transMappingRoot, final boolean notifyListeners, final Object source) { invalidateStatus(transMappingRoot,QueryValidator.SELECT_TRNS,notifyListeners,source, false); invalidateStatus(transMappingRoot,QueryValidator.UPDATE_TRNS,notifyListeners,source, false); invalidateStatus(transMappingRoot,QueryValidator.INSERT_TRNS,notifyListeners,source, false); invalidateStatus(transMappingRoot,QueryValidator.DELETE_TRNS,notifyListeners,source, false); } /** * Invalidate any Status that uses the provided sourceGroup. This means that the next * time status is requested, the query will need to be parsed/resolved/validated. */ public static void invalidateRootsWithSourceGroups(final Set sourceGroups) { // Go thru all the cached select MappingRoots HashMap currentSelectSqlCache = new HashMap(getCache(QueryValidator.SELECT_TRNS)); Iterator selectIter = currentSelectSqlCache.keySet().iterator(); while (selectIter.hasNext()) { EObject selectRoot = (EObject)selectIter.next(); boolean invalidateRoot = false; Iterator grpIter = sourceGroups.iterator(); while(grpIter.hasNext()) { Object sourceGroup = grpIter.next(); if(TransformationHelper.isSqlProcedureResultSet(sourceGroup)) { sourceGroup = TransformationHelper.getSqlProcedureForResultSet(sourceGroup); } if(containsStatus(selectRoot,QueryValidator.SELECT_TRNS)) { SqlTransformationResult selectStatus = getStatus(selectRoot,QueryValidator.SELECT_TRNS,false); if(selectStatus != null && selectStatus.hasSourceGroup(sourceGroup)) { invalidateRoot = true; break; } if(containsStatus(selectRoot,QueryValidator.INSERT_TRNS)) { SqlTransformationResult insertStatus = getStatus(selectRoot,QueryValidator.INSERT_TRNS,false); if(insertStatus != null && insertStatus.hasSourceGroup(sourceGroup)) { invalidateRoot = true; break; } } if(containsStatus(selectRoot,QueryValidator.UPDATE_TRNS)) { SqlTransformationResult updateStatus = getStatus(selectRoot,QueryValidator.UPDATE_TRNS,false); if(updateStatus != null && updateStatus.hasSourceGroup(sourceGroup)) { invalidateRoot = true; break; } } if(containsStatus(selectRoot,QueryValidator.DELETE_TRNS)) { SqlTransformationResult deleteStatus = getStatus(selectRoot,QueryValidator.DELETE_TRNS,false); if(deleteStatus != null && deleteStatus.hasSourceGroup(sourceGroup)) { invalidateRoot = true; break; } } } } if(invalidateRoot) { invalidateSelectStatus(selectRoot,true,null); } } } /** * Invalidate any Status that has any of the provided groups as its target. This means that * the next time status is requested, the query will need to be parsed/resolved/validated. */ public static void invalidateRootsWithTargetGroups(final Set groups) { // Go thru all the cached select MappingRoots HashMap currentSelectSqlCache = new HashMap(getCache(QueryValidator.SELECT_TRNS)); Iterator selectIter = currentSelectSqlCache.keySet().iterator(); while (selectIter.hasNext()) { EObject mappingRoot = (EObject)selectIter.next(); if(containsStatus(mappingRoot,QueryValidator.SELECT_TRNS)) { EObject targetGrp = TransformationHelper.getTransformationLinkTarget(mappingRoot); if(groups!=null && groups.contains(targetGrp)) { invalidateSelectStatus(mappingRoot,true,null); } } } } /** * Invalidate any cached status that is for a mappingRoot within the supplied project. * @param proj the supplied project. */ public static void invalidateCacheForProject(final IProject proj) { if(proj!=null && proj.isOpen()) { // Get the ModelResources within the supplied project List modelResources = new ArrayList(); ModelResourceCollectorVisitor visitor = new ModelResourceCollectorVisitor(); try { proj.getProject().accept(visitor); modelResources.addAll(visitor.getModelResources()); } catch (CoreException e) { // If unable to get ModelResources, just return. return; } // Iterate thru all the cached SELECT MappingRoots HashMap currentSelectSqlCache = new HashMap(getCache(QueryValidator.SELECT_TRNS)); Iterator selectIter = currentSelectSqlCache.keySet().iterator(); while (selectIter.hasNext()) { EObject mappingRoot = (EObject)selectIter.next(); // If mapping root is within a model in the supplied project, invalidate it. // Invalidating the SELECT, will cause INS/UPD/DEL to invalidate also. ModelResource mdlRsrc = ModelerCore.getModelEditor().findModelResource(mappingRoot); if (mdlRsrc != null && mdlRsrc.exists() && modelResources.contains(mdlRsrc)) { invalidateSelectStatus(mappingRoot,true,null); } } } } /** * This method invalidates mappingRoots upon closing a project or removing a model from * the workspace. All of the cached mapping roots are checked - if the target table or * any of the source table resource cannot be found, the mapping root status is invalidated. */ public static void invalidateRootsOnProjectOrModelRemove() { // Go thru all the cached select MappingRoots HashMap currentSelectSqlCache = new HashMap(getCache(QueryValidator.SELECT_TRNS)); Iterator selectIter = currentSelectSqlCache.keySet().iterator(); while (selectIter.hasNext()) { EObject selectRoot = (EObject)selectIter.next(); EObject realEObj = null; if( selectRoot != null ) { // Defect 19658 - This code was getting the URI for a root where the eContainer == NULL and the // URI was coming back "#//" and getEObject() was being called with this eObject causing // an StringIndexOutOfBoundsException. Simply checking the eResource() is sufficient // to verify if the root is out of scope (i.e. unloaded/closed/removed from workspace) if( selectRoot.eResource() != null ) realEObj = selectRoot; // // URI uri = ModelerCore.getModelEditor().getUri(selectRoot); // try { // realEObj = ModelerCore.getModelContainer().getEObject(uri, false); // } catch (CoreException err) { // err.printStackTrace(); // } } ModelResource mdlRsrc = null; boolean invalidateRoot = false; if (realEObj == null) { invalidateRoot = true; } else { mdlRsrc = ModelerCore.getModelEditor().findModelResource(selectRoot); if (mdlRsrc == null || !mdlRsrc.exists()) { invalidateRoot = true; } else if (containsStatus(selectRoot, QueryValidator.SELECT_TRNS)) { SqlTransformationResult selectStatus = getStatus(selectRoot, QueryValidator.SELECT_TRNS, false); if (selectStatus != null && (areAnySourceGroupsProxies(selectStatus) // this check looks for proxies without resolving them || !selectStatus.areSrcGroupMdlResourcesValid())) { invalidateRoot = true; } else { if (containsStatus(selectRoot, QueryValidator.INSERT_TRNS)) { SqlTransformationResult insertStatus = getStatus(selectRoot, QueryValidator.INSERT_TRNS, false); if (insertStatus != null && !insertStatus.areSrcGroupMdlResourcesValid()) { invalidateRoot = true; } } if (!invalidateRoot && containsStatus(selectRoot, QueryValidator.UPDATE_TRNS)) { SqlTransformationResult updateStatus = getStatus(selectRoot, QueryValidator.UPDATE_TRNS, false); if (updateStatus != null && !updateStatus.areSrcGroupMdlResourcesValid()) { invalidateRoot = true; } } if (!invalidateRoot && containsStatus(selectRoot, QueryValidator.DELETE_TRNS)) { SqlTransformationResult deleteStatus = getStatus(selectRoot, QueryValidator.DELETE_TRNS, false); if (deleteStatus != null && !deleteStatus.areSrcGroupMdlResourcesValid()) { invalidateRoot = true; } } } } } if (invalidateRoot) { invalidateSelectStatus(selectRoot, true, null); } } // endwhile } /** Scan the source groups, looking for proxies, without actually * resolving the proxies. * * @param status The status to use. * @return true if eIsProxy returns true for any source group. */ private static boolean areAnySourceGroupsProxies(SqlTransformationResult status) { // We need to wrap this in a NON_UNDOABLE transaction here to cover problems associated with re-loading // EMF resources which are creating CompoundCommand Undoables... Object[] srcGroups = null; boolean started = ModelerCore.startTxn(false, false, "SqlMappingRootCache_ProxyCheck", status); //$NON-NLS-1$ boolean succeeded = false; try { srcGroups= status.getSourceGroups().toArray(); succeeded = true; }finally { if ( started ) { if ( succeeded ) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } for (int i = 0; i < srcGroups.length; i++) { EObject eoj = (EObject) srcGroups[i]; if (eoj.eIsProxy()) { return true; } // endif } // endfor return false; } /** * Get the SELECT SQL Parsable State for the supplied TransformationMappingRoot. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isSelectParsable(final Object transMappingRoot) { return isParsable(transMappingRoot,QueryValidator.SELECT_TRNS); } /** * Get the SELECT SQL Resolvable State for the supplied TransformationMappingRoot. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isSelectResolvable(final Object transMappingRoot) { return isResolvable(transMappingRoot,QueryValidator.SELECT_TRNS); } /** * Get the SELECT SQL Valid State for the supplied TransformationMappingRoot. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isSelectValid(final Object transMappingRoot) { return isValid(transMappingRoot,QueryValidator.SELECT_TRNS); } /** * Get the INSERT SQL Valid State for the supplied TransformationMappingRoot. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isInsertValid(final Object transMappingRoot) { return isValid(transMappingRoot,QueryValidator.INSERT_TRNS); } /** * Get the UPDATE SQL Valid State for the supplied TransformationMappingRoot. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isUpdateValid(final Object transMappingRoot) { return isValid(transMappingRoot,QueryValidator.UPDATE_TRNS); } /** * Get the DELETE SQL Valid State for the supplied TransformationMappingRoot. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isDeleteValid(final Object transMappingRoot) { return isValid(transMappingRoot,QueryValidator.DELETE_TRNS); } /** * Get the SELECT Command language object for the supplied TransformationMappingRoot. * @param transMappingRoot the transformation MappingRoot * @return the Command languageObject */ public static ICommand getSelectCommand(final Object transMappingRoot) { return getCommand(transMappingRoot,QueryValidator.SELECT_TRNS); } /** * Get the INSERT Command language object for the supplied TransformationMappingRoot. * @param transMappingRoot the transformation MappingRoot * @return the Command languageObject */ public static ICommand getInsertCommand(final Object transMappingRoot) { return getCommand(transMappingRoot,QueryValidator.INSERT_TRNS); } /** * Get the UPDATE Command language object for the supplied TransformationMappingRoot. * @param transMappingRoot the transformation MappingRoot * @return the Command languageObject */ public static ICommand getUpdateCommand(final Object transMappingRoot) { return getCommand(transMappingRoot,QueryValidator.UPDATE_TRNS); } /** * Get the DELETE Command language object for the supplied TransformationMappingRoot. * @param transMappingRoot the transformation MappingRoot * @return the Command languageObject */ public static ICommand getDeleteCommand(final Object transMappingRoot) { return getCommand(transMappingRoot,QueryValidator.DELETE_TRNS); } /** * Get the SELECT Command language object for the supplied TransformationMappingRoot. * @param transMappingRoot the transformation MappingRoot * @return the Command languageObject */ public static String getSelectSql(final EObject transMappingRoot) { return getSqlString(transMappingRoot,QueryValidator.SELECT_TRNS); } /** * Determine if either the supplied user SQL is different than the cached Status SQL. If the cached * status is a uuid status, they are considered different. Otherwise a string comparison is done to determine * if they are different. * @param transMappingRoot the transformation MappingRoot * @param cmdType the command type (SELECT, INSERT, UPDATE, DELETE) * @param userSql the user SQL to compare to the cache * @return 'true' if the strings are different or cached is uuid, 'false' otherwise. */ public static boolean isSqlDifferent(final Object transMappingRoot,final int cmdType, final String userSql) { boolean isDifferent = true; if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { if(containsStatus((EObject)transMappingRoot,cmdType)) { // get status from the cache HashMap cache = getCache(cmdType); SqlTransformationResult status = (SqlTransformationResult)cache.get(transMappingRoot); // check whether the status is a uuid status or user status when doing comparison String cachedSql = status.getSqlString(); // If uuid status, use uuidSql for the comparison isDifferent = TransformationHelper.stringsDifferent(userSql,cachedSql); } } return isDifferent; } /** * Invalidate the Status for the cmd type, if it exists in the cache. This means that the next * time status is requested, the query will need to be parsed/resolved/validated. */ private static synchronized void invalidateStatus(final Object transMappingRoot, final int cmdType, final boolean notifyListeners, Object source, boolean overwriteDirty) { if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { if(containsStatus((EObject)transMappingRoot,cmdType)) { // Remove the status for the supplied command type removeStatus((EObject)transMappingRoot,cmdType); // If the command is a SELECT, then invalidate the others since they usually depend on SELECT if(cmdType==QueryValidator.SELECT_TRNS) { removeStatus((EObject)transMappingRoot,QueryValidator.INSERT_TRNS); removeStatus((EObject)transMappingRoot,QueryValidator.UPDATE_TRNS); removeStatus((EObject)transMappingRoot,QueryValidator.DELETE_TRNS); } if(source==null) { source = getInstance(); } } if(notifyListeners) { notifyEventListeners(new SqlTransformationStatusChangeEvent((EObject)transMappingRoot,source,overwriteDirty)); } } } /** * Get the Parsable State for the cmdType. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isParsable(final Object transMappingRoot,final int cmdType) { boolean isParsable = false; if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { // Get status (goes to cache first) SqlTransformationResult status = getStatus((EObject)transMappingRoot,cmdType,false); if(status!=null) { isParsable = status.isParsable(); } } return isParsable; } /** * Get the Resolvable State for the cmdType. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isResolvable(final Object transMappingRoot,final int cmdType) { boolean isResolvable = false; if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { // Get status (goes to cache first) SqlTransformationResult status = getStatus((EObject)transMappingRoot,cmdType,false); if(status!=null) { isResolvable = status.isResolvable(); } } return isResolvable; } /** * Get the Valid State for the cmdType. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isValid(final Object transMappingRoot,final int cmdType) { boolean isValid = false; if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { // Get status (goes to cache first) SqlTransformationResult status = getStatus((EObject)transMappingRoot,cmdType,false); if(status!=null) { isValid = status.isValidatable(); } } return isValid; } /** * Determine if the transformation has the supplied source group. * @param transMappingRoot the transformation MappingRoot * @param sourceGroup the source group to look for * @param cmdType the command type to look in. * @return 'true' if the transformation command type has the sourceGroup, 'false' if not. */ public static boolean hasSourceGroup(final Object transMappingRoot,final Object sourceGroup,final int cmdType) { boolean hasSourceGroup = false; if(transMappingRoot!=null && sourceGroup!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot) && TransformationHelper.isSqlTable(sourceGroup) ) { // Get status (goes to cache first) SqlTransformationResult status = getStatus((EObject)transMappingRoot,cmdType,false); if(status!=null) { Collection sourceGroups = status.getSourceGroups(); if(sourceGroups.contains(sourceGroup)) { hasSourceGroup = true; } } } return hasSourceGroup; } /** * Get the Valid State for the cmdType. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static boolean isTargetValid(final Object transMappingRoot,final int cmdType) { boolean isTargetValid = false; if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { // Get status (goes to cache first) SqlTransformationResult status = getStatus((EObject)transMappingRoot,cmdType,false); if(status!=null) { isTargetValid = status.isTargetValid(); } } return isTargetValid; } /** * Get the Valid Status for the transformation. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. */ public static IStatus getTargetValidStatus(final Object transMappingRoot,final int cmdType) { IStatus targetValidStatus = null; if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { // Get status (goes to cache first) SqlTransformationResult status = getStatus((EObject)transMappingRoot,cmdType,false); if(status!=null) { targetValidStatus = status.getTargetValidStatus(); } } return targetValidStatus; } /** * Get the Valid Status for the transformation. If the * status is not in the cache, the query will be parsed/resolved/validated and put in * the cache for next time. * * @param The transformation mapping root whose status is returned * @param cmdType The type of sql being validated * @param anyStatus A boolean if true returns a SqlTransformationResult which may be a status obtained * by validating UUID sql, else the status always contains user sql. * @param restrictSearch A boolean indicating if the search needs to be restricted to model imports * or if the whole workspace needs to be searched * @param context the ValidationContext to use; may be null */ public static SqlTransformationResult getSqlTransformationStatus(final SqlTransformationMappingRoot transMappingRoot, final int cmdType, final boolean restrictSearch, final ValidationContext context) { CoreArgCheck.isNotNull(transMappingRoot); return getStatus(transMappingRoot, cmdType, restrictSearch, context); } /** * Get the SELECT Command language object for the supplied TransformationMappingRoot. * @param transMappingRoot the transformation MappingRoot * @return the Command languageObject */ public static ICommand getCommand(final Object transMappingRoot,final int cmdType) { ICommand command = null; if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { // Get status (goes to cache first) SqlTransformationResult status = getStatus((EObject)transMappingRoot,cmdType,false); if(status!=null) { command = status.getCommand(); } } return command; } public static String getSqlString(final Object transMappingRoot,final int cmdType) { String sqlString = null; if(transMappingRoot!=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { // Get status (goes to cache first) SqlTransformationResult status = getStatus((EObject)transMappingRoot,cmdType,false); if(status!=null) { sqlString = status.getSqlString(); } } return sqlString; } /** * Determine if there is a cached result for the supplied MappingRoot and command type * @param transMappingRoot the mappingRoot * @param cmdType the command type (SELECT, INSERT, UPDATE, DELETE) * @return 'true' if the cache contains a result, 'false' if not. */ public static boolean containsStatus(final EObject transMappingRoot,final int cmdType) { HashMap cache = getCache(cmdType); return cache.containsKey(transMappingRoot); } /** * Remove the cached result for the supplied MappingRoot and command type * @param transMappingRoot the mappingRoot * @param cmdType the command type (SELECT, INSERT, UPDATE, DELETE) */ private static void removeStatus(final EObject transMappingRoot,final int cmdType) { //if( cmdType == QueryValidator.SELECT_TRNS) { // EObject target = TransformationHelper.getTransformationTarget(transMappingRoot); // System.out.println(" ===>> SqlMappingRootCache.removeStatus(TYPE=" + cmdType + ") Target = " + ModelerCore.getModelEditor().getName(target)); //} HashMap cache = getCache(cmdType); cache.remove(transMappingRoot); } /** * Create a status object for the mapping roots supplied commandType * @param transMappingRoot the transformation mapping root * @param cmdType The type of sql * @param statusType the type of status desired (EITHER_STATUS - either uuid or user is ok, USER_STATUS - * must be user status) * @param restrictSearch A boolean indicating if the search needs to be restricted to model imports * or if the whole workspace needs to be searched * @param context the ValidationContext to use; may be null */ private static SqlTransformationResult createStatus(final EObject transMappingRoot,final int cmdType, final boolean restrictSearch, final ValidationContext context) { SqlTransformationResult status = null; // Parse/Resolve/Validate the SQL if(transMappingRoot !=null && TransformationHelper.isSqlTransformationMappingRoot(transMappingRoot)) { // user sql string String userSql = null; // create a validator final TransformationValidator validator = (context != null ? new TransformationValidator((SqlTransformationMappingRoot)transMappingRoot, context, true, restrictSearch) : new TransformationValidator((SqlTransformationMappingRoot)transMappingRoot, true, restrictSearch)); //if this is workspace validation, validate the UUID sql if that does not validate validate the userSql // Any unexpected exception here creates invalid status and logs error try { // this is non-worspace validation just validate the user sql // get user Sql userSql = getSqlUserString(transMappingRoot, cmdType); //getConvertedSqlString(transMappingRoot, cmdType, restrictSearch, context); if(userSql != null) { status = (SqlTransformationResult) validator.validateSql(userSql, cmdType, false); } } catch (Exception e) { String message = TransformationPlugin.Util.getString("SqlMappingRootCache.validationError"); //$NON-NLS-1$ TransformationPlugin.Util.log(IStatus.ERROR, e, message); final IStatus fatalErrorStatus = new Status(IStatus.ERROR,TransformationPlugin.PLUGIN_ID,0,message,e); status = new SqlTransformationResult(null,fatalErrorStatus); status.setParsable(false); status.setResolvable(false); status.setValidatable(false); status.setSqlString(getSqlUserString(transMappingRoot,cmdType)); } } return status; } /** * Add a SELECT status object for a mappingRoot */ public static void setStatus(final EObject transMappingRoot,final int cmdType,final SqlTransformationResult status) { HashMap cache = getCache(cmdType); if(status!=null ) { //if( cmdType == QueryValidator.SELECT_TRNS) { // EObject target = TransformationHelper.getTransformationTarget(transMappingRoot); // System.out.println(" ===>> SqlMappingRootCache.setStatus(TYPE=" + cmdType + ") Target = " + ModelerCore.getModelEditor().getName(target)); //} cache.put(transMappingRoot,status); notifyEventListeners(new SqlTransformationStatusChangeEvent(transMappingRoot, new Object(), false)); } else { removeStatus(transMappingRoot,cmdType); } } /** * Get the SELECT status object (new status is created if not contained in cache) */ private static synchronized SqlTransformationResult getStatus(final EObject transMappingRoot, final int cmdType, final boolean restrictSearch) { return getStatus(transMappingRoot, cmdType, restrictSearch, null); } /** * Get the status object for the provided command type (new status is created if not contained in cache) * @param transMappingRoot the transformation mapping root * @param cmdType The type of sql command * @param statusType the type of status desired (EITHER_STATUS - either uuid or user is ok, USER_STATUS - * must be user status) * @param restrictSearch A boolean indicating if the search needs to be restricted to model imports * or if the whole workspace needs to be searched * @param context the ValidationContext to use; may be null */ private static synchronized SqlTransformationResult getStatus(final EObject transMappingRoot, final int cmdType, final boolean restrictSearch, final ValidationContext context) { SqlTransformationResult statusResult = null; // If there's a cached Status, try to use it if(containsStatus(transMappingRoot,cmdType)) { // get status from the cache HashMap cache = getCache(cmdType); SqlTransformationResult status = (SqlTransformationResult)cache.get(transMappingRoot); // If statusType is EITHER, use the cached status // If statusType is USER, check that the cached status is not a UUID Status if(status != null) { // if(statusType==EITHER_STATUS || // statusType==USER_STATUS && !status.isUUIDStatus()) { statusResult = status; // } } } // If a cached status not found, create it if(statusResult==null) { // Cache doesnt contain status or the status is a UUID status // This does a parse/resolve/validate on the SQL statusResult = createStatus(transMappingRoot, cmdType, restrictSearch, context); // when validating in editor etc context is null, cach in that case if(context == null || context.cacheMappingRootResults()) { // Add status to the cache setStatus(transMappingRoot,cmdType,statusResult); } } return statusResult; } /** * Get the Cache for the supplied command type */ private static HashMap getCache(final int cmdType) { switch (cmdType) { case QueryValidator.SELECT_TRNS: return selectSqlCache; case QueryValidator.INSERT_TRNS: return insertSqlCache; case QueryValidator.UPDATE_TRNS: return updateSqlCache; case QueryValidator.DELETE_TRNS: return deleteSqlCache; default: return null; } } /** * Get the SQL string, given a SqlTransformationMappingRoot and a command type * @param transMappingRoot the transformation mapping root * @param cmdType The command type whose user sql is to be returned. * @return the SQL UUID String */ private static String getSqlUserString(final Object transMappingRoot, final int cmdType) { switch (cmdType) { case QueryValidator.SELECT_TRNS: return getSelectSqlUserString(transMappingRoot); case QueryValidator.INSERT_TRNS: return getInsertSqlUserString(transMappingRoot); case QueryValidator.UPDATE_TRNS: return getUpdateSqlUserString(transMappingRoot); case QueryValidator.DELETE_TRNS: return getDeleteSqlUserString(transMappingRoot); default: return getSelectSqlUserString(transMappingRoot); } } /** * Get the SQL Select String, given a SqlTransformationMappingRoot * @param transMappingRoot the transformation mapping root * @return the SQL Select String */ private static String getSelectSqlUserString(final Object transMappingRoot) { SqlTransformation userSqlTransformation = TransformationHelper.getUserSqlTransformation(transMappingRoot); String result = null; if(userSqlTransformation!=null) { result = userSqlTransformation.getSelectSql(); } return result; } /** * Get the SQL Insert String, given a SqlTransformationMappingRoot * @param transMappingRoot the transformation mapping root * @return the SQL Insert String */ private static String getInsertSqlUserString(final Object transMappingRoot) { SqlTransformation userSqlTransformation = TransformationHelper.getUserSqlTransformation(transMappingRoot); String result = null; if(userSqlTransformation!=null) { result = userSqlTransformation.getInsertSql(); } return result; } /** * Get the SQL Update String, given a SqlTransformationMappingRoot * @param transMappingRoot the transformation mapping root * @return the SQL Update String */ private static String getUpdateSqlUserString(final Object transMappingRoot) { SqlTransformation userSqlTransformation = TransformationHelper.getUserSqlTransformation(transMappingRoot); String result = null; if(userSqlTransformation!=null) { result = userSqlTransformation.getUpdateSql(); } return result; } /** * Get the SQL Delete String, given a SqlTransformationMappingRoot * @param transMappingRoot the transformation mapping root * @return the SQL Delete String */ private static String getDeleteSqlUserString(final Object transMappingRoot) { SqlTransformation userSqlTransformation = TransformationHelper.getUserSqlTransformation(transMappingRoot); String result = null; if(userSqlTransformation!=null) { result = userSqlTransformation.getDeleteSql(); } return result; } //------------------------------------------------------------------------- // Methods to Register, UnRegister, Notify Listeners to Cache Change Events // Status Event is fired whenever the transformation is invalidated, // meaning that something has changed and it needs to be refreshed. //------------------------------------------------------------------------- /** * This method will register the listener for all SqlEditorEvents * @param listener the listener to be registered */ public static void addEventListener(EventObjectListener listener) { if (eventListeners == null) { eventListeners = new ArrayList(); } if(!eventListeners.contains(listener)) { eventListeners.add(listener); } } /** * This method will un-register the listener for all SqlEditorEvents * @param listener the listener to be un-registered */ public static void removeEventListener(EventObjectListener listener) { if (eventListeners != null) { eventListeners.remove(listener); } } /** * This method will notify the registered listeners of a SqlEditorEvent */ private static void notifyEventListeners(EventObject event) { if (eventListeners != null) { Iterator iterator = eventListeners.iterator(); while (iterator.hasNext()) { EventObjectListener listener = (EventObjectListener)iterator.next(); if (listener !=null) { listener.processEvent(event); } } } } }