001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.krms.framework.engine;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.List;
021
022import org.kuali.rice.krms.api.engine.ExecutionEnvironment;
023import org.kuali.rice.krms.api.engine.ResultEvent;
024import org.kuali.rice.krms.api.engine.ExecutionFlag;
025import org.kuali.rice.krms.api.repository.LogicalOperator;
026import 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 * @author Kuali Rice Team (rice.collab@kuali.org)
033 */
034public final class CompoundProposition implements Proposition {
035        
036    private static final ResultLogger LOG = ResultLogger.getInstance();
037    
038        private final LogicalOperator logicalOperator;
039        private final List<Proposition> propositions;
040
041    /**
042     * Create a CompoundProposition with the given values
043     * @param logicalOperator {@link LogicalOperator} to set logicalOperator to
044     * @param propositions to set the propositions to
045     */
046        public CompoundProposition(LogicalOperator logicalOperator, List<Proposition> propositions) {
047                                
048                if (propositions == null || propositions.isEmpty()) {
049                        throw new IllegalArgumentException("Propositions must be non-null and non-empty.");
050                }
051                if (logicalOperator == null) {
052                        throw new IllegalArgumentException("Logical operator must be non-null.");
053                }
054                this.logicalOperator = logicalOperator;
055                this.propositions = new ArrayList<Proposition>(propositions);
056        }
057        
058        @Override
059        public PropositionResult evaluate(ExecutionEnvironment environment) {
060                
061                PropositionResult result = evaluateInner(environment);
062                
063                // handle compound proposition result logging
064                if (LOG.isEnabled(environment)) { 
065            LOG.logResult(new BasicResult(ResultEvent.PROPOSITION_EVALUATED, this, environment, result.getResult()));
066        }
067                
068                return result;
069        }
070
071    /**
072     * Evaluates then {@link ExecutionEnvironment}
073     *
074     * @param environment {@link ExecutionEnvironment} to use for evaluation
075     * @return PropositionResult {@link PropositionResult} the results of the evaluation
076     * @throws IllegalStateException if the logicalOperator is invalid.
077     */
078        
079    private PropositionResult evaluateInner(ExecutionEnvironment environment) {
080        
081        boolean collatedResult;
082        boolean evaluateAll = environment.getExecutionOptions().getFlag(ExecutionFlag.EVALUATE_ALL_PROPOSITIONS);
083        
084        if (logicalOperator == LogicalOperator.AND) {
085
086            collatedResult = true;
087
088                        for (Proposition proposition : propositions) {
089                                
090                                PropositionResult singleResult = proposition.evaluate(environment);
091                                logPropositionResult(proposition, singleResult, environment);
092                                                                
093                                if (!singleResult.getResult()) {
094                                        collatedResult = false;
095                                        if(!evaluateAll) break;
096                                }
097                        }
098                        
099                        return new PropositionResult(collatedResult);
100                        
101                } else if (logicalOperator == LogicalOperator.OR) {
102                        
103                    collatedResult = false;
104                        
105                        for (Proposition proposition : propositions) {
106                                
107                            PropositionResult singleResult = proposition.evaluate(environment);
108                                logPropositionResult(proposition, singleResult, environment);
109                                
110                                if (singleResult.getResult()) {
111                                        collatedResult = true;
112                                        if(!evaluateAll) break;
113                                }
114                        }
115                        
116                        return new PropositionResult(collatedResult);
117                }
118                throw new IllegalStateException("Invalid logical operator: " + logicalOperator);
119    }
120    
121    /*
122     * Logs only if the proposition is not compound
123     * and have the compound proposition log its own result
124     * @param proposition {@link Proposition} to log.  Compound Propositions will not log.
125     * @param propositionResult {@link PropositionResult} to log the result and execution details of
126     * @param environment {@link ExecutionEnvironment} to log
127     */
128    
129    public void logPropositionResult(Proposition proposition, PropositionResult propositionResult, ExecutionEnvironment environment) {
130                
131        if(!proposition.isCompound()) {
132            LOG.logResult(new BasicResult(propositionResult.getExecutionDetails(), ResultEvent.PROPOSITION_EVALUATED, proposition, environment, propositionResult.getResult()));
133        }
134        
135    }
136
137    /**
138     * Returns an unmodifiableList of {@link Proposition}s.
139     * @return an unmodifiableList of {@link Proposition}s
140     */
141    @Override
142    public List<Proposition> getChildren() {
143        return Collections.unmodifiableList(propositions);
144    }
145    
146    @Override
147    public boolean isCompound() {
148        return true;
149    }
150
151}