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