/** * Do the business of this node. The 2-input nodes, on receiving a token, have to do several * things, and their actions change based on whether it's an ADD or REMOVE, and whether it's the * right or left input! * * <PRE> * * ********** For ADDs, left input: * 1) Look for this token in the left memory. If it's there, do nothing; * If it's not, add it to the left memory. * * 2) Perform all this node's tests on this token and each of the right- * memory tokens. For any right token for which they succeed: * * 3) a) append the right token to a copy of this token. b) do a * CallNode on each of the successors using this new token. * * ********** For ADDs, right input: * * 1) Look for this token in the right memory. If it's there, do nothing; * If it's not, add it to the right memory. * * 2) Perform all this node's tests on this token and each of the left- * memory tokens. For any left token for which they succeed: * * 3) a) append this token to a copy of the left token. b) do a * CallNode on each of the successors using this new token. * * ********** For REMOVEs, left input: * * 1) Look for this token in the left memory. If it's there, remove it; * else do nothing. * * 2) Perform all this node's tests on this token and each of the right- * memory tokens. For any right token for which they succeed: * * 3) a) append the right token to a copy of this token. b) do a * CallNode on each of the successors using this new token. * * ********** For REMOVEs, right input: * * 1) Look for this token in the right memory. If it's there, remove it; * else do nothing. * * 2) Perform all this node's tests on this token and each of the left- * memory tokens. For any left token for which they succeed: * * 3) a) append this token to a copy of the left token. b) do a * CallNode on each of the successors using this new token. * * </PRE> */ boolean CallNode(Token token, int callType) throws ReteException { // the four cases listed above are implemented in order. // debugPrint(token, callType); Token tmp; switch (callType) { case Node.LEFT: switch (token.tag) { case RU.ADD: case RU.UPDATE: if ((tmp = findInMemory(left, token)) == null) left.addElement(token); runTestsVaryRight(token); break; case RU.REMOVE: if ((tmp = findInMemory(left, token)) != null) left.removeElement(tmp); runTestsVaryRight(token); break; default: throw new ReteException( "Node2::CallNode", "Bad tag in token", String.valueOf(token.tag)); } // switch token.tag break; // case Node.LEFT; case Node.RIGHT: switch (token.tag) { case RU.UPDATE: case RU.ADD: if ((tmp = findInMemory(right, token)) == null) right.addElement(token); runTestsVaryLeft(token); break; case RU.REMOVE: if ((tmp = findInMemory(right, token)) != null) right.removeElement(tmp); runTestsVaryLeft(token); break; default: throw new ReteException( "Node2::CallNode", "Bad tag in token", String.valueOf(token.tag)); } // switch token.tag break; // case Node.RIGHT default: throw new ReteException("Node2::CallNode", "Bad callType", String.valueOf(callType)); } // switch callType // the runTestsVary* routines pass messages on to the successors. return true; }
/** * The system was designed so that right-input tokens have only one fact in them. Furthermore, * they'll all have the same class type! As an optimization, then, we could skip the size check * and class comparison. For now, I'm leaving it in, using a general comparison function in the * Token class. In addition, we're assuming a token can only appear once; this is also by design, * and should always be true, unless we implement fact duplication, which CLIPS has as an option. * The user can always simulate this by using serial #s for facts. * * @returns null if not found, the found token otherwise. */ protected final Token findInMemory(TokenVector v, Token t) { Token tmp; int size = v.size(); for (int i = 0; i < size; i++) { tmp = v.elementAt(i); if (t.sortcode != tmp.sortcode) continue; if (t.data_equals(tmp)) return tmp; } return null; }
/** * Run all the tests on a given (left) token and every token in the right memory. For the true * ones, assemble a composite token and pass it along to the successors. */ protected void runTestsVaryRight(Token lt) throws ReteException { int size = right.size(); for (int i = 0; i < size; i++) { Token rt = right.elementAt(i); Token nt = appendToken(lt, rt); if (runTests(lt, rt, nt)) { int nsucc = _succ.length; for (int j = 0; j < nsucc; j++) { Successor s = _succ[j]; s.node.CallNode(nt, s.callType); } } } }
/** * Run all the tests on a given (right) token and every token in the left memory. For the true * ones, assemble a composite token and pass it along to the successors. */ protected void runTestsVaryLeft(Token rt) throws ReteException { int size = left.size(); for (int i = 0; i < size; i++) { Token lt = left.elementAt(i); Token nt = appendToken(lt, rt); if (runTests(lt, rt, nt)) { // the new token has the *left* token's tag at birth... nt.tag = rt.tag; int nsucc = _succ.length; for (int j = 0; j < nsucc; j++) { Successor s = _succ[j]; s.node.CallNode(nt, s.callType); } } } }