001: package org.ofbiz.rules.engine;
002:
003: /**
004: * <p><b>Title:</b> Structure
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 Structure is a functor associated with a number of terms;
029: * a functor can be any object. A term is an object that
030: * implements the Term interface, including structures and
031: * variables.
032: * <p>
033: * An example of a structure is:
034: * <blockquote><pre>
035: * starred(jamesCagney, "Yankee Doodle Dandy", Year)
036: * </pre></blockquote>
037: * This structure has the String <code>"starred"</code> as its
038: * functor. This structure's first term is another structure
039: * that has "jamesCagney" as its functor and no terms of its own.
040: * Similarly, the second term is a structure with the functor
041: * "Yankee Doodle Dandy" and no terms of its own. The third
042: * term is a variable, Year.
043: * <p>
044: * This particular example has two elements that favor a
045: * parser: the quotes around the film title and the
046: * capitalization of the variable. When using Structure and
047: * Variable directly, you do not need the kinds of clues a
048: * parser needs. So, Yankee Doodle Dandy is just another
049: * string, whose internal blanks are not at all confusing.
050: * Further, a variable can have any string as its name, not
051: * necessarily capitalized.
052: * <p>
053: * You can create the starred example with
054: * <blockquote><pre>
055: * Structure s = new Structure(
056: * "starred",
057: * new Term[]{
058: * new Structure("jamesCagney"),
059: * new Structure("Yankee Doodle Dandy"),
060: * new Variable("Year")});
061: * </pre></blockquote>
062: * To be able to prove itself against a program, a structure
063: * must appear in a Rule. Rules associate like-named variables
064: * in a "scope", which is essentially a dictionary. A rule
065: * makes an executable copy of itself by creating a new
066: * variable dictionary, and by making "consulting" copies of
067: * its structures.
068: *
069: * @author Steven J. Metsker
070: * @version 1.0
071: */
072: public class Structure implements Term {
073: protected Object functor;
074: protected Term[] terms;
075:
076: /** the empty list singleton */
077: public final static EmptyList emptyList = new EmptyList();
078:
079: /**
080: * Contructs a structure from the specified object.
081: *
082: * @param Object the functor for this structure
083: */
084: public Structure(Object functor) {
085: this (functor, new Term[0]);
086: }
087:
088: /**
089: * Constructs a structure with the specified functor and terms.
090: *
091: * @param Object the functor of the structure
092: *
093: * @param Term[] the terms of the structure, which may be
094: * either variables or other structures
095: */
096: public Structure(Object functor, Term[] terms) {
097: this .functor = functor;
098: this .terms = terms;
099: }
100:
101: /**
102: * Return the number of terms in this structure.
103: *
104: * @return the number of terms in this structure
105: */
106: public int arity() {
107: return terms.length;
108: }
109:
110: /**
111: * Returns <code>false</code>.
112: * <p>
113: * Objects of this class, the superclass of all structures,
114: * should not appear in dynamic rules. When a nondynamic
115: * rule creates its dynamic counterpart, it populates it
116: * with provable versions of its structures. A general
117: * <code>Structure</code> object will construct a <code>
118: * ConsultingStructure</code> when it participates in building
119: * a dynamic rule.
120: * <p>
121: * This particular method is almost never called. Subclasses
122: * implement more interesting behavior.
123: *
124: * @return <code>false</code>
125: */
126: public boolean canFindNextProof() {
127: return false;
128: }
129:
130: /**
131: * Create a <code>ConsultingStructure</code> counterpart that
132: * can unify with other structures.
133: *
134: * @param AxiomSource where to find axioms to prove
135: * against
136: *
137: * @param Scope the scope to use for variables in the
138: * <code>ConsultingStructure</code>
139: *
140: * @return a <code>ConsultingStructure</code> counterpart that
141: * can unify with other structures.
142: */
143: public Term copyForProof(AxiomSource as, Scope scope) {
144: Term[] newTerms = new Term[terms.length];
145:
146: for (int i = 0; i < terms.length; i++) {
147: newTerms[i] = terms[i].copyForProof(as, scope);
148: }
149: return new ConsultingStructure(as, functor, newTerms);
150: }
151:
152: /**
153: * Returns true if the supplied object is an equivalent
154: * structure.
155: *
156: * @param object the object to compare
157: *
158: * @return true, if the supplied object's functor equals
159: * this structure's functor, and both structures'
160: * terms are all equal
161: */
162: public boolean equals(Object o) {
163: if (!(o instanceof Structure))
164: return false;
165: Structure s = (Structure) o;
166:
167: if (!functorAndArityEquals(s)) {
168: return false;
169: }
170: for (int i = 0; i < terms.length; i++) {
171: if (!(terms[i].equals(s.terms[i]))) {
172: return false;
173: }
174: }
175: return true;
176: }
177:
178: /**
179: * Return this structure, if it is nonatomic, or just the
180: * functor, if this is an atom.
181: */
182: public Object eval() {
183: if (terms().length > 0) {
184: return this ;
185: }
186: return functor;
187: }
188:
189: /**
190: * Returns <code>true</code> if this structure's functor and
191: * number of terms match the supplied structure.
192: *
193: * @param Structure the structure to compare this one against
194: *
195: * @return <code>true</code> if this structure's functor and
196: * number of terms match the supplied structure
197: */
198: public boolean functorAndArityEquals(Structure s) {
199: return arity() == s.arity() && functor.equals(s.functor);
200: }
201:
202: /**
203: * This method helps the static list factories.
204: *
205: * A list is a structure whose functor is "." and that has two
206: * terms. The first term of a list can be any term; the second
207: * term of a list is another list, an empty list, or a
208: * variable.
209: * <p>
210: * This method accepts an array of terms and a tail, which must
211: * be a list structure or a variable. This method composes and
212: * returns a two-element array.
213: * <p>
214: * The first element of the returned array will always be the
215: * first element of the supplied terms array.
216: * <p>
217: * The second element of the returned array will be a list.
218: * This list will be a concatenation of the remainder of the
219: * given array with the supplied tail.
220: */
221: protected static Term[] headAndTail(Term[] terms, Term tail) {
222:
223: if (terms.length == 0) {
224: throw new InternalError("Cannot create a list with no head");
225: }
226:
227: Term[] headAndTail = new Term[2];
228:
229: headAndTail[0] = terms[0];
230:
231: if (terms.length == 1) {
232: headAndTail[1] = tail;
233: } else {
234: Term[] rest = new Term[terms.length - 1];
235:
236: System.arraycopy(terms, 1, rest, 0, rest.length);
237: headAndTail[1] = list(rest, tail);
238: }
239:
240: return headAndTail;
241: }
242:
243: /**
244: * Return true, if this structure is a list, which means it
245: * has an functor of ".", and has two terms, the second of which
246: * must be a list.
247: *
248: * @return true if this structure is a list
249: */
250: public boolean isList() {
251: return terms.length == 2 && functor.equals(".")
252: && terms[1].isList();
253: }
254:
255: /**
256: * Constructs a list that contains the supplied object, wrapped
257: * as Facts.
258: *
259: * @param Object[] the contents of the list
260: */
261: public static Structure list(Object[] objects) {
262: return list(Fact.facts(objects));
263: }
264:
265: /**
266: * Constructs a list from the given terms.
267: * <p>
268: * This constructor creates a list of two terms, regardless of
269: * the number of terms supplied here. The new list's first
270: * term is the first term of the supplied array. Its second
271: * term is a list of the remaining terms.
272: *
273: * @param Term[] the terms of the list
274: */
275:
276: public static Structure list(Term[] terms) {
277: return new Structure(".", headAndTail(terms, emptyList));
278: }
279:
280: /**
281: * Constructs a list that terminates with a known list, or a
282: * variable.
283: * <p>
284: * This allows construction of a list such as:
285: *
286: * <blockquote><pre>
287: * Variable head = new Variable("Head");
288: * Variable tail = new Variable("Tail");
289: * Structure ht = Structure.list(new Term[] {head}, tail);
290: * </pre></blockquote>
291: *
292: * @param Term[] the leading terms of the list. In practice,
293: * this array usually contains a single term.
294: *
295: * @param Term a list, or a variable that represents the tail
296: * of the list
297: */
298: public static Structure list(Term[] terms, Term tail) {
299: return new Structure(".", headAndTail(terms, tail));
300: }
301:
302: /**
303: * Returns a representation of this list as the inner part of
304: * some other list. This method is used by <code>toString()
305: * </code>.
306: */
307: public String listTailString() {
308: return ", " + listTermsToString();
309: }
310:
311: /**
312: * Return a textual represenation of this list's terms, with
313: * a normal representation of the first term, and with the
314: * second term as the tail of a list.
315: */
316: protected String listTermsToString() {
317: String s = terms[0].toString();
318:
319: if (terms.length > 1) {
320: s += terms[1].listTailString();
321: }
322: return s;
323: }
324:
325: /**
326: * Return the terms of this structure.
327: *
328: * @return the terms of this structure
329: */
330: public Term[] terms() {
331: return terms;
332: }
333:
334: /**
335: * Returns a string representation of this structure.
336: *
337: * @return a string representation of this structure
338: */
339: public String toString() {
340: if (isList()) {
341:
342: /*
343: * Show the brackets, the head, and the tail. The
344: * tail prints itself recursively, until the empty
345: * list stops the recursion.
346: */
347: return "[" + listTermsToString() + "]";
348: }
349: StringBuffer buf = new StringBuffer(functor.toString());
350:
351: if (terms.length > 0) {
352: buf.append("(");
353: for (int i = 0; i < terms.length; i++) {
354: if (i > 0) {
355: buf.append(", ");
356: }
357: buf.append(terms[i].toString());
358: }
359: buf.append(")");
360: }
361: return buf.toString();
362: }
363:
364: /**
365: * Unifies the terms in this structure with the terms in the
366: * given structure, and returns the variable bindings that
367: * result.
368: * <p>
369: * If two structures have equal functors and the same number of
370: * terms, they can unify if all of their terms unify. For
371: * example, the following structures can unify:
372: * <blockquote><pre>
373: * address(Detail, city(City), state(State))
374: * address(mall(fayette), city(lexington), state(ky))
375: * </pre></blockquote>
376: * The unification of these structures is:
377: * <blockquote><pre>
378: * Detail = mall(fayette),
379: * City = lexington,
380: * State = ky
381: * </pre></blockquote>
382: *
383: * @param Structure a structure to unify with
384: *
385: * @return the sum of the variables that bind to values to make
386: * the unification work.
387: */
388: public Unification unify(Structure s) {
389: if (!functorAndArityEquals(s)) {
390: return null;
391: }
392: Unification u = new Unification();
393: Term others[] = s.terms();
394:
395: for (int i = 0; i < terms().length; i++) {
396: Unification subUnification = terms()[i].unify(others[i]);
397:
398: if (subUnification == null) {
399: u.unbind();
400: return null;
401: }
402: u.append(subUnification);
403: }
404: return u;
405: }
406:
407: /**
408: * Unifies this structure with the supplied term.
409: * <p>
410: * This method dispatches the unify request to either a
411: * structure or a variable. The receiver will get a signature
412: * match from this object as a Structure, not just a Term.
413: *
414: * @param Term a term to unify with
415: *
416: * @return the sum of the variables that bind to values to make
417: * the unification work. Returns null if the
418: * unification fails.
419: */
420: public Unification unify(Term t) {
421: return t.unify(this );
422: }
423:
424: /**
425: * Unifies this structure with the supplied variable.
426: * <p>
427: * This method dispatches the unify request to the variable.
428: * Note that the variable may be instantiated to a structure
429: * that contains variables. An uninstantiated variable will
430: * bind to this structure, but an instantiated variable will
431: * forward the unification request to its instantiation.
432: *
433: * @param Term a term to unify with
434: *
435: * @return the sum of the variables that bind to values to make
436: * the unification work. Returns null if the
437: * unification fails.
438: */
439: public Unification unify(Variable v) {
440: return v.unify(this );
441: }
442:
443: /**
444: * Returns the variables of the terms of this structure.
445: * <p>
446: * Note that a structure may contain variables or other structures as
447: * terms. This method adds this structure's variables directly to the
448: * returned unification. In addition, this method adds in all the
449: * variables from the structures among this structure's terms.
450: * <p>
451: * For example, the variables of:
452: * <blockquote><pre>
453: * address(street(StreetName), city(CityName), State)
454: * </pre></blockquote>
455: * are StreetName, CityName, and State.
456: *
457: * @return unification all the variables of the terms of this
458: * structure
459: */
460: public Unification variables() {
461: Unification u = new Unification();
462:
463: if (terms.length > 0) {
464: for (int i = 0; i < terms().length; i++) {
465: u.append(terms[i].variables());
466: }
467: }
468: return u;
469: }
470: }
|