View Javadoc

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