Package org.drools.reteoo

Source Code of org.drools.reteoo.LeftTupleSource

/*
* Copyright 2005 JBoss Inc
*
* 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.reteoo;

import static org.drools.core.util.BitMaskUtil.intersect;
import static org.drools.reteoo.PropertySpecificUtil.calculateNegativeMask;
import static org.drools.reteoo.PropertySpecificUtil.calculatePositiveMask;
import static org.drools.reteoo.PropertySpecificUtil.getSettableProperties;
import static org.drools.reteoo.PropertySpecificUtil.isPropertyReactive;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.List;

import org.drools.base.ClassObjectType;
import org.drools.common.BaseNode;
import org.drools.common.InternalFactHandle;
import org.drools.common.InternalWorkingMemory;
import org.drools.common.RuleBasePartitionId;
import org.drools.reteoo.builder.BuildContext;
import org.drools.rule.Pattern;
import org.drools.spi.ClassWireable;
import org.drools.spi.ObjectType;
import org.drools.spi.PropagationContext;

/**
* A source of <code>ReteTuple</code> s for a <code>TupleSink</code>.
*
* <p>
* Nodes that propagate <code>Tuples</code> extend this class.
* </p>
*
* @see LeftTupleSource
* @see LeftTuple
*/
public abstract class LeftTupleSource extends BaseNode
        implements
        Externalizable {

    private long                      leftDeclaredMask;
    private long                      leftInferredMask;
    private long                      leftNegativeMask;


    /** The left input <code>TupleSource</code>. */
    protected LeftTupleSource         leftInput;

   
    // ------------------------------------------------------------
    // Instance members
    // ------------------------------------------------------------

    /** The destination for <code>Tuples</code>. */
    protected LeftTupleSinkPropagator sink;

   
    private transient int              leftInputOtnId;

    // ------------------------------------------------------------
    // Constructors
    // ------------------------------------------------------------
    public LeftTupleSource() {

    }

    /**
     * Single parameter constructor that specifies the unique id of the node.
     *
     * @param id
     */
    protected LeftTupleSource(final int id,
                    final RuleBasePartitionId partitionId,
                    final boolean partitionsEnabled) {
        super( id, partitionId, partitionsEnabled );
        this.sink = EmptyLeftTupleSinkAdapter.getInstance();
    }

    // ------------------------------------------------------------
    // Instance methods
    // ------------------------------------------------------------
    public void readExternal(ObjectInput in) throws IOException,
                                            ClassNotFoundException {
        super.readExternal( in );
        sink = (LeftTupleSinkPropagator) in.readObject();
        leftInput = (LeftTupleSource) in.readObject();       
        leftDeclaredMask = in.readLong();
        leftInferredMask = in.readLong();
        leftNegativeMask = in.readLong();
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        super.writeExternal( out );
        out.writeObject( sink );
        out.writeObject( leftInput );       
        out.writeLong( leftDeclaredMask );
        out.writeLong( leftInferredMask );
        out.writeLong( leftNegativeMask );
    }
   
    public abstract LeftTuple createPeer(LeftTuple original);
   
    public void addTupleSink(final LeftTupleSink tupleSink) {
        addTupleSink(tupleSink, null);
    }
   
    public LeftTupleSource getLeftTupleSource() {
        return leftInput;
    }

    public void setLeftTupleSource(LeftTupleSource leftInput) {
        this.leftInput = leftInput;
    }

    /**
    public LeftTupleSource getLeftTupleSource() {
    return leftInput;
  }

  public void setLeftTupleSource(LeftTupleSource leftInput) {
    this.leftInput = leftInput;
  }

  /**
     * Adds the <code>TupleSink</code> so that it may receive
     * <code>Tuples</code> propagated from this <code>TupleSource</code>.
     *
     * @param tupleSink
     *            The <code>TupleSink</code> to receive propagated
     *            <code>Tuples</code>.
     */
    protected void addTupleSink(final LeftTupleSink tupleSink, final BuildContext context) {
        this.sink = addTupleSink(this.sink, tupleSink, context);
    }

    protected LeftTupleSinkPropagator addTupleSink(final LeftTupleSinkPropagator sinkPropagator, final LeftTupleSink tupleSink, final BuildContext context) {
        if ( sinkPropagator instanceof EmptyLeftTupleSinkAdapter ) {
            // otherwise, we use the lighter synchronous propagator
            return new SingleLeftTupleSinkAdapter( this.getPartitionId(), tupleSink );
        }

        if ( sinkPropagator instanceof SingleLeftTupleSinkAdapter ) {
            final CompositeLeftTupleSinkAdapter sinkAdapter;
            sinkAdapter = new CompositeLeftTupleSinkAdapter( this.getPartitionId() );
            sinkAdapter.addTupleSink( sinkPropagator.getSinks()[0] );
            sinkAdapter.addTupleSink( tupleSink );
            return sinkAdapter;
        }

        ((CompositeLeftTupleSinkAdapter) sinkPropagator).addTupleSink( tupleSink );
        return sinkPropagator;
    }

    /**
     * Removes the <code>TupleSink</code>
     *
     * @param tupleSink
     *            The <code>TupleSink</code> to remove
     */
    protected void removeTupleSink(final LeftTupleSink tupleSink) {
        if ( this.sink instanceof EmptyLeftTupleSinkAdapter ) {
            throw new IllegalArgumentException( "Cannot remove a sink, when the list of sinks is null" );
        }

        if ( this.sink instanceof SingleLeftTupleSinkAdapter ) {
            this.sink = EmptyLeftTupleSinkAdapter.getInstance();
        } else {
            final CompositeLeftTupleSinkAdapter sinkAdapter = (CompositeLeftTupleSinkAdapter) this.sink;
            sinkAdapter.removeTupleSink( tupleSink );
            if ( sinkAdapter.size() == 1 ) {
                this.sink = new SingleLeftTupleSinkAdapter( this.getPartitionId(), sinkAdapter.getSinks()[0] );
            }
        }
    }

    public LeftTupleSinkPropagator getSinkPropagator() {
        return this.sink;
    }

    public abstract void updateSink(LeftTupleSink sink,
                                    PropagationContext context,
                                    InternalWorkingMemory workingMemory);

    public boolean isInUse() {
        return this.sink.size() > 0;
    }

    protected final void initMasks(BuildContext context,
                                   LeftTupleSource leftInput) {
        initDeclaredMask( context, leftInput );
        initInferredMask( leftInput );
    }

    protected void initDeclaredMask(BuildContext context,
                                    LeftTupleSource leftInput) {
        if ( context == null || context.getLastBuiltPatterns() == null ) {
            // only happens during unit tests
            leftDeclaredMask = Long.MAX_VALUE;
            return;
        }

        if ( leftInput.getType() != NodeTypeEnums.LeftInputAdapterNode) {
            // BetaNode's not after LIANode are not relevant for left mask property specific, so don't block anything.
            leftDeclaredMask = Long.MAX_VALUE;
            return;
        }

        Pattern pattern = context.getLastBuiltPatterns()[1]; // left input pattern

        ObjectType objectType;
        if (pattern == null || this.getType() == NodeTypeEnums.AccumulateNode) {
            ObjectSource objectSource = ((LeftInputAdapterNode)leftInput).getParentObjectSource();
            if ( objectSource.getType() != NodeTypeEnums.ObjectTypeNode) {
                leftDeclaredMask = Long.MAX_VALUE;
                return;
            }
            objectType = ((ObjectTypeNode) objectSource).getObjectType();
        } else {
            objectType = pattern.getObjectType();
        }

        if ( !(objectType instanceof ClassObjectType) ) {
            // Only ClassObjectType can use property specific
            leftDeclaredMask = Long.MAX_VALUE;
            return;
        }

        Class objectClass = ((ClassWireable) objectType).getClassType();
        if ( isPropertyReactive(context, objectClass) ) {
            // TODO: at the moment if pattern is null (e.g. for eval node) we cannot calculate the mask, so we leave it to 0
            if ( pattern != null ) {
                List<String> leftListenedProperties = pattern.getListenedProperties();
                List<String> settableProperties = getSettableProperties( context.getRuleBase(), objectClass );
                leftDeclaredMask = calculatePositiveMask( leftListenedProperties, settableProperties );
                leftNegativeMask = calculateNegativeMask( leftListenedProperties, settableProperties );
                setLeftListenedProperties(leftListenedProperties);
            }
        } else {
            // if property specific is not on, then accept all modification propagations
            leftDeclaredMask = Long.MAX_VALUE;
        }
    }

    protected void setLeftListenedProperties(List<String> leftListenedProperties) { }

    protected void initInferredMask(LeftTupleSource leftInput) {
        LeftTupleSource unwrappedLeft = unwrapLeftInput(leftInput);
        if ( unwrappedLeft.getType() == NodeTypeEnums.LeftInputAdapterNode && ((LeftInputAdapterNode)unwrappedLeft).getParentObjectSource().getType() == NodeTypeEnums.AlphaNode ) {
            AlphaNode alphaNode = (AlphaNode) ((LeftInputAdapterNode)unwrappedLeft).getParentObjectSource();
            leftInferredMask = alphaNode.updateMask( leftDeclaredMask );
        } else {
            leftInferredMask = leftDeclaredMask;
        }
        leftInferredMask &= (Long.MAX_VALUE - leftNegativeMask);
    }

    private LeftTupleSource unwrapLeftInput(LeftTupleSource leftInput) {
        if (leftInput.getType() == NodeTypeEnums.FromNode) {
            return ((FromNode)leftInput).getLeftTupleSource();
        }
        return leftInput;
    }

    public void modifyLeftTuple(InternalFactHandle factHandle,
                                ModifyPreviousTuples modifyPreviousTuples,
                                PropagationContext context,
                                InternalWorkingMemory workingMemory) {
        doModifyLeftTuple( factHandle, modifyPreviousTuples, context, workingMemory,
                           (LeftTupleSink) this, getLeftInputOtnId(), getLeftInferredMask());
    }

    public static void doModifyLeftTuple(InternalFactHandle factHandle,
                                         ModifyPreviousTuples modifyPreviousTuples,
                                         PropagationContext context,
                                         InternalWorkingMemory workingMemory,
                                         LeftTupleSink sink,
                                         int leftInputOtnId,
                                         long leftInferredMask) {
        LeftTuple leftTuple = modifyPreviousTuples.peekLeftTuple();
        while ( leftTuple != null && leftTuple.getLeftTupleSink().getLeftInputOtnId() < leftInputOtnId ) {
            modifyPreviousTuples.removeLeftTuple();
            leftTuple.setPropagationContext( context );
           
//            // we skipped this node, due to alpha hashing, so retract now
//            if ( leftTuple.getMemory() != null && leftTuple.getMemory().isStagingMemory() ) {  // can be null for RTN, or no unlinking
//                // this is only possible when unlinking is enabled
//                leftTuple.getMemory().remove( leftTuple ); // could be in liam staging or segmentmemory staging, but it shouldn't matter
//                LiaNodeMemory lm = ( LiaNodeMemory ) workingMemory.getNodeMemory( (LeftInputAdapterNode) sink.getLeftTupleSource() );
//                lm.setCounter( lm.getCounter() - 1 ); // we need this to track when we unlink
//                if ( lm.getCounter() == 0 ) {
//                    lm.unlinkNode( workingMemory );
//                }               
//            } else {
//            leftTuple.getLeftTupleSink().retractLeftTuple( leftTuple,
//                                                           context,
//                                                           workingMemory );
//            }
           
            ((LeftInputAdapterNode) leftTuple.getLeftTupleSink().getLeftTupleSource()).retractLeftTuple( leftTuple,
                                                                                                         context,
                                                                                                         workingMemory );
           

           
            leftTuple = modifyPreviousTuples.peekLeftTuple();
        }

        if ( leftTuple != null && leftTuple.getLeftTupleSink().getLeftInputOtnId() == leftInputOtnId ) {
            modifyPreviousTuples.removeLeftTuple();
            leftTuple.reAdd();
            leftTuple.setPropagationContext( context );
            if ( intersect( context.getModificationMask(), leftInferredMask ) ) {               
                // LeftTuple previously existed, so continue as modify, unless it's currently staged
                sink.modifyLeftTuple( leftTuple,
                                      context,
                                      workingMemory );
               
//                if ( leftTuple.getMemory() == null || !leftTuple.getMemory().isStagingMemory() ) { // can be null for RTN, or unlinking is off                   
//                    sink.modifyLeftTuple( leftTuple,
//                                          context,
//                                          workingMemory );
//                } // else LeftTuple is still staged, hasn't propagated yet
            }
        } else {
            if ( intersect( context.getModificationMask(), leftInferredMask ) ) {
                // LeftTuple does not exist, so create and continue as assert
               
                LeftTuple newLeftTuple = sink.createLeftTuple( factHandle,
                                                               sink,
                                                               true );
                newLeftTuple.setPropagationContext( context );
               
//                LeftInputAdapterNode liaNode = ((LeftInputAdapterNode) sink.getLeftTupleSource());
//                if ( liaNode.isUnlinkingEnabled() ) {
//                    // Add it to the lia node for lazy propagation on linking
//                    LiaNodeMemory lm = ( LiaNodeMemory ) workingMemory.getNodeMemory( liaNode );
//                    if ( lm.getSegmentMemory() == null ) {
//                        BetaNode.createNodeSegmentMemory( liaNode, workingMemory ); // initialises for all nodes in segment, including this one
//                    }         
//                    if ( lm.getStagedLeftTupleList().size() == 0 ) {
//                        // link. We do this on staged tuples, instead of entire count, as the lazy agenda might need re-activating
//                        lm.linkNode( workingMemory );
//                    }           
//                    lm.getStagedLeftTupleList().add( newLeftTuple );
//                    lm.setCounter( lm.getCounter() + 1 ); // we need this to track when we unlink
//                } else {
//     
//                }
                sink.assertLeftTuple( newLeftTuple,
                                      context,
                                      workingMemory );
            }
        }

        //        // cast is safe, as LIANode never has this method called
        //        LeftTupleSink sink = (LeftTupleSink)this;
        //        LeftTuple leftTuple = modifyPreviousTuples.removeLeftTuple(sink);
        //        if ( leftTuple != null ) {
        //            leftTuple.reAdd();
        //        }
        //
        //        if ( intersect(context.getModificationMask(), leftInferredMask) ) {
        //            if ( leftTuple != null ) {
        //                // LeftTuple previously existed, so continue as modify
        //                sink.modifyLeftTuple( leftTuple,
        //                        context,
        //                        workingMemory );
        //            } else {
        //                // LeftTuple does not exist, so create and continue as assert
        //                sink.assertLeftTuple( sink.createLeftTuple( factHandle,
        //                                                            sink,
        //                                                            true ),
        //                                      context,
        //                                      workingMemory );
        //            }
        //        }
    }
   
    public long getLeftDeclaredMask() {
        return leftDeclaredMask;
    }

    public long getLeftInferredMask() {
        return leftInferredMask;
    }

    protected void setLeftInferredMask(long leftInferredMask) {
        this.leftInferredMask = leftInferredMask;
    }

    public long getLeftNegativeMask() {
        return leftNegativeMask;
    }

    public int getLeftInputOtnId() {
        return leftInputOtnId;
    }

    public void setLeftInputOtnId(int leftInputOtnId) {
        this.leftInputOtnId = leftInputOtnId;
    }

    protected abstract ObjectTypeNode getObjectTypeNode();

    public ObjectType getObjectType() {
        ObjectTypeNode objectTypeNode = getObjectTypeNode();
        return objectTypeNode != null ? objectTypeNode.getObjectType() : null;
    }
   
    public boolean isUnlinkingEnabled() {
        return false;
    }
}
TOP

Related Classes of org.drools.reteoo.LeftTupleSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.