001 /**
002 * Copyright 2005-2014 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.api.engine;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.kuali.rice.core.api.mo.ModelObjectComplete;
020
021 import java.io.Serializable;
022 import java.util.Collections;
023 import java.util.HashMap;
024 import java.util.Map;
025
026 /**
027 * <p>Parameter object for the {@link org.kuali.rice.krms.api.engine.Engine} used to pass in mappings from Term to value
028 * (aka facts). In rule parlance, a fact is a concrete value of a term. Intuitively this relationship is one of
029 * definition and instance, similar to a parameter definition (e.g. int count) for a function (or method) in a
030 * programming language and a parameter value (e.g. 5).</p>
031 *
032 * <p>{@link Facts} is immutable, and has a private constructor. Use the inner {@link Builder} class to construct.</p>
033 *
034 * @author Kuali Rice Team (rice.collab@kuali.org)
035 */
036 public final class Facts implements ModelObjectComplete, Serializable {
037
038 private static final long serialVersionUID = -1448089944850300846L;
039
040 /**
041 * empty facts object
042 */
043 public static final Facts EMPTY_FACTS = new Facts(Builder.create());
044
045 private Map<Term, Object> factMap;
046
047 private Facts() {
048 // private no-args constructor forces use of builder
049 }
050
051 private Facts(Builder b) {
052 // copy the map to avoid surprises
053 this.factMap = new HashMap<Term, Object>(b.factMap);
054 }
055
056 /**
057 * @return the Map of Terms to fact values. May be empty, will never be null. The returned map is unmodifiable.
058 */
059 public Map<Term, Object> getFactMap() {
060 return Collections.unmodifiableMap(factMap);
061 }
062
063 @Override
064 public boolean equals(Object o) {
065 if (this == o) {
066 return true;
067 }
068 if (o == null || getClass() != o.getClass()) {
069 return false;
070 }
071
072 final Facts facts = (Facts) o;
073
074 if (factMap != null ? !factMap.equals(facts.factMap) : facts.factMap != null) {
075 return false;
076 }
077
078 return true;
079 }
080
081 @Override
082 public int hashCode() {
083 return factMap != null ? factMap.hashCode() : 0;
084 }
085
086 @Override
087 public String toString() {
088 return "Facts{" + "factMap=" + factMap + '}';
089 }
090
091 /**
092 * Builder for a {@link Facts} parameter object
093 */
094 public static class Builder {
095 private Map<Term, Object> factMap = new HashMap<Term, Object>();
096
097 private Builder() {
098 // private constructor forces use of static factory
099 }
100
101 /**
102 * Static factory method to produce instances of this {@link Builder} class
103 * @return
104 */
105 public static Builder create() {
106 return new Builder();
107 }
108
109 /**
110 * Add a fact mapping from the name and parameter map combination to the fact value
111 * @param termName the name of the term. Must not be empty or null.
112 * @param termParameters any parameters for the term. May be null or empty.
113 * @param factValue the concrete value for the term
114 */
115 public Builder addFact(String termName, Map<String, String> termParameters, Object factValue) {
116 if (StringUtils.isEmpty(termName)) {
117 throw new IllegalArgumentException("termName must not be null or empty");
118 }
119 factMap.put(new Term(termName, termParameters), factValue);
120 return this;
121 }
122
123 /**
124 * Add a fact mapping from the term name to the fact value
125 * @param termName the name of the term. Must not be empty or null.
126 * @param factValue the concrete value for the term
127 */
128 public Builder addFact(String termName, Object factValue) {
129 addFact(termName, null, factValue);
130 return this;
131 }
132
133 /**
134 * Add a fact mapping from the {@link Term} to the fact value
135 * @param term the term that this fact is a value for. Must not be null.
136 * @param factValue the fact value
137 */
138 public Builder addFact(Term term, Object factValue) {
139 if (term == null) {
140 throw new IllegalArgumentException("term must not be null");
141 }
142 factMap.put(term, factValue);
143 return this;
144 }
145
146 /**
147 * Add facts in bulk to this Facts parameter object
148 * @param facts the map of Terms to fact values. May be null, in that case this call is a no op.
149 */
150 public Builder addFactsByTerm(Map<Term, Object> facts) {
151 if (facts != null) {
152 factMap.putAll(facts);
153 }
154 return this;
155 }
156
157 /**
158 * Add facts in bulk to this Facts parameter object
159 * @param facts the map of term names to fact values. May be null, in that case this call is a no op.
160 */
161 public Builder addFactsByName(Map<String, Object> facts) {
162 if (facts != null) {
163 for (Map.Entry<String, Object> entry : facts.entrySet()) {
164 factMap.put(new Term(entry.getKey()), entry.getValue());
165 }
166 }
167 return this;
168 }
169
170 /**
171 * return a {@link Facts} parameter object spawned from this {@link Builder}
172 */
173 public Facts build() {
174 if (factMap.isEmpty()) {
175 return EMPTY_FACTS;
176 } else {
177 return new Facts(this);
178 }
179 }
180
181 }
182
183
184 }