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