View Javadoc

1   /**
2    * Copyright 2011 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.common.impex.model.util;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.lang3.StringUtils;
24  import org.kuali.common.impex.model.Column;
25  import org.kuali.common.impex.model.ForeignKey;
26  import org.kuali.common.impex.model.Index;
27  import org.kuali.common.impex.model.NamedElement;
28  import org.kuali.common.impex.model.Schema;
29  import org.kuali.common.impex.model.Sequence;
30  import org.kuali.common.impex.model.Table;
31  import org.kuali.common.impex.model.UniqueConstraint;
32  import org.kuali.common.impex.model.View;
33  import org.kuali.common.impex.model.compare.ColumnDifference;
34  import org.kuali.common.impex.model.compare.ForeignKeyDifference;
35  import org.kuali.common.impex.model.compare.ForeignKeyDifferenceType;
36  import org.kuali.common.impex.model.compare.IndexDifference;
37  import org.kuali.common.impex.model.compare.MissingColumn;
38  import org.kuali.common.impex.model.compare.MissingForeignKey;
39  import org.kuali.common.impex.model.compare.MissingIndex;
40  import org.kuali.common.impex.model.compare.MissingSequence;
41  import org.kuali.common.impex.model.compare.MissingTable;
42  import org.kuali.common.impex.model.compare.MissingUniqueConstraint;
43  import org.kuali.common.impex.model.compare.MissingView;
44  import org.kuali.common.impex.model.compare.SequenceDifference;
45  import org.kuali.common.impex.model.compare.SequenceDifferenceType;
46  import org.kuali.common.impex.model.compare.TableDifference;
47  import org.kuali.common.impex.model.compare.TableDifferenceType;
48  import org.kuali.common.impex.model.compare.UniqueConstraintDifference;
49  import org.kuali.common.impex.model.compare.ViewDifference;
50  import org.kuali.common.impex.model.compare.ViewDifferenceType;
51  
52  public class CompareUtils {
53  
54      public static final int EXPECTED_MISSING_ELEMENTS_SET_COUNT = 2;
55  
56      public static Collection<ColumnDifference> compareColumns(Schema schema1, Table table1, Column col1, Schema schema2, Table table2, Column col2) {
57          Collection<ColumnDifference> results = new ArrayList<ColumnDifference>();
58  
59          // Check for data type difference
60          if (col1.getType() != col2.getType()) {
61              ColumnDifference dataTypeDiff = new ColumnDifference(schema1, table1, col1, schema2, table2, col2);
62              dataTypeDiff.setType(TableDifferenceType.COLUMN_DATA_TYPE);
63              results.add(dataTypeDiff);
64          }
65  
66          // check for primary key difference
67          if (col1.isPrimaryKey() != col2.isPrimaryKey()) {
68              ColumnDifference pkDiff = new ColumnDifference(schema1, table1, col1, schema2, table2, col2);
69              pkDiff.setType(TableDifferenceType.COLUMN_PRIMARY_KEY);
70              results.add(pkDiff);
71          }
72  
73          // check for nullable difference
74          if (col1.isNullable() != col2.isNullable()) {
75              ColumnDifference nullableDiff = new ColumnDifference(schema1, table1, col1, schema2, table2, col2);
76              nullableDiff.setType(TableDifferenceType.COLUMN_NULLABLE);
77              results.add(nullableDiff);
78          }
79  
80          // check for type size difference
81          if(!objectsEqual(col1.getSize(), col2.getSize())) {
82              ColumnDifference sizeDiff = new ColumnDifference(schema1, table1, col1, schema2, table2, col2);
83              sizeDiff.setType(TableDifferenceType.COLUMN_DATA_TYPE_SIZE);
84              results.add(sizeDiff);
85          }
86  
87          // check for description difference
88          if(!StringUtils.equals(col1.getDescription(), col2.getDescription())) {
89              ColumnDifference descDiff = new ColumnDifference(schema1, table1, col1, schema2, table2, col2);
90              descDiff.setType(TableDifferenceType.COLUMN_DESCRIPTION);
91              results.add(descDiff);
92          }
93  
94          // check for default value difference
95          if (!StringUtils.equals(col1.getDefaultValue(), col2.getDefaultValue())) {
96              ColumnDifference defaultDiff = new ColumnDifference(schema1, table1, col1, schema2, table2, col2);
97              defaultDiff.setType(TableDifferenceType.COLUMN_DEFAULT_VALUE);
98          }
99  
100         return results;
101     }
102 
103 
104     public static <T extends NamedElement> MissingElements<T> determineMissingElements(List<List<T>> sets) {
105 
106         MissingElements<T> results = new MissingElements<T>();
107 
108         if (sets.size() != EXPECTED_MISSING_ELEMENTS_SET_COUNT) {
109             throw new IllegalArgumentException("Map of sets is expected to have exactly " + EXPECTED_MISSING_ELEMENTS_SET_COUNT + " entries");
110         }
111 
112         List<T> set1Elements = sets.get(0);
113         List<T> set2Elements = sets.get(1);
114 
115         // Create a mapping of names to elements for set two
116         Map<String, T> set2NameMap = ModelUtils.buildNameMap(set2Elements);
117 
118         // Build a list of names in set 2 that are not in set 1
119         // This list is discovered by populating it first with the names of
120         // all elements in set 2, then removing each table name found in both sets
121         Collection<String> namesInSet2Only = set2NameMap.keySet();
122 
123         // Build comparison objects from the perspective of set 1
124         for (T n : set1Elements) {
125             // if this element is in set 1 and set 2
126             if (set2NameMap.containsKey(n.getName())) {
127                 // add this element's name to the list that is in both sets
128                 results.getBoth().add(new MatchingElement<T>(n, set2NameMap.get(n.getName())));
129 
130                 // remove the name from the list of names in set 2 only
131                 namesInSet2Only.remove(n.getName());
132             }
133             // if this element is only in set 1, add it to the set1Only list
134             else {
135                 results.getSet1Only().add(n);
136             }
137         }
138 
139         // add any elements in set2 that were not found in set1
140         for (String name : namesInSet2Only) {
141             results.getSet2Only().add(set2NameMap.get(name));
142         }
143 
144         return results;
145     }
146 
147 
148     public static Collection<UniqueConstraintDifference> compareUniqueConstraints(Schema schema1, Table table1, UniqueConstraint uniqueConstraint1, Schema schema2, Table table2, UniqueConstraint uniqueConstraint2) {
149         Collection<UniqueConstraintDifference> results = new ArrayList<UniqueConstraintDifference>();
150 
151         if (!uniqueConstraint1.getColumnNames().equals(uniqueConstraint2.getColumnNames())) {
152             UniqueConstraintDifference diff = new UniqueConstraintDifference(schema1, table1, uniqueConstraint1, schema2, table2, uniqueConstraint2);
153             diff.setType(TableDifferenceType.UNIQUE_CONSTRAINT_COLUMNS);
154             results.add(diff);
155         }
156 
157         return results;
158     }
159 
160     public static Collection<IndexDifference> compareIndices(Schema schema1, Table table1, Index index1, Schema schema2, Table table2, Index index2) {
161         Collection<IndexDifference> results = new ArrayList<IndexDifference>();
162 
163         if (!index1.getColumnNames().equals(index2.getColumnNames())) {
164             IndexDifference diff = new IndexDifference(schema1, table1, index1, schema2, table2, index2);
165             diff.setType(TableDifferenceType.INDEX_COLUMNS);
166             results.add(diff);
167         }
168 
169         if (index1.isUnique() != index2.isUnique()) {
170             IndexDifference diff = new IndexDifference(schema1, table1, index1, schema2, table2, index2);
171             diff.setType(TableDifferenceType.INDEX_UNIQUE);
172             results.add(diff);
173         }
174 
175         return results;
176     }
177 
178     public static Collection<ForeignKeyDifference> compareForeignKeys(Schema schema1, ForeignKey foreignKey1, Schema schema2, ForeignKey foreignKey2) {
179 
180         Collection<ForeignKeyDifference> results = new ArrayList<ForeignKeyDifference>();
181 
182         if (!StringUtils.equals(foreignKey1.getLocalTableName(), foreignKey2.getLocalTableName())) {
183             ForeignKeyDifference diff = new ForeignKeyDifference(schema1, foreignKey1, schema2, foreignKey2);
184             diff.setType(ForeignKeyDifferenceType.LOCAL_TABLE);
185             results.add(diff);
186         }
187 
188         if (!StringUtils.equals(foreignKey1.getForeignTableName(), foreignKey2.getForeignTableName())) {
189             ForeignKeyDifference diff = new ForeignKeyDifference(schema1, foreignKey1, schema2, foreignKey2);
190             diff.setType(ForeignKeyDifferenceType.FOREIGN_TABLE);
191             results.add(diff);
192         }
193 
194         if (!objectsEqual(foreignKey1.getLocalColumnNames(), foreignKey2.getLocalColumnNames())) {
195             ForeignKeyDifference diff = new ForeignKeyDifference(schema1, foreignKey1, schema2, foreignKey2);
196             diff.setType(ForeignKeyDifferenceType.LOCAL_COLUMNS);
197             results.add(diff);
198         }
199 
200         if (!objectsEqual(foreignKey1.getForeignColumnNames(), foreignKey2.getForeignColumnNames())) {
201             ForeignKeyDifference diff = new ForeignKeyDifference(schema1, foreignKey1, schema2, foreignKey2);
202             diff.setType(ForeignKeyDifferenceType.FOREIGN_COLUMNS);
203             results.add(diff);
204         }
205 
206         if (!objectsEqual(foreignKey1.getOnDelete(), foreignKey2.getOnDelete())) {
207             ForeignKeyDifference diff = new ForeignKeyDifference(schema1, foreignKey1, schema2, foreignKey2);
208             diff.setType(ForeignKeyDifferenceType.ON_DELETE);
209             results.add(diff);
210         }
211 
212         if (!objectsEqual(foreignKey1.getOnUpdate(), foreignKey2.getOnUpdate())) {
213             ForeignKeyDifference diff = new ForeignKeyDifference(schema1, foreignKey1, schema2, foreignKey2);
214             diff.setType(ForeignKeyDifferenceType.ON_UPDATE);
215             results.add(diff);
216         }
217 
218         return results;
219     }
220 
221     public static Collection<ViewDifference> compareViews(Schema schema1, View view1, Schema schema2, View view2) {
222         Collection<ViewDifference> results = new ArrayList<ViewDifference>();
223 
224         if(!StringUtils.equals(view1.getQueryString(), view2.getQueryString())) {
225             ViewDifference diff = new ViewDifference(schema1, view1, schema2, view2);
226             diff.setType(ViewDifferenceType.QUERY_STRING);
227             results.add(diff);
228         }
229 
230         return results;
231     }
232 
233     public static Collection<SequenceDifference> compareSequences(Schema schema1, Sequence seq1, Schema schema2, Sequence seq2) {
234         Collection<SequenceDifference> results = new ArrayList<SequenceDifference>();
235 
236         if (!StringUtils.equals(seq1.getStartValue(), seq2.getStartValue())) {
237             SequenceDifference diff = new SequenceDifference(schema1, seq1, schema2, seq2);
238             diff.setType(SequenceDifferenceType.START_VALUE);
239             results.add(diff);
240         }
241 
242         return results;
243     }
244 
245     private static boolean objectsEqual(Object o1, Object o2) {
246         if(o1 == null) {
247             return o2 == null;
248         }
249 
250         return o1.equals(o2);
251     }
252 
253     public static String tableDifferenceToString(TableDifference t) {
254         switch (t.getType()) {
255             case MISSING_TABLE:{
256                 MissingTable missing = (MissingTable) t;
257                 String foundToken = missing.getSourceSchema().getName() + DifferenceUtils.DOT + missing.getTable().getName();
258                 String notFoundToken = missing.getMissingSchema().getName();
259                 return DifferenceUtils.buildMissingElementToken(t.getType().getLabel(), foundToken, notFoundToken);
260             }
261             case MISSING_COLUMN: {
262                 MissingColumn missing = (MissingColumn) t;
263                 String foundToken = missing.getSourceSchema().getName() + DifferenceUtils.DOT + missing.getSourceTable().getName() + DifferenceUtils.DOT + missing.getColumn().getName();
264                 String notFoundToken = missing.getMissingSchema().getName() + DifferenceUtils.DOT + missing.getMissingTable().getName();
265                 return DifferenceUtils.buildMissingElementToken(t.getType().getLabel(), foundToken, notFoundToken);
266             }
267             case MISSING_INDEX: {
268                 MissingIndex missing = (MissingIndex) t;
269                 String foundToken = missing.getSourceSchema().getName() + DifferenceUtils.DOT + missing.getSourceTable().getName() + DifferenceUtils.DOT + missing.getIndex().getName();
270                 String notFoundToken = missing.getMissingSchema().getName() + DifferenceUtils.DOT + missing.getMissingTable().getName();
271                 return DifferenceUtils.buildMissingElementToken(t.getType().getLabel(), foundToken, notFoundToken);
272             }
273             case MISSING_UNIQUE_CONSTRAINT: {
274                 MissingUniqueConstraint missing = (MissingUniqueConstraint) t;
275                 String foundToken = missing.getSourceSchema().getName() + DifferenceUtils.DOT + missing.getSourceTable().getName() + DifferenceUtils.DOT + missing.getUniqueConstraint().getName();
276                 String notFoundToken = missing.getMissingSchema().getName() + DifferenceUtils.DOT + missing.getMissingTable().getName();
277                 return DifferenceUtils.buildMissingElementToken(t.getType().getLabel(), foundToken, notFoundToken);
278             }
279             default: {
280                 return DifferenceUtils.buildDifferenceToken(t.getType().getLabel(), t);
281             }
282         }
283     }
284 
285     public static String foreignKeyDifferenceToString(ForeignKeyDifference f) {
286         switch (f.getType()) {
287             case MISSING_FOREIGN_KEY: {
288                 MissingForeignKey missing = (MissingForeignKey) f;
289                 String foundToken = missing.getSourceSchema().getName() + DifferenceUtils.DOT + missing.getForeignKey().getName();
290                 String notFoundToken = missing.getMissingSchema().getName();
291                 return DifferenceUtils.buildMissingElementToken(f.getType().getLabel(), foundToken, notFoundToken);
292             }
293             default: {
294                 return DifferenceUtils.buildDifferenceToken(f.getType().getLabel(), f);
295             }
296         }
297     }
298 
299     public static String viewDifferenceToString(ViewDifference v) {
300         switch (v.getType()) {
301             case MISSING_VIEW: {
302                 MissingView missing = (MissingView) v;
303                 String foundToken = missing.getSourceSchema().getName() + DifferenceUtils.DOT + missing.getView().getName();
304                 String notFoundToken = missing.getMissingSchema().getName();
305                 return DifferenceUtils.buildMissingElementToken(v.getType().getLabel(), foundToken, notFoundToken);
306             }
307             default: {
308                 return DifferenceUtils.buildDifferenceToken(v.getType().getLabel(), v);
309             }
310         }
311     }
312 
313     public static String sequenceDifferenceToString(SequenceDifference s) {
314         switch (s.getType()) {
315             case MISSING_SEQUENCE: {
316                 MissingSequence missing = (MissingSequence) s;
317                 String foundToken = missing.getSourceSchema().getName() + DifferenceUtils.DOT + missing.getSequence().getName();
318                 String notFoundToken = missing.getMissingSchema().getName();
319                 return DifferenceUtils.buildMissingElementToken(s.getType().getLabel(), foundToken, notFoundToken);
320             }
321             default: {
322                 return DifferenceUtils.buildDifferenceToken(s.getType().getLabel(), s);
323             }
324         }
325     }
326 
327 }