Coverage Report - org.kuali.student.core.statement.util.PropositionBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
PropositionBuilder
0%
0/141
0%
0/79
5.833
PropositionBuilder$1
0%
0/1
N/A
5.833
PropositionBuilder$TranslationResults
0%
0/2
N/A
5.833
 
 1  
 package org.kuali.student.core.statement.util;
 2  
 
 3  
 import org.kuali.rice.krms.api.repository.LogicalOperator;
 4  
 import org.kuali.rice.krms.framework.engine.Agenda;
 5  
 import org.kuali.rice.krms.framework.engine.AgendaTree;
 6  
 import org.kuali.rice.krms.framework.engine.AgendaTreeEntry;
 7  
 import org.kuali.rice.krms.framework.engine.BasicAgenda;
 8  
 import org.kuali.rice.krms.framework.engine.BasicAgendaTree;
 9  
 import org.kuali.rice.krms.framework.engine.BasicAgendaTreeEntry;
 10  
 import org.kuali.rice.krms.framework.engine.BasicRule;
 11  
 import org.kuali.rice.krms.framework.engine.expression.ComparisonOperator;
 12  
 import org.kuali.rice.krms.framework.engine.CompoundProposition;
 13  
 import org.kuali.rice.krms.framework.engine.Proposition;
 14  
 import org.kuali.rice.krms.framework.engine.Rule;
 15  
 import org.kuali.student.common.exceptions.InvalidParameterException;
 16  
 import org.kuali.student.common.util.krms.RulesExecutionConstants;
 17  
 import org.kuali.student.common.util.krms.proposition.CourseSetCompletionProposition;
 18  
 import org.kuali.student.common.util.krms.proposition.CourseSetEnrollmentProposition;
 19  
 import org.kuali.student.common.util.krms.proposition.MaxCourseCompletionProposition;
 20  
 import org.kuali.student.common.util.krms.proposition.SingleCourseCompletionProposition;
 21  
 import org.kuali.student.common.util.krms.proposition.SingleCourseEnrollmentProposition;
 22  
 import org.kuali.student.core.statement.dto.ReqCompFieldInfo;
 23  
 import org.kuali.student.core.statement.dto.ReqComponentInfo;
 24  
 import org.kuali.student.core.statement.dto.StatementOperatorTypeKey;
 25  
 import org.kuali.student.core.statement.dto.StatementTreeViewInfo;
 26  
 
 27  
 import java.util.ArrayList;
 28  
 import java.util.Arrays;
 29  
 import java.util.Collection;
 30  
 import java.util.Collections;
 31  
 import java.util.HashMap;
 32  
 import java.util.List;
 33  
 import java.util.Map;
 34  
 
 35  
 /**
 36  
  *
 37  
  *
 38  
  * @author alubbers
 39  
  *
 40  
  */
 41  0
 public class PropositionBuilder {
 42  
     
 43  0
     public static final Collection<String> TRANSLATABLE_STATEMENT_TYPES = Collections.singleton(StatementServiceConstants.PREREQUISITE_STATEMENT_TYPE);
 44  
 
 45  
     //private LrcService lrcService;
 46  
     
 47  
     //private ApplicationContext appContext;
 48  
     
 49  
     private static final List<String> validRequirementComponentTypes;
 50  
 
 51  
     static {
 52  0
         String[] REQ_COM_TYPE_SEED_DATA = {
 53  
                 StatementServiceConstants.ENROLLED_COURSE_REQ_COM_TYPE,
 54  
                 StatementServiceConstants.N_OF_REQUIRED_COURSES_ENROLLED_REQ_COM_TYPE,
 55  
                 StatementServiceConstants.ALL_OF_REQUIRED_COURSES_ENROLLED_REQ_COM_TYPE,
 56  
                 //"kuali.reqComponent.type.course.courseset.grade.max",
 57  
                 //"kuali.reqComponent.type.course.permission.org.required",
 58  
                 //"kuali.reqComponent.type.course.permission.instructor.required",
 59  
                 //"kuali.reqComponent.type.course.test.score.min",
 60  
                 //"kuali.reqComponent.type.course.courseset.credits.completed.nof",
 61  
                 //"kuali.reqComponent.type.course.courseset.gpa.min",
 62  
                 //"kuali.reqComponent.type.course.courseset.grade.min"
 63  
                 //"kuali.reqComponent.type.course.courseset.nof.grade.min",
 64  
                 StatementServiceConstants.ALL_OF_REQUIRED_COURSES_COMPLETED_REQ_COM_TYPE,
 65  
                 StatementServiceConstants.COMPLETED_COURSE_REQ_COM_TYPE,
 66  
                 StatementServiceConstants.N_OF_REQUIRED_COURSES_COMPLETED_REQ_COM_TYPE,
 67  
                 StatementServiceConstants.MAX_N_OF_COURSES_COMPLETED_REQ_COM_TYPE,
 68  
                 StatementServiceConstants.NONE_OF_COURSES_COMPLETED_REQ_COM_TYPE,
 69  
                 StatementServiceConstants.NOT_COMPLETED_COURSE_REQ_COM_TYPE
 70  
                 };
 71  
         
 72  0
         validRequirementComponentTypes = Collections.unmodifiableList(Arrays.asList(REQ_COM_TYPE_SEED_DATA));
 73  0
     }
 74  
 
 75  0
     public static class TranslationResults {
 76  
         public Agenda agenda;
 77  
 
 78  0
         public Map<Proposition, ReqComponentInfo> reqComponentPropositionMap = new HashMap<Proposition, ReqComponentInfo>();
 79  
     }
 80  
 
 81  
     public TranslationResults translateStatement(StatementTreeViewInfo statementTreeView, Map<String, String> qualifierMap) throws InvalidParameterException {
 82  
 
 83  0
         TranslationResults results = new TranslationResults();
 84  
         
 85  0
         Proposition rootProposition = buildPropositionFromComponents(statementTreeView, results.reqComponentPropositionMap);
 86  
         
 87  0
         Rule rule = new BasicRule(rootProposition, null);
 88  
         
 89  0
         List<AgendaTreeEntry> treeEntries = new ArrayList<AgendaTreeEntry>();
 90  0
         treeEntries.add(new BasicAgendaTreeEntry(rule));
 91  
         
 92  0
         AgendaTree agendaTree = new BasicAgendaTree(treeEntries);
 93  
 
 94  0
         if (qualifierMap == null) {
 95  0
             qualifierMap = Collections.emptyMap();
 96  
         }
 97  
 
 98  0
         results.agenda = new BasicAgenda(qualifierMap, agendaTree);
 99  
 
 100  0
         return results;
 101  
         
 102  
     }
 103  
 
 104  
     private Proposition buildPropositionFromComponents(StatementTreeViewInfo statementTreeView, Map<Proposition, ReqComponentInfo> reqComponentPropositionMap) throws InvalidParameterException {
 105  0
         if(statementTreeView.getType().equals(StatementServiceConstants.PREREQUISITE_STATEMENT_TYPE)) {
 106  0
             if(statementTreeView.getStatements().isEmpty()) {
 107  
                 // if no sub-statements, there are only one or two req components
 108  
                     
 109  0
                     Proposition proposition = translateReqComponents(statementTreeView.getReqComponents(), statementTreeView.getOperator(), reqComponentPropositionMap);
 110  
                     
 111  0
                 return proposition;
 112  
             }
 113  
             
 114  
             // otherwise, make a compound proposition out of the recursive result for each sub-statement
 115  0
             List<Proposition> subProps = new ArrayList<Proposition>(statementTreeView.getStatements().size());
 116  
             
 117  0
             for(StatementTreeViewInfo subStatement : statementTreeView.getStatements()) {
 118  
             
 119  0
                     Proposition proposition = buildPropositionFromComponents(subStatement, reqComponentPropositionMap);
 120  
                                         
 121  0
                 subProps.add(buildPropositionFromComponents(subStatement, reqComponentPropositionMap));
 122  
                                 
 123  
                 
 124  0
             }
 125  
             
 126  0
             CompoundProposition compoundProposition = new CompoundProposition(translateOperator(statementTreeView.getOperator()), subProps);
 127  
             
 128  0
             return compoundProposition;
 129  
         }
 130  
         
 131  0
         return null;
 132  
     }
 133  
     
 134  
     
 135  
     private Proposition translateReqComponents(List<ReqComponentInfo> reqComponents, StatementOperatorTypeKey operator, Map<Proposition, ReqComponentInfo> reqComponentPropositionMap) throws InvalidParameterException {
 136  
         
 137  0
         ReqComponentInfo req1 = null, req2 = null;
 138  
         
 139  0
         if(reqComponents == null || reqComponents.isEmpty() || reqComponents.size() > 2) {
 140  0
             throw new InvalidParameterException("reqComponents parameter is invalid");
 141  
         }
 142  
         
 143  0
         req1 = reqComponents.get(0);
 144  0
         Proposition prop1 = buildPropositionForRequirementComponent(req1);
 145  
         
 146  0
         reqComponentPropositionMap.put(prop1, req1);
 147  
 
 148  
         
 149  0
         Proposition prop2 = null;
 150  0
         if(reqComponents.size() == 2) {
 151  0
             req2 = reqComponents.get(1);
 152  0
             prop2 = buildPropositionForRequirementComponent(req2);
 153  
             
 154  0
             reqComponentPropositionMap.put(prop2, req2);
 155  
 
 156  
         }
 157  
         
 158  0
         if(prop2 == null) {
 159  0
             return prop1;
 160  
         }
 161  
         else {
 162  0
             LogicalOperator logicalOperator = translateOperator(operator);
 163  0
             return new CompoundProposition(logicalOperator , Arrays.asList(prop1, prop2));
 164  
         }
 165  
     }
 166  
 
 167  
     private LogicalOperator translateOperator(StatementOperatorTypeKey statementOperator) throws InvalidParameterException {
 168  
         
 169  0
         if(statementOperator == null) {
 170  0
             return null;
 171  
         }
 172  
         
 173  0
         switch(statementOperator) {
 174  
             case AND: {
 175  0
                 return LogicalOperator.AND;
 176  
             }
 177  
             case OR: {
 178  0
                 return LogicalOperator.OR;
 179  
             }
 180  
             default: {
 181  0
                 throw new InvalidParameterException("StatementOperator is an unrecognized value: " + statementOperator.toString());
 182  
             }
 183  
         }
 184  
         
 185  
     }
 186  
 
 187  
     private Proposition buildPropositionForRequirementComponent(ReqComponentInfo requirementComponent) throws InvalidParameterException {
 188  
         
 189  0
         String componentType = requirementComponent.getType();
 190  
         
 191  0
         if(!validRequirementComponentTypes.contains(componentType)) {
 192  0
             throw new InvalidParameterException("Requirement component type is not handled");
 193  
         }
 194  
         
 195  
         // requirement component types that should match this condition:
 196  
         //  -- kuali.reqComponent.type.course.permission.org.required
 197  
         //  -- kuali.reqComponent.type.course.permission.instructor.required
 198  
         
 199  0
         if(componentType.contains("permission")) {
 200  0
             return buildPermissionProposition(requirementComponent);
 201  
         }
 202  
 
 203  
         // requirement component types that should match this condition:
 204  
         //  -- kuali.reqComponent.type.course.courseset.credits.completed.nof
 205  
         
 206  0
         if(componentType.contains("credits")) {
 207  0
             return buildCreditCountProposition(requirementComponent);
 208  
         }
 209  
 
 210  0
         if(componentType.equals(StatementServiceConstants.ENROLLED_COURSE_REQ_COM_TYPE) ||
 211  
                 componentType.equals(StatementServiceConstants.N_OF_REQUIRED_COURSES_ENROLLED_REQ_COM_TYPE) ||
 212  
                 componentType.equals(StatementServiceConstants.ALL_OF_REQUIRED_COURSES_ENROLLED_REQ_COM_TYPE)) {
 213  0
             return buildEnrolledCountProposition(requirementComponent);
 214  
         }
 215  
         
 216  0
         if(componentType.equals(StatementServiceConstants.COMPLETED_COURSE_REQ_COM_TYPE) ||
 217  
                 componentType.equals(StatementServiceConstants.N_OF_REQUIRED_COURSES_COMPLETED_REQ_COM_TYPE) ||
 218  
                 componentType.equals(StatementServiceConstants.ALL_OF_REQUIRED_COURSES_COMPLETED_REQ_COM_TYPE)) {
 219  0
             return buildCompletedCountProposition(requirementComponent);
 220  
         }
 221  
 
 222  0
         if(componentType.equals(StatementServiceConstants.NOT_COMPLETED_COURSE_REQ_COM_TYPE) ||
 223  
                 componentType.equals(StatementServiceConstants.MAX_N_OF_COURSES_COMPLETED_REQ_COM_TYPE) ||
 224  
                 componentType.equals(StatementServiceConstants.NONE_OF_COURSES_COMPLETED_REQ_COM_TYPE)) {
 225  0
             return buildMaxCompletedCountProposition(requirementComponent);
 226  
         }
 227  
         
 228  
         
 229  
         // requirement component types that should match this condition:
 230  
         //  -- kuali.reqComponent.type.course.courseset.gpa.min
 231  
         //  -- kuali.reqComponent.type.course.courseset.grade.min
 232  
         //  -- kuali.reqComponent.type.course.courseset.grade.max
 233  
         //  -- kuali.reqComponent.type.course.courseset.nof.grade.min
 234  
         
 235  0
         if(componentType.endsWith("grade.min") || componentType.endsWith("grade.max") || componentType.endsWith("gpa.min")) {
 236  0
             return buildGradeComparisonProposition(requirementComponent);
 237  
         }
 238  
         
 239  0
         if(componentType.equals("kuali.reqComponent.type.course.test.score.min")) {
 240  
             // build the test score proposition here
 241  
             
 242  
             // get the expected test score and the tests
 243  0
             Map<String, ReqCompFieldInfo> fieldMap = buildFieldMap(requirementComponent.getReqCompFields());
 244  0
             Float testScore = Float.parseFloat(fieldMap.get("kuali.reqComponent.field.type.test.score").getValue());
 245  0
             String testSetId = fieldMap.get("kuali.reqComponent.field.type.test.cluSet.id").getValue();
 246  
 
 247  
             // TODO
 248  
             //Proposition result = new TestScoreCompareProposition(ComparisonOperator.GREATER_THAN_EQUAL, testSetId, testScore);
 249  
             
 250  
             //return result;
 251  
         }
 252  
         
 253  0
         return null;
 254  
     }
 255  
 
 256  
     private Proposition buildMaxCompletedCountProposition(ReqComponentInfo requirementComponent) {
 257  0
         Map<String, ReqCompFieldInfo> fieldMap = buildFieldMap(requirementComponent.getReqCompFields());
 258  
 
 259  0
         Proposition result = null;
 260  0
         if(requirementComponent.getType().equals(StatementServiceConstants.NOT_COMPLETED_COURSE_REQ_COM_TYPE)) {
 261  
             // Single course to check for non-completion
 262  0
             String courseId = fieldMap.get(StatementServiceConstants.COURSE_ID_REQ_COM_FIELD_TYPE).getValue();
 263  
 
 264  0
             result = new MaxCourseCompletionProposition(courseId);
 265  
 
 266  0
             return result;
 267  
         }
 268  
 
 269  
         // for the other two types of max completion propositions handled here, a course set field will be provided
 270  0
         String courseSetId = fieldMap.get(StatementServiceConstants.COURSE_SET_ID_REQ_COM_FIELD_TYPE).getValue();
 271  
 
 272  0
         if(fieldMap.containsKey(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE)) {
 273  
             // if the field map contains an integer use that value for the maximum allowed courses to be completed in the set
 274  
             // otherwise, the maximum is 0 (no courses in the set can be completed)
 275  
 
 276  0
             Integer maxToComplete = Integer.parseInt(fieldMap.get(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE).getValue());
 277  0
             result = new MaxCourseCompletionProposition(courseSetId, maxToComplete);
 278  0
         }
 279  
         else {
 280  0
             result = new MaxCourseCompletionProposition(courseSetId, 0);
 281  
         }
 282  
 
 283  0
         return result;
 284  
     }
 285  
 
 286  
     private Proposition buildEnrolledCountProposition(ReqComponentInfo requirementComponent) {
 287  0
         Map<String, ReqCompFieldInfo> fieldMap = buildFieldMap(requirementComponent.getReqCompFields());
 288  
 
 289  0
         Proposition result = null;
 290  0
         if(requirementComponent.getType().equals(StatementServiceConstants.ENROLLED_COURSE_REQ_COM_TYPE)) {
 291  
             // only checking one course
 292  0
             String courseId = fieldMap.get(StatementServiceConstants.COURSE_ID_REQ_COM_FIELD_TYPE).getValue();
 293  
 
 294  0
             result = new SingleCourseEnrollmentProposition(courseId);
 295  
 
 296  0
             return result;
 297  
         }
 298  
 
 299  
         // for the other two types of enrollment propositions handled here, a course set field will be provided
 300  0
         String courseSetId = fieldMap.get(StatementServiceConstants.COURSE_SET_ID_REQ_COM_FIELD_TYPE).getValue();
 301  
 
 302  0
         if(fieldMap.containsKey(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE)) {
 303  
             // if the field map contains an integer use that value for the minimum number of courses to be enrolled in the set
 304  
             // otherwise, the minimum is not set, and the proposition checks for all courses for enrollment
 305  
 
 306  0
             Integer minToComplete = Integer.parseInt(fieldMap.get(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE).getValue());
 307  0
             result = new CourseSetEnrollmentProposition(courseSetId, minToComplete);
 308  0
         }
 309  
         else {
 310  0
             result = new CourseSetEnrollmentProposition(courseSetId);
 311  
         }
 312  
 
 313  0
         return result;
 314  
     }
 315  
 
 316  
     private Proposition buildCompletedCountProposition(ReqComponentInfo requirementComponent) {
 317  0
         Map<String, ReqCompFieldInfo> fieldMap = buildFieldMap(requirementComponent.getReqCompFields());
 318  
         
 319  0
         Proposition result = null;
 320  
         
 321  0
         if(requirementComponent.getType().equals(StatementServiceConstants.COMPLETED_COURSE_REQ_COM_TYPE)) {
 322  
             // only checking one course
 323  0
             String courseId = fieldMap.get(StatementServiceConstants.COURSE_ID_REQ_COM_FIELD_TYPE).getValue();
 324  
             
 325  0
             result = new SingleCourseCompletionProposition(courseId);
 326  
             
 327  0
             return result;
 328  
         }
 329  
 
 330  
         // for the other two types of completion propositions handled here, a course set field will be provided
 331  0
         String courseSetId = fieldMap.get(StatementServiceConstants.COURSE_SET_ID_REQ_COM_FIELD_TYPE).getValue();
 332  
         
 333  0
         if(fieldMap.containsKey(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE)) {
 334  
             // if the field map contains an integer use that value for the minimum number of courses to be completed in the set
 335  
             // otherwise, the minimum is not set, and the proposition checks for all courses for completion
 336  
 
 337  0
             Integer minToComplete = Integer.parseInt(fieldMap.get(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE).getValue());
 338  0
             result = new CourseSetCompletionProposition(courseSetId, minToComplete);
 339  0
         }
 340  
         else {
 341  0
             result = new CourseSetCompletionProposition(courseSetId);
 342  
         }
 343  
         
 344  0
         return result;
 345  
     }
 346  
 
 347  
     private Map<String, ReqCompFieldInfo> buildFieldMap(List<ReqCompFieldInfo> reqCompFields) {
 348  0
         Map<String, ReqCompFieldInfo> result = new HashMap<String, ReqCompFieldInfo>(reqCompFields.size());
 349  
         
 350  0
         for(ReqCompFieldInfo field : reqCompFields) {
 351  0
             result.put(field.getType(), field);
 352  
         }
 353  
         
 354  0
         return result;
 355  
     }
 356  
 
 357  
     private Proposition buildPermissionProposition(ReqComponentInfo requirementComponent) {
 358  0
         Proposition result = null;
 359  
         
 360  0
         if(requirementComponent.getType().equals("kuali.reqComponent.type.course.permission.org.required")) {
 361  
             // if the type is permission from an org, get the org id
 362  0
             Map<String, ReqCompFieldInfo> fieldMap = buildFieldMap(requirementComponent.getReqCompFields());
 363  0
             String orgId = fieldMap.get("kuali.reqComponent.field.type.org.id").getValue();
 364  
 
 365  
             // TODO
 366  
             // result = new OrgPermissionProposition(orgId);
 367  
         }
 368  
         else {
 369  
             // result = new InstructorPermissionProposition();
 370  
         }
 371  
         
 372  0
         return result;
 373  
     }
 374  
     
 375  
     private Proposition buildCreditCountProposition(ReqComponentInfo requirementComponent) {
 376  0
         Proposition result = null;
 377  
         
 378  0
         Map<String, ReqCompFieldInfo> fieldMap = buildFieldMap(requirementComponent.getReqCompFields());
 379  
         
 380  0
         Integer minimumCredits = Integer.parseInt(fieldMap.get(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE).getValue());
 381  
         
 382  0
         String courseSetId = fieldMap.get(StatementServiceConstants.COURSE_SET_ID_REQ_COM_FIELD_TYPE).getValue();
 383  
 
 384  
         // TODO
 385  
         // result = new CourseSetCreditsProposition(courseSetId, ComparisonOperator.GREATER_THAN_EQUAL, minimumCredits);
 386  
         
 387  0
         return result;
 388  
     }
 389  
 
 390  
     //  -- kuali.reqComponent.type.course.courseset.gpa.min
 391  
     //  -- kuali.reqComponent.type.course.courseset.grade.min
 392  
     //  -- kuali.reqComponent.type.course.courseset.grade.max
 393  
     //  -- kuali.reqComponent.type.course.courseset.nof.grade.min
 394  
     
 395  
     private Proposition buildGradeComparisonProposition(ReqComponentInfo requirementComponent) {
 396  0
         Proposition result = null;
 397  
         
 398  0
         Map<String, ReqCompFieldInfo> fieldMap = buildFieldMap(requirementComponent.getReqCompFields());
 399  
         
 400  0
         String courseSetId = fieldMap.get(StatementServiceConstants.COURSE_SET_ID_REQ_COM_FIELD_TYPE).getValue();
 401  
         
 402  0
         ComparisonOperator operator = null;
 403  0
         if(requirementComponent.getType().endsWith("min")) {
 404  0
             operator = ComparisonOperator.GREATER_THAN_EQUAL;
 405  
         }
 406  
         else {
 407  0
             operator = ComparisonOperator.LESS_THAN;
 408  
         }
 409  
         
 410  0
         boolean hasNumCourses = false;
 411  0
         Integer numCourses = -1;
 412  0
         if(fieldMap.containsKey(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE)) {
 413  0
             numCourses = Integer.parseInt(fieldMap.get(StatementServiceConstants.INTEGER_REQ_COM_FIELD_TYPE).getValue());
 414  0
             hasNumCourses = true;
 415  
         }
 416  
         
 417  0
         if(fieldMap.containsKey("kuali.reqComponent.field.type.gpa")) {
 418  0
             Float gpa = Float.parseFloat(fieldMap.get("kuali.reqComponent.field.type.gpa").getValue());
 419  
 
 420  
             // TODO
 421  
             // result = new CourseSetGPAProposition(courseSetId, gpa, operator);
 422  0
         }
 423  0
         else if(fieldMap.containsKey("kuali.reqComponent.field.type.gradeType.id")) {
 424  0
             String gradeType = fieldMap.get("kuali.reqComponent.field.type.gradeType.id").getValue();
 425  0
             String gradeValue = fieldMap.get("kuali.reqComponent.field.type.grade.id").getValue();
 426  
 
 427  
             // TODO
 428  
             /*
 429  
             GradeInfo gradeInfo = null;
 430  
             
 431  
             gradeInfo = lrcService.getGrade(gradeValue);
 432  
             
 433  
             if(hasNumCourses) {
 434  
                 result = new CourseSetGradeProposition(courseSetId, gradeInfo, numCourses, operator);
 435  
             }
 436  
             else {
 437  
                 result = new CourseSetGradeProposition(courseSetId, gradeInfo, operator);
 438  
             }*/
 439  
         }
 440  
         
 441  0
         return result;
 442  
     }
 443  
 
 444  
 }