All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.drools.core.common.TruthMaintenanceSystem Maven / Gradle / Ivy

There is a newer version: 9.44.0.Final
Show newest version
/*
 * Copyright 2005 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.drools.core.common;

import org.drools.core.RuleBaseConfiguration.AssertBehaviour;
import org.drools.core.beliefsystem.BeliefSet;
import org.drools.core.beliefsystem.BeliefSystem;
import org.drools.core.beliefsystem.simple.SimpleMode;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.impl.StatefulKnowledgeSessionImpl;
import org.drools.core.reteoo.ObjectTypeConf;
import org.drools.core.spi.Activation;
import org.drools.core.spi.PropagationContext;
import org.drools.core.util.ObjectHashMap;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.internal.runtime.beliefs.Mode;

import java.util.Iterator;

import static org.drools.core.common.ClassAwareObjectStore.getActualClass;

/**
 * The Truth Maintenance System is responsible for tracking two things. Firstly
 * It maintains a Map to track the classes with the same Equality, using the
 * EqualityKey. The EqualityKey has an internal data structure which references
 * all the handles which are equal. Secondly It maintains another map tracking
 * the justifications for logically asserted facts.
 */
public class TruthMaintenanceSystem {

    private InternalWorkingMemoryEntryPoint ep;

    private ObjectTypeConfigurationRegistry typeConfReg;

    private ObjectHashMap         equalityKeyMap;

    private BeliefSystem          defaultBeliefSystem;

    private AssertBehaviour       assertBehaviour;

    public TruthMaintenanceSystem() {}

    public TruthMaintenanceSystem(StatefulKnowledgeSessionImpl wm,
                                  InternalWorkingMemoryEntryPoint ep) {
        this.ep = ep;

        assertBehaviour = ep.getKnowledgeBase().getConfiguration().getAssertBehaviour();

        typeConfReg = ep.getObjectTypeConfigurationRegistry();

        this.equalityKeyMap = new ObjectHashMap();
        this.equalityKeyMap.setComparator( EqualityKeyComparator.getInstance() );


        defaultBeliefSystem = wm.getKnowledgeBase().getConfiguration().getComponentFactory().getBeliefSystemFactory().createBeliefSystem(wm.getSessionConfiguration().getBeliefSystemType(), ep, this);
    }

    public ObjectHashMap getEqualityKeyMap() {
        return this.equalityKeyMap;
    }

    public Object put(final EqualityKey key) {
        return this.equalityKeyMap.put( key,
                                   key,
                                   false );
    }


    public InternalFactHandle insert(Object object,
                                     Object tmsValue,
                                     RuleImpl rule,
                                     Activation activation) {
        ObjectTypeConf typeConf = typeConfReg.getObjectTypeConf( ep.getEntryPoint(),  object );
        if ( !typeConf.isTMSEnabled()) {
            enableTMS(object, typeConf);
        }

        // get the key for other "equal" objects, returns null if none exist
        EqualityKey key = get(object);


        InternalFactHandle fh = null;
        if ( key == null ) {
            // no EqualityKey exits, so we construct one. We know it can only be justified.
            fh =  ep.getHandleFactory().newFactHandle(object, typeConf, ep.getInternalWorkingMemory(), ep );
            key = new EqualityKey( fh, EqualityKey.JUSTIFIED );
            fh.setEqualityKey( key );
            put(key);
        } else {
            fh = key.getLogicalFactHandle();
            if ( fh == null ) {
                // The EqualityKey exists, but this is the first logical object in the key.
                fh =  ep.getHandleFactory().newFactHandle(object, typeConf, ep.getInternalWorkingMemory(), ep );
                key.setLogicalFactHandle( fh );
                fh.setEqualityKey( key );
            }
        }

        // Any logical propagations are handled via the TMS.addLogicalDependency
        fh = addLogicalDependency(fh,
                                  object,
                                  tmsValue,
                                  activation,
                                  activation.getPropagationContext(),
                                  rule,
                                  typeConf);

        return fh;
    }

    public void delete(FactHandle fh) {
        if ( fh == null ) {
            return;
        }
        InternalFactHandle ifh = (InternalFactHandle) fh;
        // This will clear out the logical entries for the FH. However the FH and EqualityKey remain, if it's stated

        // Update the equality key, which maintains a list of stated FactHandles
        final EqualityKey key = ifh.getEqualityKey();

        if ( key.getLogicalFactHandle() != fh ) {
            throw new IllegalArgumentException( "The FactHandle did not originate from TMS : " + fh);
        }

        InternalWorkingMemory wm = ep.getInternalWorkingMemory();

        final PropagationContext propagationContext = ep.getPctxFactory().createPropagationContext( wm.getNextPropagationIdCounter(), PropagationContext.Type.DELETION,
                                                                                                    null, null, ifh,  ep.getEntryPoint());

        TruthMaintenanceSystemHelper.removeLogicalDependencies( ifh, propagationContext );

    }

