001    /*
002     * Copyright 2011 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may      obtain a copy of the License at
007     *
008     *      http://www.osedu.org/licenses/ECL-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.student.contract.model.impl;
017    
018    import java.io.File;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.Date;
022    import java.util.HashMap;
023    import java.util.HashSet;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.Set;
027    import org.junit.After;
028    import org.junit.AfterClass;
029    import org.junit.Before;
030    import org.junit.BeforeClass;
031    import org.junit.Test;
032    import static org.junit.Assert.*;
033    import org.junit.Ignore;
034    
035    import org.kuali.student.contract.model.MessageStructure;
036    import org.kuali.student.contract.model.Service;
037    import org.kuali.student.contract.model.ServiceContractModel;
038    import org.kuali.student.contract.model.ServiceMethod;
039    import org.kuali.student.contract.model.ServiceMethodParameter;
040    import org.kuali.student.contract.model.XmlType;
041    import org.kuali.student.contract.model.util.HtmlContractMessageStructureWriter;
042    import org.kuali.student.contract.model.util.ModelFinder;
043    import org.kuali.student.contract.model.validation.ServiceContractModelValidator;
044    
045    /**
046     *
047     * @author nwright
048     */
049    @Ignore
050    public class R1R2ServiceContractComparisonTest {
051    
052        public R1R2ServiceContractComparisonTest() {
053        }
054    
055        @BeforeClass
056        public static void setUpClass() throws Exception {
057        }
058    
059        @AfterClass
060        public static void tearDownClass() throws Exception {
061        }
062    
063        @Before
064        public void setUp() {
065    
066            System.out.println("This section was created by programmatically comparing the message structures.");
067            System.out.println("Run on: " + new Date());
068            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]");
069            System.out.println("");
070            System.out.println("*TABLE OF CONTENTS*");
071            System.out.println("{toc}");
072            System.out.println("");
073            System.out.println("h1. Loading models of the contracts from the source code");
074            System.out.println("h2. Log from loading model for R1");
075            getModel1();
076            System.out.println("h2. Log from loading model for R2");
077            getModel2();
078            getFinder1();
079            getFinder2();
080            loadKnownObjectRenames();
081            loadKnownUnconvertedObjects();
082            loadKnownFieldRenames();
083            loadKnownFieldIssues();
084            loadKnownMethodRenames();
085            loadKnownMethodIssues ();
086        }
087    
088        @After
089        public void tearDown() {
090        }
091        private static final String RESOURCES_DIRECTORY = "src/test/resources";
092        private static final String TEST_SOURCE_DIRECTORY =
093                "src/test/java/org/kuali/student/contract/model/test/source";
094        private static final String ENROLL_PROJECT_SRC_MAIN = "C:/svn/ks-1.3-services/ks-enroll/ks-enroll-api/src/main";
095        private static final String ENROLL_PROJECT_JAVA_DIRECTORY = ENROLL_PROJECT_SRC_MAIN + "/java";
096        private static final String RICE_CORE_API_DIRECTORY = "C:/svn/rice/trunk/core/api/src/main/java";
097        private static final String RICE_KIM_API_DIRECTORY = "C:/svn/rice/trunk/kim/kim-api/src/main/java";
098        private static final String RICE_LOCATION_API_DIRECTORY = "C:/svn/rice/trunk/location/api/src/main/java";
099        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    }