View Javadoc

1   /**
2    * Copyright 2005-2012 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.rice.krms.framework.engine;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.List;
21  
22  import org.kuali.rice.krms.api.engine.ExecutionEnvironment;
23  import org.kuali.rice.krms.api.engine.ResultEvent;
24  import org.kuali.rice.krms.api.engine.ExecutionFlag;
25  import org.kuali.rice.krms.api.repository.LogicalOperator;
26  import org.kuali.rice.krms.framework.engine.result.BasicResult;
27  
28  /**
29   *
30   * An implementation of {@link Proposition} which holds other Propositions and a {@link LogicalOperator}.
31   *
32   * NOTE - this is a patched version of CompoundProposition which fixes bugs in evaluation "OR"-ed propositions
33   *
34   * @author Kuali Rice Team (rice.collab@kuali.org)
35   */
36  public final class CompoundProposition implements Proposition {
37  	
38      private static final ResultLogger LOG = ResultLogger.getInstance();
39      
40  	private final LogicalOperator logicalOperator;
41  	private final List<Proposition> propositions;
42  
43      /**
44       * Create a CompoundProposition with the given values
45       * @param logicalOperator {@link LogicalOperator} to set logicalOperator to
46       * @param propositions to set the propositions to
47       */
48  	public CompoundProposition(LogicalOperator logicalOperator, List<Proposition> propositions) {
49  				
50  		if (propositions == null || propositions.isEmpty()) {
51  			throw new IllegalArgumentException("Propositions must be non-null and non-empty.");
52  		}
53  		if (logicalOperator == null) {
54  			throw new IllegalArgumentException("Logical operator must be non-null.");
55  		}
56  		this.logicalOperator = logicalOperator;
57  		this.propositions = new ArrayList<Proposition>(propositions);
58  	}
59  	
60  	@Override
61  	public PropositionResult evaluate(ExecutionEnvironment environment) {
62  		
63  		PropositionResult result = evaluateInner(environment);
64  		
65  		// handle compound proposition result logging
66  		if (LOG.isEnabled(environment)) { 
67              LOG.logResult(new BasicResult(ResultEvent.PROPOSITION_EVALUATED, this, environment, result.getResult()));
68          }
69  		
70  		return result;
71  	}
72  
73      /**
74       * Evaluates then {@link ExecutionEnvironment}
75       *
76       * @param environment {@link ExecutionEnvironment} to use for evaluation
77       * @return PropositionResult {@link PropositionResult} the results of the evaluation
78       * @throws IllegalStateException if the logicalOperator is invalid.
79       */
80  	
81      private PropositionResult evaluateInner(ExecutionEnvironment environment) {
82      	
83      	boolean collatedResult;
84      	boolean evaluateAll = environment.getExecutionOptions().getFlag(ExecutionFlag.EVALUATE_ALL_PROPOSITIONS);
85      	
86          if (logicalOperator == LogicalOperator.AND) {
87  
88              collatedResult = true;
89  
90  			for (Proposition proposition : propositions) {
91  				
92  				PropositionResult singleResult = proposition.evaluate(environment);
93  				logPropositionResult(proposition, singleResult, environment);
94  								
95  				if (!singleResult.getResult()) {
96  					collatedResult = false;
97  					if(!evaluateAll) break;
98  				}
99  			}
100 			
101 			return new PropositionResult(collatedResult);
102 			
103 		} else if (logicalOperator == LogicalOperator.OR) {
104 			
105 		    collatedResult = false;
106 			
107 			for (Proposition proposition : propositions) {
108 				
109 			    PropositionResult singleResult = proposition.evaluate(environment);
110 				logPropositionResult(proposition, singleResult, environment);
111 				
112 				if (singleResult.getResult()) {
113 					collatedResult = true;
114 					if(!evaluateAll) break;
115 				}
116 			}
117 			
118 			return new PropositionResult(collatedResult);
119 		}
120 		throw new IllegalStateException("Invalid logical operator: " + logicalOperator);
121     }
122     
123     /*
124      * Logs only if the proposition is not compound
125      * and have the compound proposition log its own result
126      * @param proposition {@link Proposition} to log.  Compound Propositions will not log.
127      * @param propositionResult {@link PropositionResult} to log the result and execution details of
128      * @param environment {@link ExecutionEnvironment} to log
129      */
130     
131     public void logPropositionResult(Proposition proposition, PropositionResult propositionResult, ExecutionEnvironment environment) {
132     	    	
133     	if(!proposition.isCompound()) {
134             LOG.logResult(new BasicResult(propositionResult.getExecutionDetails(), ResultEvent.PROPOSITION_EVALUATED, proposition, environment, propositionResult.getResult()));
135     	}
136     	
137     }
138 
139     /**
140      * Returns an unmodifiableList of {@link Proposition}s.
141      * @return an unmodifiableList of {@link Proposition}s
142      */
143     @Override
144     public List<Proposition> getChildren() {
145         return Collections.unmodifiableList(propositions);
146     }
147     
148     @Override
149     public boolean isCompound() {
150         return true;
151     }
152 
153 }