001: /*
002: * $Id: ConsultingStructure.java,v 1.1 2003/08/19 01:12:57 jonesde Exp $
003: *
004: * Copyright (c) 1999 Steven J. Metsker.
005: * Copyright (c) 2001 The Open For Business Project - www.ofbiz.org
006: *
007: * Permission is hereby granted, free of charge, to any person obtaining a
008: * copy of this software and associated documentation files (the "Software"),
009: * to deal in the Software without restriction, including without limitation
010: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
011: * and/or sell copies of the Software, and to permit persons to whom the
012: * Software is furnished to do so, subject to the following conditions:
013: *
014: * The above copyright notice and this permission notice shall be included
015: * in all copies or substantial portions of the Software.
016: *
017: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
018: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
019: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
020: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
021: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
022: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
023: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
024: */
025:
026: package org.ofbiz.rules.engine;
027:
028: /**
029: * A ConsultingStructure is structure that can prove itself against an axiom source supplied with the constructor.
030: * <p>
031: * When a rule creates a dynamic version of itself, a normal
032: * structure will create a ConsultingStructure counterpart
033: * that uses the rule's scope, and that consults a given
034: * axiom source (such as a Program).
035: * <p>
036: * The primary behavior that a ConsultingStructure adds
037: * is the ability to prove itself.
038: *
039: * @author Steven J. Metsker
040: * @version 1.0
041: */
042: public class ConsultingStructure extends Structure {
043: protected AxiomSource source;
044: protected AxiomEnumeration axioms;
045: protected Unification currentUnification;
046: protected DynamicRule resolvent;
047:
048: /**
049: * Constructs a consulting structure with the specified functor
050: * and terms, to consult against the supplied axiom source.
051: * This constructor is for use by Structure.
052: */
053: protected ConsultingStructure(AxiomSource source, Object functor,
054: Term[] terms) {
055: super (functor, terms);
056: if (source == null)
057: throw new IllegalArgumentException(
058: "Cannot create ConsultingStructure with a null source");
059: this .source = source;
060: }
061:
062: /**
063: * Returns the axioms that a consulting structure can
064: * consult. Note that after canUnify fails, this object will
065: * set its axioms to null, which forces its proving
066: * attempts to start over at the beginning of the source.
067: */
068: protected AxiomEnumeration axioms() {
069: if (axioms == null) {
070: axioms = source.axioms(this );
071: }
072: return axioms;
073: }
074:
075: /**
076: * Tests if this structure can find another proof, and, if so,
077: * sets this structure's variables to the values that make the
078: * proof true.
079: *
080: * @return <code>true</code> if this structure can find another
081: * proof.
082: */
083: public boolean canFindNextProof() {
084:
085: /*
086: * A consulting structure proves itself by unifying with rule
087: * in a program. When that rule has more than one structure,
088: * the proving structure takes the tail of the rule as its
089: * "resolvent". The resolvent is the remainder of the rule,
090: * which, if proven true, confirms the truth of this
091: * structure. The resolvent may have multiple different
092: * proofs, and each of these counts as a new proof of this
093: * structure.
094: */
095: if (resolvent != null) {
096: if (resolvent.canFindNextProof()) {
097: return true;
098: }
099: }
100: while (true) {
101:
102: /*
103: * No hogging the CPU! Who knows? We might be in a tight
104: * loop that the user wants to halt. For example, with the
105: * program "loop :- loop;" and the query "loop", we need
106: * to distract the proof dog enough to let a halt button
107: * click come through.
108: */
109: Thread.yield();
110:
111: /*
112: * Find a new axiom to prove.
113: */
114: unbind();
115: if (!canUnify()) {
116: axioms = null;
117: return false;
118: }
119:
120: /*
121: * Show that the unifying axiom's remainder is either
122: * empty or provable.
123: */
124: if (resolvent.canEstablish()) {
125: return true;
126: }
127: }
128: }
129:
130: /**
131: * Return true if this structure can unify with another rule in the
132: * program.
133: * <p>
134: * A consulting structure proves itself true by unifying with
135: * the head of a rule in a program, and then asking the tail
136: * of that rule to prove itself. Unification is a kind of
137: * matching. Two structures unify if they have equal functors,
138: * and the terms all unify. A variable unifies with a
139: * structure simply by setting its instantiation to be the
140: * structure.
141: *
142: * <p>
143: * For example, the following structures can unify:
144: * <blockquote><pre>
145: * starred(jamesCagney, Title, Year)
146: * starred(jamesCagney, "Yankee Doodle Dandy", 1942)
147: * </pre></blockquote>
148: *
149: * When these structures unify, the variable Title will bind
150: * itself to "Yankee Doodle Dandy", and Year will bind to 1942.
151: * To be more specific, Title will bind to the atom
152: * whose functor is "Yankee Doodle Dandy". Year will bind to the
153: * atom whose functor is the number 1942.
154: *
155: * @return <code>true</code>, if this structure can unify with
156: * an axiom in the axiom source
157: */
158: protected boolean canUnify() {
159: while (axioms().hasMoreAxioms()) {
160: Axiom a = axioms().nextAxiom();
161: Structure h = a.head();
162:
163: if (!functorAndArityEquals(h)) {
164: continue;
165: }
166: DynamicAxiom aCopy = a.dynamicAxiom(source);
167:
168: currentUnification = aCopy.head().unify(this );
169: resolvent = null;
170: if (currentUnification != null) {
171: resolvent = aCopy.resolvent();
172: return true;
173: }
174: }
175: return false;
176: }
177:
178: /**
179: * Release the variable bindings that the last unification
180: * produced.
181: */
182: protected void unbind() {
183: if (currentUnification != null) {
184: currentUnification.unbind();
185: }
186: currentUnification = null;
187: resolvent = null;
188: }
189: }
|