View Javadoc

1   /*
2    * Copyright 2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may	obtain a copy of the License at
7    *
8    * 	http://www.osedu.org/licenses/ECL-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.student.contract.model.impl;
17  
18  import java.io.File;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Date;
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  import org.junit.After;
28  import org.junit.AfterClass;
29  import org.junit.Before;
30  import org.junit.BeforeClass;
31  import org.junit.Test;
32  import static org.junit.Assert.*;
33  import org.junit.Ignore;
34  
35  import org.kuali.student.contract.model.MessageStructure;
36  import org.kuali.student.contract.model.Service;
37  import org.kuali.student.contract.model.ServiceContractModel;
38  import org.kuali.student.contract.model.ServiceMethod;
39  import org.kuali.student.contract.model.ServiceMethodParameter;
40  import org.kuali.student.contract.model.XmlType;
41  import org.kuali.student.contract.model.util.HtmlContractMessageStructureWriter;
42  import org.kuali.student.contract.model.util.ModelFinder;
43  import org.kuali.student.contract.model.validation.ServiceContractModelValidator;
44  
45  /**
46   *
47   * @author nwright
48   */
49  @Ignore
50  public class R1R2ServiceContractComparisonTest {
51  
52      public R1R2ServiceContractComparisonTest() {
53      }
54  
55      @BeforeClass
56      public static void setUpClass() throws Exception {
57      }
58  
59      @AfterClass
60      public static void tearDownClass() throws Exception {
61      }
62  
63      @Before
64      public void setUp() {
65  
66          System.out.println("This section was created by programmatically comparing the message structures.");
67          System.out.println("Run on: " + new Date());
68          System.out.println("See [R1R2ServiceContractComparisonTest.java|https://test.kuali.org/svn/student/tools/maven-kscontractdoc-plugin/trunk/src/test/java/org/kuali/student/contract/model/impl/R1R2ServiceContractComparisonTest.java]");
69          System.out.println("");
70          System.out.println("*TABLE OF CONTENTS*");
71          System.out.println("{toc}");
72          System.out.println("");
73          System.out.println("h1. Loading models of the contracts from the source code");
74          System.out.println("h2. Log from loading model for R1");
75          getModel1();
76          System.out.println("h2. Log from loading model for R2");
77          getModel2();
78          getFinder1();
79          getFinder2();
80          loadKnownObjectRenames();
81          loadKnownUnconvertedObjects();
82          loadKnownFieldRenames();
83          loadKnownFieldIssues();
84          loadKnownMethodRenames();
85          loadKnownMethodIssues ();
86      }
87  
88      @After
89      public void tearDown() {
90      }
91      private static final String RESOURCES_DIRECTORY = "src/test/resources";
92      private static final String TEST_SOURCE_DIRECTORY =
93              "src/test/java/org/kuali/student/contract/model/test/source";
94      private static final String ENROLL_PROJECT_SRC_MAIN = "C:/svn/ks-1.3-services/ks-enroll/ks-enroll-api/src/main";
95      private static final String ENROLL_PROJECT_JAVA_DIRECTORY = ENROLL_PROJECT_SRC_MAIN + "/java";
96      private static final String RICE_CORE_API_DIRECTORY = "C:/svn/rice/trunk/core/api/src/main/java";
97      private static final String RICE_KIM_API_DIRECTORY = "C:/svn/rice/trunk/kim/kim-api/src/main/java";
98      private static final String RICE_LOCATION_API_DIRECTORY = "C:/svn/rice/trunk/location/api/src/main/java";
99      private static final String RICE_KEW_API_DIRECTORY = "C:/svn/rice/trunk/kew/api/src/main/java";
100     private static final String RICE_KEN_API_DIRECTORY = "C:/svn/rice/trunk/ken/api/src/main/java";
101     private static final String RICE_KSB_API_DIRECTORY = "C:/svn/rice/trunk/ksb/api/src/main/java";
102     private static final String RICE_KRMS_API_DIRECTORY = "C:/svn/rice/trunk/krms/api/src/main/java";
103     private static final String R1_PROJECT_DIRECTORY = "C:/svn/student/";
104     private static final String CORE_API_DIRECTORY = R1_PROJECT_DIRECTORY + "ks-core/ks-core-api/src/main/java";
105     private static final String COMMON_API_DIRECTORY = R1_PROJECT_DIRECTORY + "ks-common/ks-common-api/src/main/java";
106     private static final String LUM_API_DIRECTORY = R1_PROJECT_DIRECTORY + "ks-lum/ks-lum-api/src/main/java";
107     private static ServiceContractModel model1 = null;
108     private static ServiceContractModel model2 = null;
109 
110     /**
111      * Test of getServiceMethods method, of class ServiceContractModelQDoxLoader.
112      */
113     @Test
114     public void testCompareModels() {
115         System.out.println("");
116         System.out.println("h1. Message Structure Comparison");
117         compareTypes();
118         System.out.println("");
119         System.out.println("h1. Service Method Comparison");
120         compareMethods();
121     }
122 
123     private ServiceContractModel getModel1() {
124         if (model1 != null) {
125             return model1;
126         }
127         List<String> srcDirs = new ArrayList();
128         System.out.println("User directory=" + System.getProperty("user.dir"));
129         System.out.println("Current directory=" + new File(".").getAbsolutePath());
130         srcDirs.add(COMMON_API_DIRECTORY);
131         srcDirs.add(CORE_API_DIRECTORY);
132         srcDirs.add(LUM_API_DIRECTORY);
133         System.out.println ("Reading as input:");
134         for (String directory : srcDirs) {
135             System.out.println ("* " + directory);
136         }
137         System.out.println ("");
138         boolean validateKualiStudent = false;
139         ServiceContractModel instance = new ServiceContractModelQDoxLoader(srcDirs, validateKualiStudent);
140 
141         instance = new ServiceContractModelCache(instance);
142         validate(instance);
143         model1 = instance;
144         return instance;
145     }
146 
147     private ServiceContractModel getModel2() {
148         if (model2 != null) {
149             return model2;
150         }
151         List<String> srcDirs = new ArrayList();
152         System.out.println("User directory=" + System.getProperty("user.dir"));
153         System.out.println("Current directory=" + new File(".").getAbsolutePath());
154         srcDirs.add(ENROLL_PROJECT_JAVA_DIRECTORY);
155         System.out.println ("Reading as input:");
156         for (String directory : srcDirs) {
157             System.out.println ("* " + directory);
158         }
159         System.out.println ("");     
160         boolean validateKualiStudent = true;
161         ServiceContractModel instance = new ServiceContractModelQDoxLoader(srcDirs, validateKualiStudent);
162 
163         instance = new ServiceContractModelCache(instance);
164         validate(instance);
165         model2 = instance;
166         return instance;
167     }
168 
169     private String dump(ServiceMethod method) {
170         StringBuilder bldr = new StringBuilder();
171         bldr.append(method.getName());
172         String comma = "";
173         bldr.append("(");
174         for (ServiceMethodParameter param : method.getParameters()) {
175             bldr.append(comma);
176             comma = ", ";
177             bldr.append(param.getType());
178             bldr.append(" ");
179             bldr.append(param.getName());
180         }
181         bldr.append(")");
182         return bldr.toString();
183     }
184 
185     private void validate(ServiceContractModel model) {
186         Collection<String> errors =
187                 new ServiceContractModelValidator(model).validate();
188         if (errors.size() > 0) {
189             StringBuilder buf = new StringBuilder();
190             buf.append(errors.size()).append(" errors found while validating the data.");
191             int cnt = 0;
192             for (String msg : errors) {
193                 cnt++;
194                 buf.append("\n");
195                 buf.append("*error*").append(cnt).append(":").append(msg);
196             }
197 
198             fail(buf.toString());
199         }
200     }
201     private ModelFinder finder1 = null;
202 
203     private ModelFinder getFinder1() {
204         if (finder1 == null) {
205             finder1 = new ModelFinder(getModel1());
206         }
207         return finder1;
208     }
209     private ModelFinder finder2 = null;
210 
211     private ModelFinder getFinder2() {
212         if (finder2 == null) {
213             finder2 = new ModelFinder(getModel2());
214         }
215         return finder2;
216     }
217 
218     private void compareTypes() {
219         for (Service service : model1.getServices()) {
220             System.out.println("");
221             System.out.println("h2. " + service.getName() + " Structures");
222             for (XmlType type : finder1.findAllComplexTypesInService(service.getKey())) {
223                 findCompareType(type);
224             }
225         }
226     }
227 
228     private String calcService(XmlType xmlType) {
229         StringBuilder bldr = new StringBuilder();
230         String comma = "";
231         for (String serviceKey : HtmlContractMessageStructureWriter.calcUsageByService(model1, xmlType)) {
232             bldr.append(comma);
233             comma = ", ";
234             bldr.append(serviceKey);
235         }
236         return bldr.toString();
237     }
238 
239     private String calcFieldNames(XmlType xmlType) {
240         StringBuilder bldr = new StringBuilder();
241         String comma = "";
242         for (MessageStructure ms : finder2.findMessageStructures(xmlType.getName())) {
243             bldr.append(comma);
244             comma = ", ";
245             bldr.append(ms.getShortName());
246         }
247         return bldr.toString();
248     }
249     private Map<String, String> knownUnconvertedObjects = null;
250 
251     private void loadKnownUnconvertedObjects() {
252         Map<String, String> missings = new HashMap<String, String>();
253         missings.put("ObjectStructureDefinition", "Old R1 dictionary not converted");
254         missings.put("FieldDefinition", "Old R1 dictionary not converted");
255         missings.put("ValidCharsConstraint", "Old R1 dictionary not converted");
256         missings.put("RequiredConstraint", "Old R1 dictionary not converted");
257         missings.put("CaseConstraint", "Old R1 dictionary not converted");
258         missings.put("WhenConstraint", "Old R1 dictionary not converted");
259         missings.put("Constraint", "Old R1 dictionary not converted");
260         missings.put("MustOccurConstraint", "Old R1 dictionary not converted");
261         missings.put("LookupConstraint", "Old R1 dictionary not converted");
262         missings.put("CommonLookupParam", "Old R1 dictionary not converted");
263         missings.put("CommonLookup", "Old R1 dictionary not converted");
264         missings.put("DateRangeInfo", "DateRange was merged in with Milestone");
265         missings.put("CredentialInfo", "LRC was revamped and Class II like objects were dropped");
266         missings.put("CreditInfo", "LRC was revamped and Class II like objects were dropped");
267         missings.put("ScaleInfo", "Changed to be ResultScaleInfo");
268         missings.put("GradeInfo", "LRC was revamped and Class II like objects were dropped");
269         missings.put("ResultComponentInfo", "Changed to be ResultValuesGroupInfo");
270         missings.put("QueryParamInfo", "Is really a type object that holds typing info information about a parameter model as TypeInfo and use type-type relation to connnect it to search criteria");
271         missings.put("FieldDescriptor", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
272         missings.put("SearchSelector", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
273         missings.put("ObjectStructure", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
274         missings.put("Type", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
275         missings.put("State", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
276         missings.put("Field", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
277         missings.put("ConstraintDescriptor", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
278         missings.put("ConstraintSelector", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
279         missings.put("RequireConstraint", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
280         missings.put("TypeStateCaseConstraint", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
281         missings.put("TypeStateWhenConstraint", "Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
282         missings.put("OccursConstraint", " Old pre-R1 dictionary structure that were attached to search param types were dropped -- ui dictionary provided that info");
283         missings.put("ResultColumnInfo", " is really a type that describes the type of result that comes back, store as a TypeInfo object and use type-type relation to connect to result");
284 //        missings.put("SearchCriteriaTypeInfo", "The search criteria is really a type stucture that should be modeled as as TypeInfo and type-type relationship to connect it to a search type");
285         missings.put("java.lang.String", "");
286         missings.put("Map<String, String>", "");
287         missings.put("LuiInfo", "Lui was pulled out and put in it's own service.  The LuiInfo object was not used in R1 and was radically redesigned in R2");
288 
289         knownUnconvertedObjects = missings;
290         return;
291     }
292     private Map<String, String> knownObjectRenames = null;
293 
294     private void loadKnownObjectRenames() {
295         Map<String, String> renames = new HashMap<String, String>();
296         renames.put("Message", "MessageInfo");
297         renames.put("SearchRequest", "SearchRequestInfo");
298         renames.put("SearchResult", "SearchResultInfo");
299         renames.put("SearchParam", "SearchParamInfo");
300         renames.put("SearchResultRow", "SearchResultRowInfo");
301         renames.put("SearchResultCell", "SearchResultCellInfo");
302         renames.put("Message", "MessageInfo");
303         knownObjectRenames = renames;
304         return;
305     }
306     private Map<String, String> knownFieldRenames = null;
307 
308     private void loadKnownFieldRenames() {
309         Map<String, String> renames = new HashMap<String, String>();
310         renames.put("id", "key"); // not all the time but when it happens want to catch if id not found
311         renames.put("desc", "descr");
312         renames.put("state", "stateKey");
313         renames.put("type", "typeKey");
314         renames.put("metaInfo", "meta");
315         renames.put("desc", "descr");
316         renames.put("startTerm", "startTermId");
317         renames.put("endTerm", "endTermId");
318         renames.put("longDesc", "longDescr");
319         renames.put("shortDesc", "shortDescr");
320         renames.put("objectTypeURI", "refObjectUri");
321         // TODO: this works but really should make these specific to the object they are connected with
322         renames.put("detailDesc", "descr");
323         renames.put("milestoneDate", "startDate");
324         renames.put("success", "isSuccess");
325         renames.put("relationType", "relationTypeKey");
326         renames.put("unitType", "unitTypeKey");
327         renames.put("enrollable", "isEnrollable");
328         renames.put("hazardousForDisabledStudents", "isHazardousForDisabledStudents");
329         renames.put("versionInfo", "version");
330         renames.put("primary", "isPrimary");
331         renames.put("activityType", "typeKey");
332         renames.put("loRepository", "loRepositoryKey");
333         renames.put("queryParamValueList", "queryParamValues");
334         renames.put("credentialProgramType", "typeKey");
335         knownFieldRenames = renames;
336         return;
337     }
338     private Map<String, String> knownFieldIssues = null;
339 
340     private void loadKnownFieldIssues() {
341         Map<String, String> issues = new HashMap<String, String>();
342         issues.put("AtpInfo.key", "Switched from key to Id");
343         issues.put("MilestoneInfo.key", "Switched from key to Id");
344         issues.put("AtpInfo.id", ""); // suppress the extra field message from the r2 side
345         issues.put("MilestoneInfo.id", ""); // ditto
346         issues.put("MilestoneInfo.atpId", "Is not in R2 because a Milestone can be connected to more than one ATP so it is managed through a relationship");
347         issues.put("Message.locale", "the type was changed from String to LocaleInfo to hold the different parts of the locale info");
348         issues.put("SearchRequest.params", "");
349         issues.put("SearchResult.rows", "");
350         issues.put("SearchResultRow.cells", "");
351         issues.put("ValidationResultInfo.errorLevel", "");
352         issues.put("ValidationResultInfo.level", "");
353         issues.put("ValidationResultInfo.ok", "");
354         issues.put("ValidationResultInfo.warn", "");
355         issues.put("ValidationResultInfo.error", "");
356         issues.put("DocumentInfo.documentBinaryInfo", "renamd to just documentBinary (removing the trailing Info from the field name)");
357         issues.put("OrgHierarchyInfo.key", "Switched from key to Id");
358         issues.put("SearchResultTypeInfo.resultColumns", "ResultColumns is really anotther type to describe the column, Use type-type relation to hold that info");
359         issues.put("ReqCompFieldTypeInfo.fieldDescriptor", "was dropped because it was an Old Pre-R1 dictionary and was not used -- UI dictionary provides that info instead");
360         issues.put("LuTypeInfo.instructionalFormat", "Instructional format is a TypeInfo object and should be modeled as such using the type-type relation to connect it to a learning unit type");
361         issues.put("LuTypeInfo.deliveryMethod", "Delivery method is a TypeInfo object and should be modeled as such using type-type relation to connect it to a learning unit type");
362         issues.put("SearchCriteriaTypeInfo.queryParams", "Query Params is a TypeInfo that describes the parameter, model as type and type-type relation");
363         issues.put("OrgOrgRelationTypeInfo.orgHierarchyKey", "This was removed because a particular relation type can participate in more than one hierarchies!");
364         issues.put("SearchParam.value", "Renamed to values which is List<String>, in R1 the setValue method was overloaded to take a string or List, Kept in R2 but marked as deprecated");
365         issues.put("", "");
366         issues.put("", "");
367         issues.put("", "");
368         issues.put("", "");
369         issues.put("", "");
370         issues.put("", "");
371         issues.put("", "");
372         issues.put("", "");
373         issues.put("", "");
374         issues.put("", "");
375 
376         knownFieldIssues = issues;
377         return;
378     }
379 
380     private XmlType findType(XmlType r1) {
381         XmlType r2 = finder2.findXmlType(r1.getName());
382         if (r2 == null) {
383             String renamedName = this.knownObjectRenames.get(r1.getName());
384             if (renamedName != null) {
385                 r2 = finder2.findXmlType(renamedName);
386                 if (r2 == null) {
387                     System.out.println("# (-) " + r1.getName() + ": was not found even after being renamed to " + renamedName);
388                     return null;
389                 }
390                 System.out.println("# (/) " + r1.getName() + ": was renamed to " + renamedName);
391                 return r2;
392             }
393         }
394         if (r2 == null) {
395             if (r1.getName().endsWith("TypeInfo")) {
396                 r2 = finder2.findXmlType("TypeInfo");
397             }
398         }
399         return r2;
400     }
401 
402     private void findCompareType(XmlType r1) {
403         if (r1.getName().endsWith("List")) {
404             return;
405         }
406         if (this.knownUnconvertedObjects.containsKey(r1.getName())) {
407             String message = this.knownUnconvertedObjects.get(r1.getName());
408             if (message.isEmpty()) {
409                 return;
410             }
411             System.out.println("# (/) " + r1.getName() + ":" + message);
412             return;
413         }
414         XmlType r2 = findType(r1);
415         if (r2 == null) {
416             System.out.println("# " + r1.getName() + ": has no corresponding object in r2");
417             return;
418         }
419         Set<MessageStructure> usedInR2 = new HashSet<MessageStructure>();
420         for (MessageStructure ms : finder1.findMessageStructures(r1.getName())) {
421             MessageStructure used = findCompareMessageStructure(ms, r2);
422             if (used != null) {
423                 usedInR2.add(used);
424             }
425         }
426         // Don't report extra fields on type info
427         if (!r2.getName().equals("TypeInfo")) {
428             for (MessageStructure ms : finder2.findMessageStructures(r2.getName())) {
429                 if (usedInR2.contains(ms)) {
430                     continue;
431                 }
432                 String issue = this.knownFieldIssues.get(ms.getXmlObject() + "." + ms.getShortName());
433                 if (issue != null) {
434                     if (!issue.isEmpty()) {
435                         System.out.println("# (*g) " + ms.getXmlObject() + "." + ms.getShortName() + ": " + issue);
436                     }
437                     continue;
438                 }
439                 System.out.println("# (+) " + ms.getXmlObject() + "." + ms.getShortName() + " - new field added in R2");
440             }
441         }
442     }
443 
444     private MessageStructure findCompareMessageStructure(MessageStructure r1, XmlType xmlType2) {
445         MessageStructure r2 = findMessageStructure(r1, xmlType2);
446         String issue = this.knownFieldIssues.get(r1.getXmlObject() + "." + r1.getShortName());
447         if (issue != null) {
448             if (!issue.isEmpty()) {
449                 System.out.println("# (*g) " + r1.getXmlObject() + "." + r1.getShortName() + ": " + issue);
450             }
451             return r2;
452         }
453         if (r2 == null) {
454             if (xmlType2.getName().equals("TypeInfo")) {
455                 if (r1.getShortName().endsWith("Type")
456                         || r1.getShortName().endsWith("TypeInfo")
457                         || r1.getShortName().endsWith("Types")
458                         || r1.getShortName().endsWith("TypeInfos")) {
459                     System.out.println("# (*g) " + r1.getXmlObject() + "." + r1.getShortName() + " was a type stored on a type: use type-type relationship instead");
460                     return null;
461                 }
462                 System.out.println("# (!) " + r1.getXmlObject() + "." + r1.getShortName() + " was extra data on type, store in dynamic attribute if actually used");
463                 return null;
464             }
465             System.out.println("# (-) " + r1.getXmlObject() + "." + r1.getShortName() + " not found in r2: renamed to one of these? " + calcFieldNames(xmlType2));
466             return null;
467         }
468         compareType(r1, r2);
469         return r2;
470     }
471 
472     private void compareType(MessageStructure r1, MessageStructure r2) {
473         if (r1.getType().equalsIgnoreCase(r2.getType())) {
474             return;
475         }
476         if (r1.getShortName().equals("attributes")) {
477             if (r1.getType().equals("Map<String, String>")) {
478                 if (r2.getType().equals("AttributeInfoList")) {
479                     return;
480                 }
481             }
482         }
483         if (r1.getShortName().equals("desc") || r1.getShortName().equals("descr")) {
484             if (r1.getType().equals("String")) {
485                 if (r2.getType().equals("RichTextInfo")) {
486                     System.out.println("# (*g) " + r1.getXmlObject() + "." + r1.getShortName() + ": description type were changed to RichText, use plain version");
487                     return;
488                 }
489             }
490         }
491         System.out.println("# (!) " + r1.getXmlObject() + "." + r1.getShortName() + ": the type was changed from " + r1.getType() + " to " + r2.getType());
492     }
493 
494     private MessageStructure findMessageStructure(MessageStructure r1, XmlType xmlType2) {
495         MessageStructure r2 = finder2.findMessageStructure(xmlType2.getName(), r1.getShortName());
496         if (r2 == null) {
497             String renamed = this.knownFieldRenames.get(r1.getShortName());
498             if (renamed != null) {
499                 r2 = finder2.findMessageStructure(xmlType2.getName(), renamed);
500                 if (r2 == null) {
501                     System.out.println("# (-) " + r1.getXmlObject() + "." + r1.getShortName()
502                             + " was renamed to " + xmlType2.getName() + "." + renamed
503                             + " BUT IT STILL DIDN'T EXIST IN R2");
504                     return null;
505                 }
506                 System.out.println("# (*g) " + r1.getXmlObject() + "." + r1.getShortName()
507                         + " was renamed to " + xmlType2.getName() + "." + renamed);
508             }
509         }
510         return r2;
511     }
512 
513     private void compareMethods() {
514         for (Service service : model1.getServices()) {
515             System.out.println("");
516             System.out.println("h2. " + service.getName() + " Methods");
517             List<ServiceMethod> methodsInService = finder1.findServiceMethods(service.getKey());
518             for (ServiceMethod method : methodsInService) {
519                 findCompareMethod(method);
520             }
521         }
522     }
523 
524     private void findCompareMethod(ServiceMethod method1) {
525         String issue = knownMethodIssues.get (method1.getService() + "Service." + method1.getName());
526         if (issue != null) {
527             if (!issue.isEmpty()) {
528                 System.out.println("# (*g) " + method1.getService() + "Service." + method1.getName()
529                         + ": " + issue);
530             }
531             return;
532         }
533         ServiceMethod method2 = findMethod(method1);
534         if (method2 == null) {
535 //            String possibleMethods = calcPossibleMethods(method1);
536             if (isTypeMethod(method1)) {
537                 System.out.println("# (*g) " + method1.getService() + "Service." + method1.getName()
538                         + " was dropped because it is a type, use TypeService instead");
539                 return;
540             }
541             String possibleMethods = this.calcPossibleMethods(method1);
542             if (possibleMethods.isEmpty()) {
543                 System.out.println("# (-) " + method1.getService() + "Service." + method1.getName()
544                         + " could not be found in R2");
545             } else {
546                 System.out.println("# (!) " + method1.getService() + "Service." + method1.getName()
547                         + " might have been renamed to one of these: "
548                         + possibleMethods);
549             }
550             return;
551         }
552         if (!method1.getName().equals(method2.getName())) {
553             System.out.println("# (*g) " + method1.getService() + "Service." + method1.getName()
554                     + " was renamed to " + method2.getService() + "Service." + method2.getName());
555         }
556     }
557 
558     private ServiceMethod findMethod(ServiceMethod method1) {
559         ServiceMethod method2 = findMethod2(method1.getService(), method1.getName());
560         if (method2 == null) {
561             String methodRename = knownMethodRenames.get(method1.getService() + "Service." + method1.getName());
562             if (methodRename != null) {
563                 method2 = findMethod2(method1.getService(), methodRename);
564                 if (method2 == null) {
565                     System.out.println("# (x) " + method1.getService() + "Service." + method1.getName() 
566                             + " could not be found even after being renamed to " + methodRename);
567                     return null;
568                 }
569             }
570         }
571         return method2;
572     }
573     private Map<String, String> knownMethodRenames = null;
574 
575     private void loadKnownMethodRenames() {
576         Map<String, String> renames = new HashMap<String, String>();
577         renames.put("AtpService.getAtpsByAtpType", "getAtpIdsByType");
578         renames.put("AtpService.getMilestonesByAtp", "getMilestonesForAtp");
579         renames.put("AtpService.addMilestone", "addMilestoneToAtp");
580         renames.put("AtpService.removeMilestone", "removeMilestoneFromAtp");
581         renames.put("MessageService.getMessageGroups", "getMessageGroupKeys");
582         renames.put("CommentService.getComments", "getCommentsByReferenceAndType");
583         renames.put("CommentService.getTags", "getTagsByReferenceAndType"); 
584         renames.put("CommentService.addTag", "createTag");
585         renames.put("CommentService.addComment", "createComment");
586         renames.put("CommentService.removeComment", "deleteComment");
587         renames.put("CommentService.removeTag", "deleteTag");
588         renames.put("CommentService.removeComments", "deleteCommentsByReference");
589         renames.put("CommentService.removeTags", "deleteTagsByReference");
590         renames.put("DocumentService.getDocumentsByIdList", "getDocumentsByIds");
591         renames.put("DocumentService.getCategoriesByDocument", "getDocumentCategoriesByDocumentId");
592         renames.put("DocumentService.getRefDocRelationsByDoc", "getRefDocRelationsByDocument");
593         renames.put("EnumerationManagementService.removeEnumeratedValue", "deleteEnumeratedValue");
594         renames.put("OrganizationService.getOrganization", "getOrg");
595         renames.put("OrganizationService.getOrganizationsByIdList", "getOrgsByIds");
596         renames.put("OrganizationService.getOrgOrgRelationsByIdList", "getOrgOrgRelationsByIds");
597         renames.put("OrganizationService.getOrgPersonRelationsByIdList", "getOrgPersonRelationsByIds");
598         renames.put("OrganizationService.getPersonIdsForOrgByRelationType", "");
599         renames.put("OrganizationService.getAllOrgPersonRelationsByPerson", "getOrgPersonRelationsByPerson");
600         renames.put("OrganizationService.getAllOrgPersonRelationsByOrg", "getOrgPersonRelationsByOrg");
601         renames.put("OrganizationService.createOrganization", "createOrg");
602         renames.put("OrganizationService.updateOrganization", "updateOrg");
603         renames.put("OrganizationService.deleteOrganization", "deleteOrg");
604         renames.put("OrganizationService.validateOrganization", "validateOrg");
605         renames.put("OrganizationService.removeOrgOrgRelation", "deleteOrgOrgRelation");
606         renames.put("OrganizationService.removeOrgPersonRelation", "deleteOrgPersonRelation");
607         renames.put("OrganizationService.addPositionRestrictionToOrg", "createOrgPositionRestriction");
608         renames.put("OrganizationService.updatePositionRestrictionForOrg", "updateOrgPositionRestriction");
609         renames.put("OrganizationService.removePositionRestrictionFromOrg", "deleteOrgPositionRestriction");
610         renames.put("StatementService.getStatementsUsingReqComponent", "getStatementsByReqComponent");
611         renames.put("StatementService.getStatementsUsingStatement", "getStatementsForStatement");
612         renames.put("CourseService.getCourseFormats", "getCourseFormatsByCourse");
613         renames.put("CourseService.getCourseActivities", "getCourseActivitiesByCourseFormat");
614         renames.put("CourseService.getCourseLos", "getCourseLearningObjectivesByCourse");
615         renames.put("LearningObjectiveService.getLoCategories", "getLoCategoriesByLoRepository");
616         renames.put("LearningObjectiveService.getLoByIdList", "getLosByIds");
617         renames.put("LearningObjectiveService.getLosByRepository", "getLosByLoRepository");
618         renames.put("LearningObjectiveService.getLoCategoriesForLo", "getLoCategoriesByLo");
619         renames.put("LrcService.getResultComponent", "getResultValuesGroup");
620         renames.put("LuService.getClusByIdList", "getClusByIds");
621         renames.put("LuService.getAllowedLuLuRelationTypesByCluId", "getAllowedCluCluRelationTypesByClu");
622         renames.put("LuService.getClusByRelation", "getClusByRelatedCluAndRelationType");
623         renames.put("LuService.getCluIdsByRelation", "getCluIdsByRelatedCluAndRelationType");
624         renames.put("LuService.getRelatedClusByCluId", "getRelatedClusByCluAndRelationType");
625         renames.put("LuService.getRelatedCluIdsByCluId", "getRelatedCluIdsByCluAndRelationType");
626         renames.put("LuService.getCluPublicationsByCluId", "getCluPublicationsByClu");
627         renames.put("LuService.getResourceRequirementsForCluId", "getResourceRequirementsForClu");
628         renames.put("LuService.getCluSetInfo", "getCluSet");
629         renames.put("LuService.getCluSetInfoByIdList", "getCluSetsByIds");
630         renames.put("LuService.getLuisByIdList", "getLuisByIds");
631         renames.put("ProgramService.getMajorIdsByCredentialProgramType", "getMajorDisciplineIdsByCredentialProgramType");
632         renames.put("ProgramService.getVariationsByMajorDisciplineId", "getProgramVariationsByMajorDiscipline");
633         renames.put("ProgramService.getHonorsByCredentialProgramType", "getHonorProgramIdsByCredentialProgramType");
634         renames.put("ProposalService.getProposalsByIdList", "getProposalsByIds");
635         renames.put("", "");
636         renames.put("", "");
637         knownMethodRenames = renames;
638         return;
639     }
640 
641       private Map<String, String> knownMethodIssues = null;
642 
643     private void loadKnownMethodIssues() {
644         Map<String, String> issues = new HashMap<String, String>();
645         issues.put("AtpService.validateDateRange", "Dropped because DateRange objects were merged in with milestones");
646         issues.put("AtpService.getDateRange", "Dropped because DateRange objects were merged in with milestones");
647         issues.put("AtpService.getDateRangesByAtp", "Dropped because DateRange objects were merged in with milestones");
648         issues.put("AtpService.getDateRangesByDate", "Dropped because DateRange objects were merged in with milestones");
649         issues.put("AtpService.addDateRange", "Dropped because DateRange objects were merged in with milestones");
650         issues.put("AtpService.updateDateRange", "Dropped because DateRange objects were merged in with milestones");
651         issues.put("AtpService.removeDateRange", "Dropped because DateRange objects were merged in with milestones");
652         issues.put("DictionaryService.getObjectTypes", "Dictionary service was completely revamped to match KRAD, old one is still around use that for R1 stuff");
653         issues.put("DictionaryService.getObjectStructure", "Dictionary service was completely revamped to match KRAD, old one is still around use that for R1 stuff");
654         issues.put("CommentService.getCommentsByType", "Renamed and changed to just get Ids, so use getCommentIdsByType then call getCommentsByIds");
655         issues.put("CommentService.getTagsByType", "Renamed and changed to just get Ids, so use getTagIdsByType then call getTagsByIds");
656         issues.put("DocumentService.getRefObjectTypes", "(!) has been dropped from the contract, the document service should store any uri");
657         issues.put("DocumentService.getRefObjectSubTypes", "(!) has been dropped from the contract, the document service should store any uri and sub-object URI");
658         issues.put("OrganizationService.getOrgOrgRelationsByRelatedOrg", " (!) the two methods for tranversing by one side of the relationship or other has replaced by a single method that finds relationships no matter which side it is on (?) Need to possibly rethink this it imposes a big change on both the implementation and on the the application. ");        
659         issues.put("OrganizationService.getPersonIdsForOrgByRelationType", "Was removed, instead use getOrgPersonRelationsByTypeAndPerson and loop through the relationships to get the list of personIds that you want.  The issue was the old method did not take into account relationships that are old/inactive so using it would lead to errors that would only appear once transitions occured in the people being related to the org.");
660         issues.put("OrganizationService.getOrgPersonRelationsByPerson", "Renamd to getOrgPersonRelationsByOrgAndPerson, because the R1 was badly named, it said just by person but the parameters required an Org as well!");
661         issues.put("OrganizationService.getPositionRestrictionsByOrg", "use getOrgPositionRestrictionIdsByOrg then call getOrgPositionRestrictionsByIds to get the objects");
662         issues.put("LearningObjectiveService.getAllowedLoLoRelationTypesForLoType", "is a type method, use Type Service instead");
663         issues.put("LrcService.getCredential", "Is a Class 2 concept and as dropped from the Class 1 service");
664         issues.put("LrcService.getCredentialsByKeyList", "Is a Class 2 concept and as dropped from the Class 1 service");
665         issues.put("LrcService.getCredentialKeysByCredentialType", "Is a Class 2 concept and as dropped from the Class 1 service");
666         issues.put("LrcService.getCredit", "Is a Class 2 concept and as dropped from the Class 1 service");
667         issues.put("LrcService.getCreditsByKeyList", "Is a Class 2 concept and as dropped from the Class 1 service");
668         issues.put("LrcService.getCreditKeysByCreditType", "Is a Class 2 concept and as dropped from the Class 1 service");
669         issues.put("LrcService.getGrade", "Is a Class 2 concept and as dropped from the Class 1 service");
670         issues.put("LrcService.getGradesByKeyList", "Is a Class 2 concept and as dropped from the Class 1 service");
671         issues.put("LrcService.getGradeKeysByGradeType", "Is a Class 2 concept and as dropped from the Class 1 service");
672         issues.put("LrcService.getGradesByScale", "Is a Class 2 concept and as dropped from the Class 1 service");
673         issues.put("LrcService.translateGrade", "(-) is not being supported at this time, translations will be added later");
674         issues.put("LrcService.compareGrades", "(-) is not being supported at this time, comparisons will be added later");
675         issues.put("LrcService.getResultComponentIdsByResultComponentType", "roughly maps to getResultValuesGroupIdsByType but they are different objects and the types have changed as well");
676         issues.put("LrcService.getResultComponentIdsByResult", "roughly maps to getResultValuesGroupsByResultValue but doesn't take the extra type parameter");
677         issues.put("LrcService.createResultComponent", "rougly maps to createResultValuesGroup");
678         issues.put("LrcService.updateResultComponent", "rougly maps to updateResultValuesGroup");
679         issues.put("LrcService.deleteResultComponent", "rougly maps to deleteResultValuesGroup");
680         issues.put("LrcService.getScale", "roughly maps to getResultScale");
681         issues.put("LuService.getAllowedLuLuRelationTypesByLuiId", "is a type method, use TypeService instead");
682         issues.put("", "");
683         issues.put("", "");
684         issues.put("", "");
685         issues.put("", "");
686         knownMethodIssues = issues;
687         return;
688     }
689     
690     
691     private ServiceMethod findMethod2(String serviceKey, String methodName) {
692         ServiceMethod method2 = finder2.findServiceMethod(serviceKey, methodName);
693         if (method2 == null) {
694             if (serviceKey.equals("Lu")) {
695                 method2 = finder2.findServiceMethod("Clu", methodName);
696                 if (method2 == null) {
697                     method2 = finder2.findServiceMethod("Lui", methodName);
698                 }
699             }
700         }
701         return method2;
702     }
703 
704     private String calcMethods(ServiceMethod method1) {
705         StringBuilder bldr = new StringBuilder();
706         String comma = "";
707         for (ServiceMethod method2 : finder2.findServiceMethods(method1.getService())) {
708             bldr.append(comma);
709             comma = ", ";
710             bldr.append(method2.getName());
711         }
712         return bldr.toString();
713     }
714 
715     private String calcPossibleMethods(ServiceMethod method1) {
716         StringBuilder bldr = new StringBuilder();
717         String comma = "";
718         for (ServiceMethod method2 : findPossibleMethods(method1)) {
719             bldr.append(comma);
720             comma = ", ";
721             bldr.append(method2.getName());
722         }
723         return bldr.toString();
724     }
725 
726     private List<ServiceMethod> findPossibleMethods(ServiceMethod method1) {
727         List<ServiceMethod> methods = new ArrayList<ServiceMethod>();
728         List<ServiceMethod> wideNet = null;
729         if (method1.getService().equals("Lu")) {
730             wideNet = finder2.findServiceMethods("Clu");
731             wideNet.addAll(finder2.findServiceMethods("Lui"));
732         } else {
733             wideNet = finder2.findServiceMethods(method1.getService());
734         }
735         for (ServiceMethod method2 : wideNet) {
736             if (isPossibleMatch(method1, method2)) {
737                 methods.add(method2);
738             }
739         }
740         return methods;
741     }
742 
743     private boolean isPossibleMatch(ServiceMethod method1, ServiceMethod method2) {
744          if (method1.getName().contains(method2.getName())) {
745             return true;
746         }
747         if (method2.getName().contains(method1.getName())) {
748             return true;
749         }
750         if (method1.getName().startsWith("get") && method2.getName().startsWith("get")) {
751             return true;
752         }
753         if (method1.getName().startsWith("add") && method2.getName().startsWith("create")) {
754             return true;
755         }
756         if (method1.getName().startsWith("create") && method2.getName().startsWith("create")) {
757             return true;
758         }
759         if (method1.getName().startsWith("update") && method2.getName().startsWith("update")) {
760             return true;
761         }
762         if (method1.getName().startsWith("delete") && method2.getName().startsWith("delete")) {
763             return true;
764         }
765         if (method1.getName().startsWith("remove") && method2.getName().startsWith("delete")) {
766             return true;
767         }
768         if (method1.getName().startsWith("validate") && method2.getName().startsWith("validate")) {
769             return true;
770         }
771         return false;
772     }
773 
774     private boolean isTypeMethod(ServiceMethod method1) {
775         if (method1.getReturnValue().getType().endsWith("TypeInfo")) {
776             return true;
777         }
778         if (method1.getReturnValue().getType().endsWith("TypeInfoList")) {
779             return true;
780         }
781         return false;
782     }
783 }