001 /**
002 * Copyright 2005-2013 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.Collections;
019 import java.util.HashMap;
020 import java.util.Map;
021 import java.util.Map.Entry;
022 import java.util.Set;
023 import java.util.HashSet;
024
025 import org.apache.commons.lang.ObjectUtils;
026 import org.kuali.rice.krms.api.engine.EngineResults;
027 import org.kuali.rice.krms.api.engine.ExecutionEnvironment;
028 import org.kuali.rice.krms.api.engine.ExecutionOptions;
029 import org.kuali.rice.krms.api.engine.SelectionCriteria;
030 import org.kuali.rice.krms.api.engine.Term;
031 import org.kuali.rice.krms.api.engine.TermResolutionEngine;
032 import org.kuali.rice.krms.api.engine.TermResolutionException;
033 import org.kuali.rice.krms.api.engine.TermResolver;
034 import org.kuali.rice.krms.api.engine.ResultEvent;
035
036 /**
037 * An implementation of {@link ExecutionEnvironment} given {@link SelectionCriteria}, facts (Map<{@link Term}, Object> ), {@link ExecutionOptions} and {@link TermResolutionEngine}.
038 * @author Kuali Rice Team (rice.collab@kuali.org)
039 */
040 public final class BasicExecutionEnvironment implements ExecutionEnvironment {
041
042 private final SelectionCriteria selectionCriteria;
043 private final Map<Term, Object> facts;
044 private final ExecutionOptions executionOptions;
045 private final EngineResults engineResults;
046 private final TermResolutionEngine termResolutionEngine;
047 private Map<Object, Set<Term>> termPropositionMap;
048
049 /**
050 * Constructor for a BasicExecutionEnvironment with the given {@link SelectionCriteria}, facts, {@link ExecutionOptions} and {@link TermResolutionEngine}
051 * @param selectionCriteria to set selectionCriteria to, cannot be null
052 * @param facts to set facts to, cannot be null
053 * @param executionOptions to set executionOptions to
054 * @param termResolutionEngine to set termResolutionEngine to
055 * @throws IllegalArgumentException if the selectionCriteria or facts are null
056 */
057 public BasicExecutionEnvironment(SelectionCriteria selectionCriteria, Map<Term, Object> facts, ExecutionOptions executionOptions, TermResolutionEngine termResolutionEngine) {
058 if (selectionCriteria == null) {
059 throw new IllegalArgumentException("Selection criteria must not be null.");
060 }
061 if (facts == null) {
062 throw new IllegalArgumentException("Facts must not be null.");
063 }
064 this.selectionCriteria = selectionCriteria;
065 this.executionOptions = new ExecutionOptions(executionOptions);
066 this.engineResults = new EngineResultsImpl();
067
068 this.termResolutionEngine = new TermResolutionEngineImpl();
069
070 // Add facts
071 this.facts = new HashMap<Term, Object>(facts.size());
072 this.facts.putAll(facts);
073
074 for (Entry<Term, Object> factsEntry : facts.entrySet()) {
075 this.termResolutionEngine.addTermValue(factsEntry.getKey(), factsEntry.getValue());
076 }
077 }
078
079 @Override
080 public SelectionCriteria getSelectionCriteria() {
081 return this.selectionCriteria;
082 }
083
084 @Override
085 public Map<Term, Object> getFacts() {
086 return Collections.unmodifiableMap(facts);
087 }
088
089 @Override
090 public void addTermResolver(TermResolver<?> termResolver) {
091 termResolutionEngine.addTermResolver(termResolver);
092 }
093
094 @Override
095 public <T> T resolveTerm(Term term, Object caller) throws TermResolutionException {
096 T value;
097
098 // This looks funny, but works around a javac bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
099 // Specifically, using <T> below works around it.
100 value = termResolutionEngine.<T>resolveTerm(term);
101
102 if (caller != null) {
103 if(termPropositionMap == null) {
104 termPropositionMap = new HashMap<Object, Set<Term>>();
105 }
106
107 // update the Proposition-Term mapping
108 if(termPropositionMap.containsKey(caller)) {
109 termPropositionMap.get(caller).add(term);
110 } else {
111 termPropositionMap.put(caller, new HashSet<Term>());
112 termPropositionMap.get(caller).add(term);
113 }
114 }
115
116 publishFact(term, value);
117
118 return value;
119 }
120
121 @Override
122 public Set<Term> getTermsForCaller(Object caller) {
123 return termPropositionMap.get(caller);
124 }
125
126 @Override
127 public boolean publishFact(Term factName, Object factValue) {
128 if (facts.containsKey(factName) && ObjectUtils.equals(facts.get(factName), factValue)) {
129 return false;
130 }
131 facts.put(factName, factValue);
132 termResolutionEngine.addTermValue(factName, factValue);
133 return true;
134 }
135
136 @Override
137 public ExecutionOptions getExecutionOptions() {
138 return executionOptions;
139 }
140
141 @Override
142 public EngineResults getEngineResults() {
143 return engineResults;
144 }
145
146
147 }