001: package org.drools.common;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.io.Serializable;
020: import java.util.HashSet;
021: import java.util.Iterator;
022: import java.util.Set;
023:
024: import org.drools.FactException;
025: import org.drools.rule.Rule;
026: import org.drools.spi.Activation;
027: import org.drools.spi.PropagationContext;
028: import org.drools.util.ObjectHashMap;
029: import org.drools.util.PrimitiveLongMap;
030: import org.w3c.dom.views.AbstractView;
031:
032: /**
033: * The Truth Maintenance System is responsible for tracking two things. Firstly
034: * It maintains a Map to track the classes with the same Equality, using the
035: * EqualityKey. The EqualityKey has an internal datastructure which references
036: * all the handles which are equal. Secondly It maintains another map tracking
037: * the justificiations for logically asserted facts.
038: *
039: * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
040: *
041: */
042: public class TruthMaintenanceSystem implements Serializable {
043:
044: private static final long serialVersionUID = 400L;
045:
046: private final AbstractWorkingMemory workingMemory;
047:
048: private final PrimitiveLongMap justifiedMap;
049:
050: private final ObjectHashMap assertMap;
051:
052: public TruthMaintenanceSystem(
053: final AbstractWorkingMemory workingMemory) {
054: this .workingMemory = workingMemory;
055:
056: this .justifiedMap = new PrimitiveLongMap(8, 32);
057: this .assertMap = new ObjectHashMap();
058: this .assertMap.setComparator(EqualityKeyComparator
059: .getInstance());
060: }
061:
062: public PrimitiveLongMap getJustifiedMap() {
063: return this .justifiedMap;
064: }
065:
066: public ObjectHashMap getAssertMap() {
067: return this .assertMap;
068: }
069:
070: public Object put(final EqualityKey key) {
071: return this .assertMap.put(key, key, false);
072: }
073:
074: public EqualityKey get(final EqualityKey key) {
075: return (EqualityKey) this .assertMap.get(key);
076: }
077:
078: public EqualityKey get(final Object object) {
079: return (EqualityKey) this .assertMap.get(object);
080: }
081:
082: public EqualityKey remove(final EqualityKey key) {
083: return (EqualityKey) this .assertMap.remove(key);
084: }
085:
086: /**
087: * An Activation is no longer true so it no longer justifies any of the logical facts
088: * it logically asserted. It iterates over the Activation's LinkedList of DependencyNodes
089: * it retrieves the justitication set for each DependencyNode's FactHandle and removes
090: * itself. If the Set is empty it retracts the FactHandle from the WorkingMemory.
091: *
092: * @param activation
093: * @param context
094: * @param rule
095: * @throws FactException
096: */
097: public void removeLogicalDependencies(final Activation activation,
098: final PropagationContext context, final Rule rule)
099: throws FactException {
100: final org.drools.util.LinkedList list = activation
101: .getLogicalDependencies();
102: if (list == null || list.isEmpty()) {
103: return;
104: }
105: for (LogicalDependency node = (LogicalDependency) list
106: .getFirst(); node != null; node = (LogicalDependency) node
107: .getNext()) {
108: final InternalFactHandle handle = (InternalFactHandle) node
109: .getFactHandle();
110: final Set set = (Set) this .justifiedMap.get(handle.getId());
111: if (set != null) {
112: set.remove(node);
113: WorkingMemoryAction action = new LogicalRetractCallback(
114: this , node, set, handle, context);
115: workingMemory.queueWorkingMemoryAction(action);
116: }
117: }
118: }
119:
120: public static class LogicalRetractCallback implements
121: WorkingMemoryAction {
122: private final TruthMaintenanceSystem tms;
123: private final LogicalDependency node;
124: private final Set set;
125: private final InternalFactHandle handle;
126: private final PropagationContext context;
127:
128: public LogicalRetractCallback(TruthMaintenanceSystem tms,
129: LogicalDependency node, Set set,
130: InternalFactHandle handle, PropagationContext context) {
131: this .tms = tms;
132: this .node = node;
133: this .set = set;
134: this .handle = handle;
135: this .context = context;
136: }
137:
138: public void execute(InternalWorkingMemory workingMemory) {
139:
140: if (set.isEmpty()) {
141: if (set.isEmpty()) {
142: this .tms.getJustifiedMap().remove(handle.getId());
143: // this needs to be scheduled so we don't upset the current
144: // working memory operation
145: workingMemory.retract(this .handle, false, true,
146: context.getRuleOrigin(), context
147: .getActivationOrigin());
148: }
149: }
150: }
151: }
152:
153: /**
154: * The FactHandle is being removed from the system so remove any logical dependencies
155: * between the justified FactHandle and its justifiers. Removes the FactHandle key
156: * from the justifiedMap. It then iterates over all the LogicalDependency nodes, if any,
157: * in the returned Set and removes the LogicalDependency node from the LinkedList maintained
158: * by the Activation.
159: *
160: * @see LogicalDependency
161: *
162: * @param handle - The FactHandle to be removed
163: * @throws FactException
164: */
165: public void removeLogicalDependencies(
166: final InternalFactHandle handle) throws FactException {
167: final Set set = (Set) this .justifiedMap.remove(handle.getId());
168: if (set != null && !set.isEmpty()) {
169: for (final Iterator it = set.iterator(); it.hasNext();) {
170: final LogicalDependency node = (LogicalDependency) it
171: .next();
172: node.getJustifier().getLogicalDependencies().remove(
173: node);
174: }
175: }
176: }
177:
178: /**
179: * Adds a justification for the FactHandle to the justifiedMap.
180: *
181: * @param handle
182: * @param activation
183: * @param context
184: * @param rule
185: * @throws FactException
186: */
187: public void addLogicalDependency(final InternalFactHandle handle,
188: final Activation activation,
189: final PropagationContext context, final Rule rule)
190: throws FactException {
191: final LogicalDependency node = new LogicalDependency(
192: activation, handle);
193: activation.getRule().setHasLogicalDependency(true);
194:
195: activation.addLogicalDependency(node);
196: Set set = (Set) this .justifiedMap.get(handle.getId());
197: if (set == null) {
198: if (context.getType() == PropagationContext.MODIFICATION) {
199: // if this was a update, chances are its trying to retract a logical assertion
200: }
201: set = new HashSet();
202: this.justifiedMap.put(handle.getId(), set);
203: }
204: set.add(node);
205: }
206: }
|