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