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 ServiceContractModel instance = new ServiceContractModelQDoxLoader(srcDirs);
159
160 instance = new ServiceContractModelCache(instance);
161 validate(instance);
162 modelM6 = instance;
163 return instance;
164 }
165
166 private ServiceContractModel getModelM7() {
167 if (modelM7 != null) {
168 return modelM7;
169 }
170 List<String> srcDirs = new ArrayList();
171 out.println("User directory=" + System.getProperty("user.dir"));
172 out.println("Current directory=" + new File(".").getAbsolutePath());
173 srcDirs.add(M7_COMMON_API_DIRECTORY);
174 srcDirs.add(M7_CORE_API_DIRECTORY);
175 srcDirs.add(M7_LUM_API_DIRECTORY);
176 srcDirs.add(M7_ENROLL_API_DIRECTORY);
177 out.println("Reading as input:");
178 for (String directory : srcDirs) {
179 out.println("* " + directory);
180 }
181 out.println("");
182 ServiceContractModel instance = new ServiceContractModelQDoxLoader(srcDirs);
183
184 instance = new ServiceContractModelCache(instance);
185 validate(instance);
186 modelM7 = instance;
187 return instance;
188 }
189
190 private String dump(ServiceMethod method) {
191 StringBuilder bldr = new StringBuilder();
192 bldr.append(method.getName());
193 String comma = "";
194 bldr.append("(");
195 for (ServiceMethodParameter param : method.getParameters()) {
196 bldr.append(comma);
197 comma = ", ";
198 bldr.append(param.getType());
199 bldr.append(" ");
200 bldr.append(param.getName());
201 }
202 bldr.append(")");
203 return bldr.toString();
204 }
205
206 private void validate(ServiceContractModel model) {
207 Collection<String> errors =
208 new ServiceContractModelValidator(model).validate();
209 if (errors.size() > 0) {
210 StringBuilder buf = new StringBuilder();
211 buf.append(errors.size()).append(" errors found while validating the data.");
212 int cnt = 0;
213 for (String msg : errors) {
214 cnt++;
215 buf.append("\n");
216 buf.append("*error*").append(cnt).append(":").append(msg);
217 }
218
219 fail(buf.toString());
220 }
221 }
222 private ModelFinder finderM6 = null;
223
224 private ModelFinder getFinderM6() {
225 if (finderM6 == null) {
226 finderM6 = new ModelFinder(getModelM6());
227 }
228 return finderM6;
229 }
230 private ModelFinder finderM7 = null;
231
232 private ModelFinder getFinderM7() {
233 if (finderM7 == null) {
234 finderM7 = new ModelFinder(getModelM7());
235 }
236 return finderM7;
237 }
238
239 private void compareTypes() {
240 for (Service service : modelM6.getServices()) {
241 Set<String> found = new LinkedHashSet<String>();
242 out.println("");
243 out.println("h2. " + service.getName() + " Structures");
244 for (XmlType xmlTypeM6 : finderM6.findAllComplexTypesInService(service.getKey())) {
245 XmlType xmlTypeM7 = findCompareType(xmlTypeM6);
246 if (xmlTypeM7 != null) {
247 found.add(xmlTypeM7.getName());
248 }
249 }
250 for (XmlType xmlTypeM7 : finderM7.findAllComplexTypesInService(service.getKey())) {
251 if (!found.contains(xmlTypeM7.getName())) {
252 out.println("# (+) " + xmlTypeM7.getName() + ": was added in M7");
253 }
254 }
255 }
256 }
257
258 private String calcService(XmlType xmlType) {
259 StringBuilder bldr = new StringBuilder();
260 String comma = "";
261 for (String serviceKey : HtmlContractMessageStructureWriter.calcUsageByService(modelM6, xmlType)) {
262 bldr.append(comma);
263 comma = ", ";
264 bldr.append(serviceKey);
265 }
266 return bldr.toString();
267 }
268
269 private String calcFieldNames(XmlType xmlType) {
270 StringBuilder bldr = new StringBuilder();
271 String comma = "";
272 for (MessageStructure ms : finderM7.findMessageStructures(xmlType.getName())) {
273 bldr.append(comma);
274 comma = ", ";
275 bldr.append(ms.getShortName());
276 }
277 return bldr.toString();
278 }
279
280 private void loadKnownUnconvertedObjects() {
281 Map<String, String> missings = new HashMap<String, String>();
282
283
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 knownUnconvertedObjects = missings;
319 return;
320 }
321 private Map<String, String> knownObjectRenames = null;
322
323 private void loadKnownObjectRenames() {
324 Map<String, String> renames = new HashMap<String, String>();
325
326
327
328
329
330
331
332 knownObjectRenames = renames;
333 return;
334 }
335
336 private void loadKnownFieldRenames() {
337 Map<String, String> renames = new HashMap<String, String>();
338 renames.put("OrgCodeInfo.key", "OrgCodeInfo.typeKey");
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363 knownFieldRenames = renames;
364 return;
365 }
366 private Map<String, String> knownFieldIssues = null;
367
368 private void loadKnownFieldIssues() {
369 Map<String, String> issues = new HashMap<String, String>();
370
371
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 knownFieldIssues = issues;
405 return;
406 }
407
408 private void loadKnownMethodRenames() {
409 Map<String, String> renames = new HashMap<String, String>();
410
411
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 knownMethodRenames = renames;
471 return;
472 }
473
474 private void loadKnownMethodIssues() {
475 Map<String, String> issues = new HashMap<String, String>();
476
477
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 knownMethodIssues = issues;
518 return;
519 }
520
521 private XmlType findType(XmlType m6) {
522 XmlType m7 = finderM7.findXmlType(m6.getName());
523 if (m7 == null) {
524 String renamedName = this.knownObjectRenames.get(m6.getName());
525 if (renamedName != null) {
526 m7 = finderM7.findXmlType(renamedName);
527 if (m7 == null) {
528 out.println("# (-) " + m6.getName() + ": was not found even after being renamed to " + renamedName);
529 return null;
530 }
531 out.println("# (/) " + m6.getName() + ": was renamed to " + renamedName);
532 return m7;
533 }
534 }
535
536
537
538
539
540 return m7;
541 }
542
543 private XmlType findCompareType(XmlType m6) {
544 if (m6.getName().endsWith("List")) {
545 return null;
546 }
547 if (this.knownUnconvertedObjects.containsKey(m6.getName())) {
548 String message = this.knownUnconvertedObjects.get(m6.getName());
549 if (message.isEmpty()) {
550 return null;
551 }
552 out.println("# (-) " + m6.getName() + ":" + message);
553 return null;
554 }
555 XmlType m7 = findType(m6);
556 if (m7 == null) {
557 out.println("# (-) " + m6.getName() + ": has no corresponding object in M7");
558 return m7;
559 }
560 Set<MessageStructure> usedInM7 = new HashSet<MessageStructure>();
561 for (MessageStructure ms : finderM6.findMessageStructures(m6.getName())) {
562 MessageStructure used = findCompareMessageStructure(ms, m7);
563 if (used != null) {
564 usedInM7.add(used);
565 }
566 }
567 return m7;
568 }
569
570 private MessageStructure findCompareMessageStructure(MessageStructure m6, XmlType xmlTypeM7) {
571 MessageStructure m7 = findMessageStructure(m6, xmlTypeM7);
572 String issue = this.knownFieldIssues.get(m6.getXmlObject() + "." + m6.getShortName());
573 if (issue != null) {
574 if (!issue.isEmpty()) {
575 out.println("# (*y) " + m6.getXmlObject() + "." + m6.getShortName() + ": " + issue);
576 }
577 return m7;
578 }
579 if (m7 == null) {
580 out.println("# (-) " + m6.getXmlObject() + "." + m6.getShortName() + " not found in M7: perhaps it was renamed to one of these? " + calcFieldNames(xmlTypeM7));
581 return null;
582 }
583 compareType(m6, m7);
584 compareDeprecation(m6, m7);
585 return m7;
586 }
587
588 private void compareType(MessageStructure m6, MessageStructure m7) {
589 if (m6.getType().equalsIgnoreCase(m7.getType())) {
590 return;
591 }
592 out.println("# (*y) " + m6.getXmlObject() + "." + m6.getShortName() + ": the type was changed from " + m6.getType() + " to " + m7.getType());
593 }
594
595 private void compareDeprecation(MessageStructure m6, MessageStructure m7) {
596 if (m6.isDeprecated() && m7.isDeprecated()) {
597 return;
598 }
599 if (!m6.isDeprecated() && !m7.isDeprecated()) {
600 return;
601 }
602 if (!m6.isDeprecated() && m7.isDeprecated()) {
603 out.println("# (!) " + m6.getXmlObject() + "." + m6.getShortName() + " has been deprecated and may be removed in future releases");
604 return;
605 }
606
607 if (m6.isDeprecated() && !m7.isDeprecated()) {
608 out.println("# (!) " + m6.getXmlObject() + "." + m6.getShortName() + " had been dedprecated but is no longer marked as such");
609 return;
610 }
611 throw new RuntimeException("should never reach here");
612 }
613
614 private MessageStructure findMessageStructure(MessageStructure m6, XmlType xmlTypeM7) {
615 MessageStructure m7 = finderM7.findMessageStructure(xmlTypeM7.getName(), m6.getShortName());
616 if (m7 == null) {
617 String renamed = this.knownFieldRenames.get(m6.getShortName());
618 if (renamed != null) {
619 m7 = finderM7.findMessageStructure(xmlTypeM7.getName(), renamed);
620 if (m7 == null) {
621 out.println("# (-) " + m6.getXmlObject() + "." + m6.getShortName()
622 + " was renamed to " + xmlTypeM7.getName() + "." + renamed
623 + " BUT IT STILL DIDN'T EXIST IN M7");
624 return null;
625 }
626 out.println("# (*y) " + m6.getXmlObject() + "." + m6.getShortName()
627 + " was renamed to " + xmlTypeM7.getName() + "." + renamed);
628 }
629 }
630 return m7;
631 }
632
633 private void compareMethods() {
634 for (Service service : modelM6.getServices()) {
635 Set<String> found = new LinkedHashSet<String>();
636 out.println("");
637 out.println("h2. " + service.getName() + " Methods");
638 List<ServiceMethod> methodsInService = finderM6.findServiceMethods(service.getKey());
639 for (ServiceMethod method : methodsInService) {
640 ServiceMethod methodM7 = findCompareMethod(method);
641 if (methodM7 != null) {
642 found.add(methodM7.getName());
643 }
644 }
645 for (ServiceMethod methodM7 : finderM7.findServiceMethods(service.getKey())) {
646 if (!found.contains(methodM7.getName())) {
647 out.println("# (+) " + methodM7.getName() + ": was added in M7");
648 }
649 }
650 }
651 }
652
653 private ServiceMethod findCompareMethod(ServiceMethod methodM6) {
654 String issue = knownMethodIssues.get(methodM6.getService() + "Service." + methodM6.getName());
655 if (issue != null) {
656 if (!issue.isEmpty()) {
657 out.println("# (*y) " + methodM6.getService() + "Service." + methodM6.getName()
658 + ": " + issue);
659 }
660 return null;
661 }
662 ServiceMethod methodM7 = findMethod(methodM6);
663 if (methodM7 == null) {
664 String possibleMethods = this.calcPossibleMethods(methodM6);
665 if (possibleMethods.isEmpty()) {
666 out.println("# (-) " + methodM6.getService() + "Service." + methodM6.getName()
667 + " could not be found in M7");
668 } else {
669 out.println("# (-) " + methodM6.getService() + "Service." + methodM6.getName()
670 + " does not exist in M7. It might have been renamed to one of these: "
671 + possibleMethods);
672 }
673 return null;
674 }
675 if (!methodM6.getName().equals(methodM7.getName())) {
676 out.println("# (*y) " + methodM6.getService() + "Service." + methodM6.getName()
677 + " was renamed to " + methodM7.getService() + "Service." + methodM7.getName());
678 }
679 if (!doAllParametersMatch(methodM6, methodM7)) {
680 out.print("# (*y) " + methodM6.getService() + "Service." + methodM6.getName()
681 + " parameters changed from (");
682 String comma = "";
683 for (ServiceMethodParameter param : methodM6.getParameters()) {
684 out.print (comma);
685 comma = ", ";
686 out.print (param.getType() + " " + param.getName());
687 }
688 out.print (") to (");
689 comma = "";
690 for (ServiceMethodParameter param : methodM7.getParameters()) {
691 out.print (comma);
692 comma = ", ";
693 out.print (param.getType() + " " + param.getName());
694 }
695 out.println (")");
696 }
697 return methodM7;
698 }
699
700 private boolean doAllParametersMatch(ServiceMethod methodM6, ServiceMethod methodM7) {
701 if (methodM6.getParameters().size() != methodM7.getParameters().size()) {
702 return false;
703 }
704 for (int i = 0; i < methodM6.getParameters().size(); i++) {
705 ServiceMethodParameter paramM6 = methodM6.getParameters().get(i);
706 ServiceMethodParameter paramM7 = methodM7.getParameters().get(i);
707 if (!doParametersMatch(paramM6, paramM7)) {
708 return false;
709 }
710 }
711 return true;
712 }
713
714 private boolean doParametersMatch(ServiceMethodParameter paramM6, ServiceMethodParameter paramM7) {
715 if (!paramM6.getName().equals(paramM7.getName())) {
716 return false;
717 }
718 if (!paramM6.getType().equals(paramM7.getType())) {
719 return false;
720 }
721 return true;
722 }
723
724 private ServiceMethod findMethod(ServiceMethod method1) {
725 ServiceMethod method2 = findMethod2(method1.getService(), method1.getName());
726 if (method2 == null) {
727 String methodRename = knownMethodRenames.get(method1.getService() + "Service." + method1.getName());
728 if (methodRename != null) {
729 method2 = findMethod2(method1.getService(), methodRename);
730 if (method2 == null) {
731 out.println("# (-) " + method1.getService() + "Service." + method1.getName()
732 + " could not be found even after being renamed to " + methodRename);
733 return null;
734 }
735 }
736 }
737 return method2;
738 }
739
740 private ServiceMethod findMethod2(String serviceKey, String methodName) {
741 ServiceMethod method2 = finderM7.findServiceMethod(serviceKey, methodName);
742 if (method2 == null) {
743 if (serviceKey.equals("Lu")) {
744 method2 = finderM7.findServiceMethod("Clu", methodName);
745 if (method2 == null) {
746 method2 = finderM7.findServiceMethod("Lui", methodName);
747 }
748 }
749 }
750 return method2;
751 }
752
753 private String calcMethods(ServiceMethod method1) {
754 StringBuilder bldr = new StringBuilder();
755 String comma = "";
756 for (ServiceMethod method2 : finderM7.findServiceMethods(method1.getService())) {
757 bldr.append(comma);
758 comma = ", ";
759 bldr.append(method2.getName());
760 }
761 return bldr.toString();
762 }
763
764 private String calcPossibleMethods(ServiceMethod method1) {
765 StringBuilder bldr = new StringBuilder();
766 String comma = "";
767 for (ServiceMethod method2 : findPossibleMethods(method1)) {
768 bldr.append(comma);
769 comma = ", ";
770 bldr.append(method2.getName());
771 }
772 return bldr.toString();
773 }
774
775 private List<ServiceMethod> findPossibleMethods(ServiceMethod method1) {
776 List<ServiceMethod> methods = new ArrayList<ServiceMethod>();
777 List<ServiceMethod> wideNet = null;
778
779
780
781
782 wideNet = finderM7.findServiceMethods(method1.getService());
783
784 for (ServiceMethod method2 : wideNet) {
785 if (isPossibleMatch(method1, method2)) {
786 methods.add(method2);
787 }
788 }
789 return methods;
790 }
791
792 private boolean isPossibleMatch(ServiceMethod method1, ServiceMethod method2) {
793 if (method1.getName().contains(method2.getName())) {
794 return true;
795 }
796 if (method2.getName().contains(method1.getName())) {
797 return true;
798 }
799 if (method1.getName().startsWith("get") && method2.getName().startsWith("get")) {
800 return true;
801 }
802 if (method1.getName().startsWith("add") && method2.getName().startsWith("create")) {
803 return true;
804 }
805 if (method1.getName().startsWith("create") && method2.getName().startsWith("create")) {
806 return true;
807 }
808 if (method1.getName().startsWith("update") && method2.getName().startsWith("update")) {
809 return true;
810 }
811 if (method1.getName().startsWith("delete") && method2.getName().startsWith("delete")) {
812 return true;
813 }
814 if (method1.getName().startsWith("remove") && method2.getName().startsWith("delete")) {
815 return true;
816 }
817 if (method1.getName().startsWith("validate") && method2.getName().startsWith("validate")) {
818 return true;
819 }
820 return false;
821 }
822 }