/* * 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.relational.compare; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.designer.relational.RelationalConstants.TYPES; import org.teiid.designer.relational.model.RelationalModel; import org.teiid.designer.relational.model.RelationalReference; /** * DifferenceGenerator - generates a difference report, with the differences between two RelationalModels */ public class DifferenceGenerator { /** * Compare two Relational Models * @param targetModel the 'target' Model with the desired end state. * @param originalModel the 'original' Model * @return the difference report */ public static DifferenceReport compare(RelationalModel targetModel, RelationalModel originalModel) { DifferenceReport diffReport = new DifferenceReport(); // Get all Primary Objects for the final desired state Collection<RelationalReference> targetChildren = filterForPrimaryRefs(targetModel.getAllReferences()); // Get all Primary Objects for the existing state Collection<RelationalReference> originalChildren = filterForPrimaryRefs(originalModel.getAllReferences()); // The targetChildren will either be a create or a replace List<RelationalReference> objsToCreate = new ArrayList<RelationalReference>(); List<RelationalReference> objsToUpdate = new ArrayList<RelationalReference>(); List<RelationalReference> objsExactMatch = new ArrayList<RelationalReference>(); Iterator<RelationalReference> iter = targetChildren.iterator(); while(iter.hasNext()) { RelationalReference targetObj = iter.next(); RelationalReference nameTypeParentMatch = getNameTypeParentMatch(originalChildren,targetObj); // The Existing Collection has an object with matching name and type if(nameTypeParentMatch!=null) { // If not an exact match, put in replace list if(!nameTypeParentMatch.equals(targetObj)) { objsToUpdate.add(targetObj); // Exact match, do nothing with it } else { objsExactMatch.add(targetObj); } // No existing children with matching name/type - create it. } else { objsToCreate.add(targetObj); } } // Now determine which of the original objects need to be deleted List<RelationalReference> objsToDelete = new ArrayList<RelationalReference>(); iter = originalChildren.iterator(); while(iter.hasNext()) { RelationalReference origObj = iter.next(); RelationalReference matchObj = getNameTypeParentMatch(targetChildren,origObj); // If no name/type match in the target list, then its a delete if(matchObj==null) { objsToDelete.add(origObj); } } // Set lists on difference report diffReport.setObjectsToCreate(objsToCreate); diffReport.setObjectsToDelete(objsToDelete); diffReport.setObjectsToUpdate(objsToUpdate); return diffReport; } /** * Find a RelationalReference in the supplied list which matches another RelationalReference * @param refs the list of RelationalReference objects * @param ref a RelationalReference * @return the matching RelationalReference or null if none found */ private static RelationalReference getNameTypeParentMatch(Collection<RelationalReference> refs, RelationalReference ref) { RelationalReference result = null; for(RelationalReference listRef : refs) { if(nameTypeParentMatch(listRef,ref)) { result = listRef; break; } } return result; } /* * Determine if the name, type and parent of the supplied objects match */ private static boolean nameTypeParentMatch(RelationalReference ref1, RelationalReference ref2) { if(ref1==null || ref2==null) { return false; } // string properties if (!CoreStringUtil.valuesAreEqual(ref1.getName(), ref2.getName()) ) { return false; } if(ref1.getType() != ref2.getType()) { return false; } RelationalReference ref1Parent = ref1.getParent(); RelationalReference ref2Parent = ref2.getParent(); if(ref1Parent==null && ref2Parent==null) { return true; } if(ref1Parent==null || ref2Parent==null) { return false; } // Parent types if(ref1Parent.getType() != ref1Parent.getType()) { return false; } // Consider model parents equal if(ref1Parent.getType()==TYPES.MODEL) { return true; // Non-model, names must match } else if (!CoreStringUtil.valuesAreEqual(ref1Parent.getName(), ref1Parent.getName()) ) { return false; } return true; } /* * Make a list of only the 'primary' objects to create */ private static Collection<RelationalReference> filterForPrimaryRefs(Collection<RelationalReference> allRefs) { List<RelationalReference> filteredList = new ArrayList<RelationalReference>(); for(RelationalReference rRef : allRefs) { if(rRef!=null) { int refType = rRef.getType(); if(refType==TYPES.TABLE || refType==TYPES.PROCEDURE || refType==TYPES.VIEW || refType==TYPES.INDEX ) { filteredList.add(rRef); } } } return filteredList; } }