    public EqualityKey get(final EqualityKey key) {
        return (EqualityKey) this.equalityKeyMap.get( key );
    }

    public EqualityKey get(final Object object) {
        EqualityKey key = (EqualityKey) this.equalityKeyMap.get( object );

        if ( key == null && assertBehaviour == AssertBehaviour.EQUALITY ) {
            // Edge case: another object X, equivalent (equals+hashcode) to "object" Y
            // has been previously stated. However, if X is a subclass of Y, TMS
            // may have not been enabled yet, and key would be null.
            InternalFactHandle fh = ep.getObjectStore().getHandleForObject(object);
            if ( fh != null ) {
                key = fh.getEqualityKey();
                if ( key == null ) {
                    // we use the FH's Object here, not the inserted object
                    ObjectTypeConf typeC = this.typeConfReg.getObjectTypeConf( ep.getEntryPoint(), fh.getObject() );
                    enableTMS( fh.getObject(), typeC );
                    key = fh.getEqualityKey();
                }
            }
        }

        return key;
    }

    public EqualityKey remove(final EqualityKey key) {
        return (EqualityKey) this.equalityKeyMap.remove( key );
    }

    /**
     * Adds a justification for the FactHandle to the justifiedMap.
     *
     * @param handle
     * @param activation
     * @param context
     * @param rule
     * @param typeConf 
     */
    public void readLogicalDependency(final InternalFactHandle handle,
                                      final Object object,
                                      final Object value,
                                      final Activation activation,
                                      final PropagationContext context,
                                      final RuleImpl rule,
                                      final ObjectTypeConf typeConf) {
        addLogicalDependency( handle, object, value, activation, context, rule, typeConf, true );
    }

    public InternalFactHandle addLogicalDependency(final InternalFactHandle handle,
                                                   final Object object,
                                                   final Object value,
                                                   final Activation activation,
                                                   final PropagationContext context,
                                                   final RuleImpl rule,
                                                   final ObjectTypeConf typeConf) {
        return addLogicalDependency( handle, object, value, activation, context, rule, typeConf, false );
    }

    public InternalFactHandle addLogicalDependency(final InternalFactHandle handle,
                                                   final Object object,
                                                   final Object value,
                                                   final Activation activation,
                                                   final PropagationContext context,
                                                   final RuleImpl rule,
                                                   final ObjectTypeConf typeConf,
                                                   final boolean read) {
        BeliefSystem beliefSystem = defaultBeliefSystem;
        if ( value != null && value instanceof Mode & !( value instanceof SimpleMode ) ) {
            Mode mode = (Mode) value;
            beliefSystem = (BeliefSystem) mode.getBeliefSystem();
        }

        BeliefSet beliefSet = handle.getEqualityKey().getBeliefSet();
        if ( beliefSet == null ) {
            if ( context.getType() == PropagationContext.Type.MODIFICATION ) {
                // if this was a  update, chances  are its trying  to retract a logical assertion
            }
            beliefSet = beliefSystem.newBeliefSet( handle );
            handle.getEqualityKey().setBeliefSet( beliefSet );
        }

        final LogicalDependency node = beliefSystem.newLogicalDependency( activation, beliefSet, object, value );
        activation.getRule().setHasLogicalDependency( true );

        activation.addLogicalDependency( node );


        if ( read ) {
            // used when deserialising
            beliefSystem.read( node, beliefSet, context, typeConf );
        } else {
            beliefSet = beliefSystem.insert( node, beliefSet, context, typeConf );
        }
        return beliefSet.getFactHandle();
    }

    public void clear() {
        this.equalityKeyMap.clear();
    }

    public BeliefSystem getBeliefSystem() {
        return defaultBeliefSystem;
    }

    /**
     * TMS will be automatically enabled when the first logical insert happens.
     *
     * We will take all the already asserted objects of the same type and initialize
     * the equality map.
     *
     * @param object the logically inserted object.
     * @param conf the type's configuration.
     */
    private void enableTMS(Object object, ObjectTypeConf conf) {
        Iterator it = ((ClassAwareObjectStore) ep.getObjectStore()).iterateFactHandles(getActualClass(object));

        while (it.hasNext()) {
            InternalFactHandle handle = it.next();
            if (handle != null && handle.getEqualityKey() == null) {
                EqualityKey key = new EqualityKey(handle);
                handle.setEqualityKey(key);
                key.setStatus(EqualityKey.STATED);
                put(key);
            }
        }

        // Enable TMS for this type.
        conf.enableTMS();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy