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.Collections; 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Map.Entry; 022import java.util.Set; 023import java.util.HashSet; 024 025import org.apache.commons.lang.ObjectUtils; 026import org.kuali.rice.krms.api.engine.EngineResults; 027import org.kuali.rice.krms.api.engine.ExecutionEnvironment; 028import org.kuali.rice.krms.api.engine.ExecutionOptions; 029import org.kuali.rice.krms.api.engine.SelectionCriteria; 030import org.kuali.rice.krms.api.engine.Term; 031import org.kuali.rice.krms.api.engine.TermResolutionEngine; 032import org.kuali.rice.krms.api.engine.TermResolutionException; 033import org.kuali.rice.krms.api.engine.TermResolver; 034import 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 */ 040public 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}