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    }