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