001: package org.ofbiz.rules.engine;
002:
003: /**
004: * <p><b>Title:</b> Dynamic Rule
005: * <p><b>Description:</b> None
006: * <p>Copyright (c) 1999 Steven J. Metsker.
007: * <p>Copyright (c) 2001 The Open For Business Project - www.ofbiz.org
008: *
009: * <p>Permission is hereby granted, free of charge, to any person obtaining a
010: * copy of this software and associated documentation files (the "Software"),
011: * to deal in the Software without restriction, including without limitation
012: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
013: * and/or sell copies of the Software, and to permit persons to whom the
014: * Software is furnished to do so, subject to the following conditions:
015: *
016: * <p>The above copyright notice and this permission notice shall be included
017: * in all copies or substantial portions of the Software.
018: *
019: * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
020: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
021: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
022: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
023: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
024: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
025: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
026: *
027: * <br>
028: * <p>A DynamicRule represents a provable statement that a
029: * structure is true if a following series of other
030: * structures are true.
031: * <p>
032: * For example,
033: * <blockquote><pre>
034: * bachelor(X) :- male(X), unmarried(X);
035: * </pre></blockquote>
036: * <p>
037: * is a logical rule.
038: * <p>
039: * The head of this rule is the structure <code>bachelor(X)
040: * </code>. A structure <code>bachelor(B)</code> can prove
041: * itself by unifying with the head, and then proving the
042: * remaining structures or "tail".
043: *
044: * The tail in this example contains <code>male(X)</code>
045: * and <code>unmarried(X)</code>.
046: *
047: * @author Steven J. Metsker
048: * @version 1.0
049: */
050:
051: public class DynamicRule extends Rule implements DynamicAxiom {
052:
053: protected AxiomSource as;
054: protected Scope scope;
055: protected boolean headInvolved = false;
056: protected DynamicRule tail;
057:
058: /**
059: * Construct a provable rule for the given axiom source,
060: * scope, and structures -- these structures must all be
061: * capable of proving themselves. That is, they must be
062: * consulting structures or gateways.
063: */
064: protected DynamicRule(AxiomSource as, Scope scope,
065: Structure[] structures) {
066: super (structures);
067: this .as = as;
068: this .scope = scope;
069: }
070:
071: /**
072: * Construct a provable rule for the given axiom source,
073: * scope, and rule.
074: *
075: * @param AxiomSource the source to consult for proving
076: * the structures in this dynamic rule
077: *
078: * @param Scope a home for the variables in this dynamic
079: * rule
080: *
081: * @param Rule the non-dynamic source of this rule.
082: */
083: protected DynamicRule(AxiomSource as, Scope scope, Rule rule) {
084: this (as, scope, provableStructures(as, scope, rule.structures));
085: }
086:
087: /**
088: * "Can establish" means that either a rule can prove itself, or
089: * that the rule is empty.
090: *
091: * When a structure unifies with the head of a rule, the
092: * structure asks the rule's tail if it can "establish" itself.
093: * This amounts to proving the tail, unless this rule is
094: * empty. If this rule is empty, it can "establish" itself,
095: * but it cannot "find next proof".
096: *
097: * @return <code>true</code> if this rule is empty, or
098: * if it is nonempty and can find another proof
099: */
100: public boolean canEstablish() {
101: if (isEmpty()) {
102: return true;
103: }
104: return canFindNextProof();
105: }
106:
107: /**
108: * Tests if this rule can find another proof, and, if so, sets
109: * this rule's variables to the values that make the proof true.
110: * <p>
111: *
112: * @return <code>true</code> if this rule can find another
113: * proof.
114: */
115: public boolean canFindNextProof() {
116: if (isEmpty()) {
117: return false;
118: }
119:
120: /*
121: * If we have already found a proof, the next proof may
122: * come by finding another proof of the tail.
123: */
124: if (headInvolved) {
125: if (tail().canFindNextProof()) {
126: return true;
127: }
128: }
129:
130: /*
131: * Prove our structures or give up. If the head is provable,
132: * it means the head has unified with another rule in the
133: * program. Our task then is to establish that either the
134: * tail is empty, or that it is provable. "Can establish"
135: * means is empty or provable.
136: */
137: while (true) {
138: headInvolved = head().canFindNextProof();
139: if (!headInvolved) {
140: return false;
141: }
142:
143: if (tail().canEstablish()) {
144: return true;
145: }
146: }
147: }
148:
149: /**
150: * Return the home of this dynamic rule's variables.
151: *
152: * @return the home of this dynamic rule's variables
153: */
154: public Scope getScope() {
155: return scope;
156: }
157:
158: /**
159: * Return <code>true</code> if this rule contains no
160: * structures.
161: *
162: * @return <code>true</code> if this rule contains no
163: * structures.
164: */
165: public boolean isEmpty() {
166: return structures.length == 0;
167: }
168:
169: /**
170: * Return a variable of the given name.
171: *
172: * @return a variable of the given name
173: *
174: * @param String the name to look up
175: */
176: public Variable lookup(String name) {
177: return scope.lookup(name);
178: }
179:
180: /**
181: * Create provable versions of an input array of structures.
182: */
183: protected static Structure[] provableStructures(AxiomSource as,
184: Scope scope, Structure[] structures) {
185:
186: Structure[] provables = new Structure[structures.length];
187:
188: for (int i = 0; i < structures.length; i++) {
189: Structure s = structures[i];
190:
191: // a "fact" is a rule asks if the fact is a known
192: // fact, and must consult the ps to find out
193: if (s instanceof Fact) {
194: provables[i] = new ConsultingStructure(as, s.functor,
195: s.terms);
196: } else {
197: provables[i] = (Structure) structures[i].copyForProof(
198: as, scope);
199: }
200: }
201: return provables;
202: }
203:
204: /**
205: * Returns the series of structures which, if proven, prove
206: * the truth of the head.
207: *
208: * @return the tail of this rule
209: */
210: public DynamicRule resolvent() {
211: return tail();
212: }
213:
214: /**
215: * Returns the series of structures after the head.
216: *
217: * @return the tail of this rule
218: */
219: public DynamicRule tail() {
220: if (tail == null) {
221: int len = structures.length;
222: Structure[] rest = new Structure[len - 1];
223:
224: System.arraycopy(structures, 1, rest, 0, len - 1);
225: tail = new DynamicRule(as, scope, rest);
226: }
227: return tail;
228: }
229:
230: /**
231: * Returns this executable rule's variables.
232: *
233: * @return unification a collection of variables from this
234: * rule
235: */
236: public Unification variables() {
237: if (structures.length == 0) {
238: return Unification.empty;
239: }
240:
241: /*
242: * The following approach keeps the variables in the order they
243: * appear in the rule.
244: */
245:
246: return head().variables().append(tail().variables());
247: }
248: }
|