1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.contract.model.impl;
17
18 import java.io.ByteArrayOutputStream;
19 import java.io.File;
20 import java.io.PrintStream;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import org.junit.After;
31 import org.junit.AfterClass;
32 import org.junit.Before;
33 import org.junit.BeforeClass;
34 import org.junit.Test;
35 import static org.junit.Assert.*;
36 import org.junit.Ignore;
37
38 import org.kuali.student.contract.model.MessageStructure;
39 import org.kuali.student.contract.model.Service;
40 import org.kuali.student.contract.model.ServiceContractModel;
41 import org.kuali.student.contract.model.ServiceMethod;
42 import org.kuali.student.contract.model.ServiceMethodParameter;
43 import org.kuali.student.contract.model.XmlType;
44 import org.kuali.student.contract.model.util.HtmlContractMessageStructureWriter;
45 import org.kuali.student.contract.model.util.ModelFinder;
46 import org.kuali.student.contract.model.validation.ServiceContractModelValidator;
47
48
49
50
51
52 @Ignore
53 public class M6M7ServiceContractComparisonTest {
54
55 public M6M7ServiceContractComparisonTest() {
56 }
57
58 @BeforeClass
59 public static void setUpClass() throws Exception {
60 }
61
62 @AfterClass
63 public static void tearDownClass() throws Exception {
64 }
65 private ByteArrayOutputStream baos;
66 private PrintStream out;
67
68 @Before
69 public void setUp() {
70 baos = new ByteArrayOutputStream();
71 out = new PrintStream(baos);
72
73 out.println("This section was created by programmatically comparing the message structures.");
74 out.println("Run on: " + new Date());
75 out.println("See [M6M7ServiceContractComparisonTest.java|https://test.kuali.org/svn/student/tools/maven-kscontractdoc-plugin/trunk/src/test/java/org/kuali/student/contract/model/impl/M6M7ServiceContractComparisonTest.java]");
76 out.println("");
77 out.println("Legend:");
78 out.println("* (-) Removed or dropped from contract");
79 out.println("* (+) Added to contract");
80 out.println("* (/) Renamed in contract");
81 out.println("* (*y) Change to contract");
82 out.println("* (!) Deprecated");
83 out.println("");
84 out.println("*TABLE OF CONTENTS*");
85 out.println("{toc}");
86 out.println("");
87 out.println("h1. Loading models of the contracts from the source code");
88 out.println("h2. Log from loading model for M6");
89 getModelM6();
90 out.println("h2. Log from loading model for M7");
91 getModelM7();
92 getFinderM6();
93 getFinderM7();
94 loadKnownObjectRenames();
95 loadKnownUnconvertedObjects();
96 loadKnownFieldRenames();
97 loadKnownFieldIssues();
98 loadKnownMethodRenames();
99 loadKnownMethodIssues();
100 }
101
102 @After
103 public void tearDown() {
104 if (baos != null) {
105 System.out.append(baos.toString());
106 }
107 }
108 private static final String RESOURCES_DIRECTORY = "src/test/resources";
109 private static final String TEST_SOURCE_DIRECTORY =
110 "src/test/java/org/kuali/student/contract/model/test/source";
111 private static final String M6_PROJECT_API_DIRECTORY = "D:/svn/ks/trunk/ks-api";
112 private static final String M6_COMMON_API_DIRECTORY = M6_PROJECT_API_DIRECTORY + "/ks-common-api/src/main/java";
113 private static final String M6_CORE_API_DIRECTORY = M6_PROJECT_API_DIRECTORY + "/ks-core-api/src/main/java";
114 private static final String M6_LUM_API_DIRECTORY = M6_PROJECT_API_DIRECTORY + "/ks-lum-api/src/main/java";
115 private static final String M6_ENROLL_API_DIRECTORY = M6_PROJECT_API_DIRECTORY + "/ks-enroll-api/src/main/java";
116 private static final String M7_PROJECT_API_DIRECTORY = "D:/svn/ks/services/ks-api";
117 private static final String M7_COMMON_API_DIRECTORY = M7_PROJECT_API_DIRECTORY + "/ks-common-api/src/main/java";
118 private static final String M7_CORE_API_DIRECTORY = M7_PROJECT_API_DIRECTORY + "/ks-core-api/src/main/java";
119 private static final String M7_LUM_API_DIRECTORY = M7_PROJECT_API_DIRECTORY + "/ks-lum-api/src/main/java";
120 private static final String M7_ENROLL_API_DIRECTORY = M7_PROJECT_API_DIRECTORY + "/ks-enroll-api/src/main/java";
121 private static ServiceContractModel modelM6 = null;
122 private static ServiceContractModel modelM7 = null;
123 private Map<String, String> knownMethodRenames = null;
124 private Map<String, String> knownFieldRenames = null;
125 private Map<String, String> knownMethodIssues = null;
126 private Map<String, String> knownUnconvertedObjects = null;
127
128
129
130
131
132 @Test
133 public void testCompareModels() {
134 out.println("");
135 out.println("h1. Message Structure Comparison");
136 compareTypes();
137 out.println("");
138 out.println("h1. Service Method Comparison");
139 compareMethods();
140 }
141
142 private ServiceContractModel getModelM6() {
143 if (modelM6 != null) {
144 return modelM6;
145 }
146 List<String> srcDirs = new ArrayList();
147 out.println("User directory=" + System.getProperty("user.dir"));
148 out.println("Current directory=" + new File(".").getAbsolutePath());
149 srcDirs.add(M6_COMMON_API_DIRECTORY);
150 srcDirs.add(M6_CORE_API_DIRECTORY);
151 srcDirs.add(M6_LUM_API_DIRECTORY);
152 srcDirs.add(M6_ENROLL_API_DIRECTORY);
153 out.println("Reading as input:");
154 for (String directory : srcDirs) {
155 out.println("* " + directory);
156 }
157 out.println("");
158 boolean validateKualiStudent = false;
159 ServiceContractModel instance = new ServiceContractModelQDoxLoader(srcDirs, validateKualiStudent);
160
161 instance = new ServiceContractModelCache(instance);
162 validate(instance);
163 modelM6 = instance;
164 return instance;
165 }
166
167 private ServiceContractModel getModelM7() {
168 if (modelM7 != null) {
169 return modelM7;
170 }
171 List<String> srcDirs = new ArrayList();
172 out.println("User directory=" + System.getProperty("user.dir"));
173 out.println("Current directory=" + new File(".").getAbsolutePath());
174 srcDirs.add(M7_COMMON_API_DIRECTORY);
175 srcDirs.add(M7_CORE_API_DIRECTORY);
176 srcDirs.add(M7_LUM_API_DIRECTORY);
177 srcDirs.add(M7_ENROLL_API_DIRECTORY);
178 out.println("Reading as input:");
179 for (String directory : srcDirs) {
180 out.println("* " + directory);
181 }
182 out.println("");
183 boolean validateKualiStudent = true;
184 ServiceContractModel instance = new ServiceContractModelQDoxLoader(srcDirs, validateKualiStudent);
185
186 instance = new ServiceContractModelCache(instance);
187 validate(instance);
188 modelM7 = instance;
189 return instance;
190 }
191
192 private String dump(ServiceMethod method) {
193 StringBuilder bldr = new StringBuilder();
194 bldr.append(method.getName());
195 String comma = "";
196 bldr.append("(");
197 for (ServiceMethodParameter param : method.getParameters()) {
198 bldr.append(comma);
199 comma = ", ";
200 bldr.append(param.getType());
201 bldr.append(" ");
202 bldr.append(param.getName());
203 }
204 bldr.append(")");
205 return bldr.toString();
206 }
207
208 private void validate(ServiceContractModel model) {
209 Collection<String> errors =
210 new ServiceContractModelValidator(model).validate();
211 if (errors.size() > 0) {
212 StringBuilder buf = new StringBuilder();
213 buf.append(errors.size()).append(" errors found while validating the data.");
214 int cnt = 0;
215 for (String msg : errors) {
216 cnt++;
217 buf.append("\n");
218 buf.append("*error*").append(cnt).append(":").append(msg);
219 }
220
221 fail(buf.toString());
222 }
223 }
224 private ModelFinder finderM6 = null;
225
226 private ModelFinder getFinderM6() {
227 if (finderM6 == null) {
228 finderM6 = new ModelFinder(getModelM6());
229 }
230 return finderM6;
231 }
232 private ModelFinder finderM7 = null;
233
234 private ModelFinder getFinderM7() {
235 if (finderM7 == null) {
236 finderM7 = new ModelFinder(getModelM7());
237 }
238 return finderM7;
239 }
240
241 private void compareTypes() {
242 for (Service service : modelM6.getServices()) {
243 Set<String> found = new LinkedHashSet<String>();
244 out.println("");
245 out.println("h2. " + service.getName() + " Structures");
246 for (XmlType xmlTypeM6 : finderM6.findAllComplexTypesInService(service.getKey())) {
247 XmlType xmlTypeM7 = findCompareType(xmlTypeM6);
248 if (xmlTypeM7 != null) {
249 found.add(xmlTypeM7.getName());
250 }
251 }
252 for (XmlType xmlTypeM7 : finderM7.findAllComplexTypesInService(service.getKey())) {
253 if (!found.contains(xmlTypeM7.getName())) {
254 out.println("# (+) " + xmlTypeM7.getName() + ": was added in M7");
255 }
256 }
257 }
258 }
259
260 private String calcService(XmlType xmlType) {
261 StringBuilder bldr = new StringBuilder();
262 String comma = "";
263 for (String serviceKey : HtmlContractMessageStructureWriter.calcUsageByService(modelM6, xmlType)) {
264 bldr.append(comma);
265 comma = ", ";
266 bldr.append(serviceKey);
267 }
268 return bldr.toString();
269 }
270
271 private String calcFieldNames(XmlType xmlType) {
272 StringBuilder bldr = new StringBuilder();
273 String comma = "";
274 for (MessageStructure ms : finderM7.findMessageStructures(xmlType.getName())) {
275 bldr.append(comma);
276 comma = ", ";
277 bldr.append(ms.getShortName());
278 }
279 return bldr.toString();
280 }
281
282 private void loadKnownUnconvertedObjects() {
283 Map<String, String> missings = new HashMap<String, String>();
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320 knownUnconvertedObjects = missings;
321 return;
322 }
323 private Map<String, String> knownObjectRenames = null;
324
325 private void loadKnownObjectRenames() {
326 Map<String, String> renames = new HashMap<String, String>();
327
328
329
330
331
332
333
334 knownObjectRenames = renames;
335 return;
336 }
337
338 private void loadKnownFieldRenames() {
339 Map<String, String> renames = new HashMap<String, String>();
340 renames.put("OrgCodeInfo.key", "OrgCodeInfo.typeKey");
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365 knownFieldRenames = renames;
366 return;
367 }
368 private Map<String, String> knownFieldIssues = null;
369
370 private void loadKnownFieldIssues() {
371 Map<String, String> issues = new HashMap<String, String>();
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406 knownFieldIssues = issues;
407 return;
408 }
409
410 private void loadKnownMethodRenames() {
411 Map<String, String> renames = new HashMap<String, String>();
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472 knownMethodRenames = renames;
473 return;
474 }
475
476 private void loadKnownMethodIssues() {
477 Map<String, String> issues = new HashMap<String, String>();
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519 knownMethodIssues = issues;
520 return;
521 }
522
523 private XmlType findType(XmlType m6) {
524 XmlType m7 = finderM7.findXmlType(m6.getName());
525 if (m7 == null) {
526 String renamedName = this.knownObjectRenames.get(m6.getName());
527 if (renamedName != null) {
528 m7 = finderM7.findXmlType(renamedName);
529 if (m7 == null) {
530 out.println("# (-) " + m6.getName() + ": was not found even after being renamed to " + renamedName);
531 return null;
532 }
533 out.println("# (/) " + m6.getName() + ": was renamed to " + renamedName);
534 return m7;
535 }
536 }
537
538
539
540
541
542 return m7;
543 }
544
545 private XmlType findCompareType(XmlType m6) {
546 if (m6.getName().endsWith("List")) {
547 return null;
548 }
549 if (this.knownUnconvertedObjects.containsKey(m6.getName())) {
550 String message = this.knownUnconvertedObjects.get(m6.getName());
551 if (message.isEmpty()) {
552 return null;
553 }
554 out.println("# (-) " + m6.getName() + ":" + message);
555 return null;
556 }
557 XmlType m7 = findType(m6);
558 if (m7 == null) {
559 out.println("# (-) " + m6.getName() + ": has no corresponding object in M7");
560 return m7;
561 }
562 Set<MessageStructure> usedInM7 = new HashSet<MessageStructure>();
563 for (MessageStructure ms : finderM6.findMessageStructures(m6.getName())) {
564 MessageStructure used = findCompareMessageStructure(ms, m7);
565 if (used != null) {
566 usedInM7.add(used);
567 }
568 }
569 return m7;
570 }
571
572 private MessageStructure findCompareMessageStructure(MessageStructure m6, XmlType xmlTypeM7) {
573 MessageStructure m7 = findMessageStructure(m6, xmlTypeM7);
574 String issue = this.knownFieldIssues.get(m6.getXmlObject() + "." + m6.getShortName());
575 if (issue != null) {
576 if (!issue.isEmpty()) {
577 out.println("# (*y) " + m6.getXmlObject() + "." + m6.getShortName() + ": " + issue);
578 }
579 return m7;
580 }
581 if (m7 == null) {
582 out.println("# (-) " + m6.getXmlObject() + "." + m6.getShortName() + " not found in M7: perhaps it was renamed to one of these? " + calcFieldNames(xmlTypeM7));
583 return null;
584 }
585 compareType(m6, m7);
586 compareDeprecation(m6, m7);
587 return m7;
588 }
589
590 private void compareType(MessageStructure m6, MessageStructure m7) {
591 if (m6.getType().equalsIgnoreCase(m7.getType())) {
592 return;
593 }
594 out.println("# (*y) " + m6.getXmlObject() + "." + m6.getShortName() + ": the type was changed from " + m6.getType() + " to " + m7.getType());
595 }
596
597 private void compareDeprecation(MessageStructure m6, MessageStructure m7) {
598 if (m6.isDeprecated() && m7.isDeprecated()) {
599 return;
600 }
601 if (!m6.isDeprecated() && !m7.isDeprecated()) {
602 return;
603 }
604 if (!m6.isDeprecated() && m7.isDeprecated()) {
605 out.println("# (!) " + m6.getXmlObject() + "." + m6.getShortName() + " has been deprecated and may be removed in future releases");
606 return;
607 }
608
609 if (m6.isDeprecated() && !m7.isDeprecated()) {
610 out.println("# (!) " + m6.getXmlObject() + "." + m6.getShortName() + " had been dedprecated but is no longer marked as such");
611 return;
612 }
613 throw new RuntimeException("should never reach here");
614 }
615
616 private MessageStructure findMessageStructure(MessageStructure m6, XmlType xmlTypeM7) {
617 MessageStructure m7 = finderM7.findMessageStructure(xmlTypeM7.getName(), m6.getShortName());
618 if (m7 == null) {
619 String renamed = this.knownFieldRenames.get(m6.getShortName());
620 if (renamed != null) {
621 m7 = finderM7.findMessageStructure(xmlTypeM7.getName(), renamed);
622 if (m7 == null) {
623 out.println("# (-) " + m6.getXmlObject() + "." + m6.getShortName()
624 + " was renamed to " + xmlTypeM7.getName() + "." + renamed
625 + " BUT IT STILL DIDN'T EXIST IN M7");
626 return null;
627 }
628 out.println("# (*y) " + m6.getXmlObject() + "." + m6.getShortName()
629 + " was renamed to " + xmlTypeM7.getName() + "." + renamed);
630 }
631 }
632 return m7;
633 }
634
635 private void compareMethods() {
636 for (Service service : modelM6.getServices()) {
637 Set<String> found = new LinkedHashSet<String>();
638 out.println("");
639 out.println("h2. " + service.getName() + " Methods");
640 List<ServiceMethod> methodsInService = finderM6.findServiceMethods(service.getKey());
641 for (ServiceMethod method : methodsInService) {
642 ServiceMethod methodM7 = findCompareMethod(method);
643 if (methodM7 != null) {
644 found.add(methodM7.getName());
645 }
646 }
647 for (ServiceMethod methodM7 : finderM7.findServiceMethods(service.getKey())) {
648 if (!found.contains(methodM7.getName())) {
649 out.println("# (+) " + methodM7.getName() + ": was added in M7");
650 }
651 }
652 }
653 }
654
655 private ServiceMethod findCompareMethod(ServiceMethod methodM6) {
656 String issue = knownMethodIssues.get(methodM6.getService() + "Service." + methodM6.getName());
657 if (issue != null) {
658 if (!issue.isEmpty()) {
659 out.println("# (*y) " + methodM6.getService() + "Service." + methodM6.getName()
660 + ": " + issue);
661 }
662 return null;
663 }
664 ServiceMethod methodM7 = findMethod(methodM6);
665 if (methodM7 == null) {
666 String possibleMethods = this.calcPossibleMethods(methodM6);
667 if (possibleMethods.isEmpty()) {
668 out.println("# (-) " + methodM6.getService() + "Service." + methodM6.getName()
669 + " could not be found in M7");
670 } else {
671 out.println("# (-) " + methodM6.getService() + "Service." + methodM6.getName()
672 + " does not exist in M7. It might have been renamed to one of these: "
673 + possibleMethods);
674 }
675 return null;
676 }
677 if (!methodM6.getName().equals(methodM7.getName())) {
678 out.println("# (*y) " + methodM6.getService() + "Service." + methodM6.getName()
679 + " was renamed to " + methodM7.getService() + "Service." + methodM7.getName());
680 }
681 if (!doAllParametersMatch(methodM6, methodM7)) {
682 out.print("# (*y) " + methodM6.getService() + "Service." + methodM6.getName()
683 + " parameters changed from (");
684 String comma = "";
685 for (ServiceMethodParameter param : methodM6.getParameters()) {
686 out.print (comma);
687 comma = ", ";
688 out.print (param.getType() + " " + param.getName());
689 }
690 out.print (") to (");
691 comma = "";
692 for (ServiceMethodParameter param : methodM7.getParameters()) {
693 out.print (comma);
694 comma = ", ";
695 out.print (param.getType() + " " + param.getName());
696 }
697 out.println (")");
698 }
699 return methodM7;
700 }
701
702 private boolean doAllParametersMatch(ServiceMethod methodM6, ServiceMethod methodM7) {
703 if (methodM6.getParameters().size() != methodM7.getParameters().size()) {
704 return false;
705 }
706 for (int i = 0; i < methodM6.getParameters().size(); i++) {
707 ServiceMethodParameter paramM6 = methodM6.getParameters().get(i);
708 ServiceMethodParameter paramM7 = methodM7.getParameters().get(i);
709 if (!doParametersMatch(paramM6, paramM7)) {
710 return false;
711 }
712 }
713 return true;
714 }
715
716 private boolean doParametersMatch(ServiceMethodParameter paramM6, ServiceMethodParameter paramM7) {
717 if (!paramM6.getName().equals(paramM7.getName())) {
718 return false;
719 }
720 if (!paramM6.getType().equals(paramM7.getType())) {
721 return false;
722 }
723 return true;
724 }
725
726 private ServiceMethod findMethod(ServiceMethod method1) {
727 ServiceMethod method2 = findMethod2(method1.getService(), method1.getName());
728 if (method2 == null) {
729 String methodRename = knownMethodRenames.get(method1.getService() + "Service." + method1.getName());
730 if (methodRename != null) {
731 method2 = findMethod2(method1.getService(), methodRename);
732 if (method2 == null) {
733 out.println("# (-) " + method1.getService() + "Service." + method1.getName()
734 + " could not be found even after being renamed to " + methodRename);
735 return null;
736 }
737 }
738 }
739 return method2;
740 }
741
742 private ServiceMethod findMethod2(String serviceKey, String methodName) {
743 ServiceMethod method2 = finderM7.findServiceMethod(serviceKey, methodName);
744 if (method2 == null) {
745 if (serviceKey.equals("Lu")) {
746 method2 = finderM7.findServiceMethod("Clu", methodName);
747 if (method2 == null) {
748 method2 = finderM7.findServiceMethod("Lui", methodName);
749 }
750 }
751 }
752 return method2;
753 }
754
755 private String calcMethods(ServiceMethod method1) {
756 StringBuilder bldr = new StringBuilder();
757 String comma = "";
758 for (ServiceMethod method2 : finderM7.findServiceMethods(method1.getService())) {
759 bldr.append(comma);
760 comma = ", ";
761 bldr.append(method2.getName());
762 }
763 return bldr.toString();
764 }
765
766 private String calcPossibleMethods(ServiceMethod method1) {
767 StringBuilder bldr = new StringBuilder();
768 String comma = "";
769 for (ServiceMethod method2 : findPossibleMethods(method1)) {
770 bldr.append(comma);
771 comma = ", ";
772 bldr.append(method2.getName());
773 }
774 return bldr.toString();
775 }
776
777 private List<ServiceMethod> findPossibleMethods(ServiceMethod method1) {
778 List<ServiceMethod> methods = new ArrayList<ServiceMethod>();
779 List<ServiceMethod> wideNet = null;
780
781
782
783
784 wideNet = finderM7.findServiceMethods(method1.getService());
785
786 for (ServiceMethod method2 : wideNet) {
787 if (isPossibleMatch(method1, method2)) {
788 methods.add(method2);
789 }
790 }
791 return methods;
792 }
793
794 private boolean isPossibleMatch(ServiceMethod method1, ServiceMethod method2) {
795 if (method1.getName().contains(method2.getName())) {
796 return true;
797 }
798 if (method2.getName().contains(method1.getName())) {
799 return true;
800 }
801 if (method1.getName().startsWith("get") && method2.getName().startsWith("get")) {
802 return true;
803 }
804 if (method1.getName().startsWith("add") && method2.getName().startsWith("create")) {
805 return true;
806 }
807 if (method1.getName().startsWith("create") && method2.getName().startsWith("create")) {
808 return true;
809 }
810 if (method1.getName().startsWith("update") && method2.getName().startsWith("update")) {
811 return true;
812 }
813 if (method1.getName().startsWith("delete") && method2.getName().startsWith("delete")) {
814 return true;
815 }
816 if (method1.getName().startsWith("remove") && method2.getName().startsWith("delete")) {
817 return true;
818 }
819 if (method1.getName().startsWith("validate") && method2.getName().startsWith("validate")) {
820 return true;
821 }
822 return false;
823 }
824 }