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