001 /**
002 * Copyright 2005-2012 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.krms.framework.engine;
017
018 import java.util.ArrayList;
019 import java.util.Collections;
020 import java.util.List;
021
022 import org.kuali.rice.krms.api.engine.ExecutionEnvironment;
023 import org.kuali.rice.krms.api.engine.ResultEvent;
024 import org.kuali.rice.krms.api.engine.ExecutionFlag;
025 import org.kuali.rice.krms.api.repository.LogicalOperator;
026 import org.kuali.rice.krms.framework.engine.result.BasicResult;
027
028 /**
029 *
030 * An implementation of {@link Proposition} which holds other Propositions and a {@link LogicalOperator}.
031 *
032 * NOTE - this is a patched version of CompoundProposition which fixes bugs in evaluation "OR"-ed propositions
033 *
034 * @author Kuali Rice Team (rice.collab@kuali.org)
035 */
036 public final class CompoundProposition implements Proposition {
037
038 private static final ResultLogger LOG = ResultLogger.getInstance();
039
040 private final LogicalOperator logicalOperator;
041 private final List<Proposition> propositions;
042
043 /**
044 * Create a CompoundProposition with the given values
045 * @param logicalOperator {@link LogicalOperator} to set logicalOperator to
046 * @param propositions to set the propositions to
047 */
048 public CompoundProposition(LogicalOperator logicalOperator, List<Proposition> propositions) {
049
050 if (propositions == null || propositions.isEmpty()) {
051 throw new IllegalArgumentException("Propositions must be non-null and non-empty.");
052 }
053 if (logicalOperator == null) {
054 throw new IllegalArgumentException("Logical operator must be non-null.");
055 }
056 this.logicalOperator = logicalOperator;
057 this.propositions = new ArrayList<Proposition>(propositions);
058 }
059
060 @Override
061 public PropositionResult evaluate(ExecutionEnvironment environment) {
062
063 PropositionResult result = evaluateInner(environment);
064
065 // handle compound proposition result logging
066 if (LOG.isEnabled(environment)) {
067 LOG.logResult(new BasicResult(ResultEvent.PROPOSITION_EVALUATED, this, environment, result.getResult()));
068 }
069
070 return result;
071 }
072
073 /**
074 * Evaluates then {@link ExecutionEnvironment}
075 *
076 * @param environment {@link ExecutionEnvironment} to use for evaluation
077 * @return PropositionResult {@link PropositionResult} the results of the evaluation
078 * @throws IllegalStateException if the logicalOperator is invalid.
079 */
080
081 private PropositionResult evaluateInner(ExecutionEnvironment environment) {
082
083 boolean collatedResult;
084 boolean evaluateAll = environment.getExecutionOptions().getFlag(ExecutionFlag.EVALUATE_ALL_PROPOSITIONS);
085
086 if (logicalOperator == LogicalOperator.AND) {
087
088 collatedResult = true;
089
090 for (Proposition proposition : propositions) {
091
092 PropositionResult singleResult = proposition.evaluate(environment);
093 logPropositionResult(proposition, singleResult, environment);
094
095 if (!singleResult.getResult()) {
096 collatedResult = false;
097 if(!evaluateAll) break;
098 }
099 }
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 }