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

org.drools.core.common.DefaultFactHandle 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 java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

import org.drools.core.WorkingMemoryEntryPoint;
import org.drools.core.base.TraitHelper;
import org.drools.core.datasources.InternalDataSource;
import org.drools.core.factmodel.traits.TraitFactory;
import org.drools.core.factmodel.traits.TraitTypeEnum;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.reteoo.LeftTuple;
import org.drools.core.reteoo.ObjectTypeNode;
import org.drools.core.reteoo.RightTuple;
import org.drools.core.spi.Tuple;
import org.drools.core.util.AbstractBaseLinkedListNode;
import org.drools.core.util.StringUtils;
import org.kie.api.runtime.rule.FactHandle;

/**
 * Implementation of FactHandle.
 */
@XmlRootElement(name = "fact-handle")
@XmlAccessorType(XmlAccessType.NONE)
public class DefaultFactHandle extends AbstractBaseLinkedListNode
                              implements
                              InternalFactHandle {

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

    private static final long       serialVersionUID = 510l;
    /** Handle id. */

    static final String     FACT_FORMAT_VERSION = "0";

    private int                     id;
    private long                    recency;
    private Object                  object;
    private EqualityKey             key;
    private int                     objectHashCode;
    private int                     identityHashCode;

    private WorkingMemoryEntryPoint entryPoint;

    private boolean                 disconnected;

    private TraitTypeEnum           traitType;

    private boolean                 valid = true;

    private boolean                 negated;

    private String                  objectClassName;

    protected LinkedTuples          linkedTuples;

    private InternalFactHandle      parentHandle;

    // ----------------------------------------------------------------------
    // Constructors
    // ----------------------------------------------------------------------

    public DefaultFactHandle() {
    }

    public DefaultFactHandle(final int id,
            final Object object) {
        // this is only used by tests, left as legacy as so many test rely on it.
        this( id,
              object,
              id,
              null,
              false);
    }

    /**
     * Construct.
     *
     * @param id
     *            Handle id.
     */
    public DefaultFactHandle(final int id,
                             final Object object,
                             final long recency,
                             final WorkingMemoryEntryPoint wmEntryPoint) {
        this( id, determineIdentityHashCode( object ), object, recency, wmEntryPoint, false );
    }

    public DefaultFactHandle(final int id,
                             final Object object,
                             final long recency,
                             final WorkingMemoryEntryPoint wmEntryPoint,
                             final boolean isTraitOrTraitable ) {
        this( id, determineIdentityHashCode( object ), object, recency, wmEntryPoint, isTraitOrTraitable );
    }

    public DefaultFactHandle(final int id,
                             final int identityHashCode,
                             final Object object,
                             final long recency,
                             final WorkingMemoryEntryPoint wmEntryPoint,
                             final boolean isTraitOrTraitable ) {
        this.id = id;
        setEntryPoint( wmEntryPoint );
        this.recency = recency;
        setObject( object );
        this.identityHashCode = identityHashCode;
        this.traitType = isTraitOrTraitable ? determineTraitType() : TraitTypeEnum.NON_TRAIT;
    }

    public DefaultFactHandle(int id,
            String wmEntryPointId,
            int identityHashCode,
            int objectHashCode,
            long recency,
            Object object) {
        this.id = id;
        setEntryPoint( ( wmEntryPointId == null ) ? null : new DisconnectedWorkingMemoryEntryPoint( wmEntryPointId ) );
        this.recency = recency;
        setObject( object );
        this.identityHashCode = identityHashCode;
        this.objectHashCode = objectHashCode;
        this.disconnected = true;
        this.traitType = TraitTypeEnum.NON_TRAIT;
    }

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

    /**
     * @see Object
     */
    public boolean equals( final Object object ) {
        return this == object || ( object instanceof DefaultFactHandle && this.id == ( (DefaultFactHandle) object ).id );
    }

    public void disconnect() {
        this.key = null;
        this.linkedTuples = null;
        this.entryPoint = ( this.entryPoint == null ) ?
                          null :
                          new DisconnectedWorkingMemoryEntryPoint( this.entryPoint.getEntryPointId() );
        this.disconnected = true;
    }

    public boolean isNegated() {
        return negated;
    }

    public void setNegated(boolean negated) {
        this.negated = negated;
    }

    @Override
    public  K as( Class klass ) throws ClassCastException {
        if ( klass.isAssignableFrom( object.getClass() ) ) {
            return (K) object;
        } else if ( this.isTraitOrTraitable() ) {
            K k = TraitHelper.extractTrait( this, klass );
            if ( k != null ) {
                return  k;
            }
        }
        throw new ClassCastException( "The Handle's Object can't be cast to " + klass );
    }

    public boolean isDisconnected() {
        return disconnected;
    }

    protected void setDisconnected( boolean disconnected ) {
        this.disconnected = disconnected;
    }

    public int getObjectHashCode() {
        return this.objectHashCode;
    }

    public int getIdentityHashCode() {
        return this.identityHashCode;
    }

    public static int determineIdentityHashCode( Object object ) {
        return System.identityHashCode( object );
    }

    protected void setIdentityHashCode( int identityHashCode ) {
        this.identityHashCode = identityHashCode;
    }

    protected void setObjectHashCode( int hashCode ) {
        this.objectHashCode = hashCode;
    }

    /**
     * @see Object
     */
    public int hashCode() {
        return this.id;
    }

    /**
     * format_version:id:identity:hashcode:recency
     * 
     * @see FactHandle
     */
    public final String toExternalForm() {
        return getFormatVersion() + ":" + this.id +
               ":" +
               getIdentityHashCode() +
               ":" +
               getObjectHashCode() +
               ":" +
               getRecency() +
               ":" +
               ( ( this.entryPoint != null ) ? this.entryPoint.getEntryPointId() : "null" ) +
               ":" +
               this.traitType.name() +
               ":" +
               this.objectClassName;
    }

    protected String getFormatVersion() {
        return FACT_FORMAT_VERSION;
    }

    @XmlAttribute(name = "external-form")
    public String getExternalForm() {
        return toExternalForm();
    }

    public void setExternalForm(String externalForm) {
        populateFactHandleFromExternalForm( externalForm, this );
    }

    /**
     * @see Object
     */
    public String toString() {
        return "[fact " + toExternalForm() + ":" + this.object + "]";
    }

    public long getRecency() {
        return this.recency;
    }

    public void setRecency( final long recency ) {
        this.recency = recency;
    }

    public int getId() {
        return this.id;
    }

    public void invalidate() {
        valid = false;
    }

    public boolean isValid() {
        return valid;
    }

    public Object getObject() {
        return this.object;
    }

    public String getObjectClassName() {
        return this.objectClassName;
    }

    public void setObject( final Object object ) {
        this.object = object;
        if (object != null) {
            this.objectClassName = object.getClass().getName();
            this.objectHashCode = object.hashCode();
        } else {
            this.objectHashCode = 0;
        }

        if ( isTraitOrTraitable() ) {
            TraitTypeEnum newType = determineTraitType();
            if ( ! ( this.traitType == TraitTypeEnum.LEGACY_TRAITABLE && newType != TraitTypeEnum.LEGACY_TRAITABLE ) ) {
                this.identityHashCode = determineIdentityHashCode( object );
            } else {
                // we are replacing a non-traitable object with its proxy, so we need to preserve the identity hashcode
            }
            this.traitType = newType;
        } else {
            this.identityHashCode = determineIdentityHashCode( object );
        }
    }

    /**
     * @return the key
     */
    public EqualityKey getEqualityKey() {
        return this.key;
    }

    /**
     * @param key the key to set
     */
    public void setEqualityKey( final EqualityKey key ) {
        this.key = key;
    }

    /**
     * Always returns false, since the DefaultFactHandle is
     * only used for regular Facts, and not for Events
     */
    public boolean isEvent() {
        return false;
    }

    public boolean isTraitOrTraitable() {
        return traitType != TraitTypeEnum.NON_TRAIT;
    }

    public WorkingMemoryEntryPoint getEntryPoint() {
        return entryPoint;
    }

    public void setEntryPoint( WorkingMemoryEntryPoint sourceNode ) {
        this.entryPoint = sourceNode;
        setLinkedTuples( entryPoint != null ? entryPoint.getKnowledgeBase() : null );
    }

    private void setLinkedTuples( InternalKnowledgeBase kbase ) {
        linkedTuples = kbase != null && kbase.getConfiguration().isMultithreadEvaluation() ?
                       new CompositeLinkedTuples() :
                       new SingleLinkedTuples();
    }

    public void addFirstLeftTuple( LeftTuple leftTuple ) {
        linkedTuples.addFirstLeftTuple( leftTuple );
    }

    public void addLastLeftTuple( LeftTuple leftTuple ) {
        linkedTuples.addLastLeftTuple( leftTuple );
    }

    public void addTupleInPosition( Tuple tuple ) {
        linkedTuples.addTupleInPosition( tuple );
    }

    public void removeLeftTuple( LeftTuple leftTuple ) {
        linkedTuples.removeLeftTuple( leftTuple );
    }

    public void addFirstRightTuple( RightTuple rightTuple ) {
        linkedTuples.addFirstRightTuple( rightTuple );
    }

    public void addLastRightTuple( RightTuple rightTuple ) {
        linkedTuples.addLastRightTuple( rightTuple );
    }

    public void removeRightTuple( RightTuple rightTuple ) {
        linkedTuples.removeRightTuple( rightTuple );
    }

    public void clearLeftTuples() {
        linkedTuples.clearLeftTuples();
    }

    public void clearRightTuples() {
        linkedTuples.clearRightTuples();
    }

    public DefaultFactHandle clone() {
        DefaultFactHandle clone = new DefaultFactHandle( this.id, this.object, this.recency, this.entryPoint );
        clone.key = this.key;
        clone.linkedTuples = this.linkedTuples.clone();

        clone.objectHashCode = this.objectHashCode;
        clone.identityHashCode = System.identityHashCode( clone.object );
        clone.disconnected = this.disconnected;
		clone.traitType = this.traitType;
        clone.negated = this.negated;
        return clone;
    }

    public static DefaultFactHandle createFromExternalFormat( String externalFormat ) {
        String[] elements = splitExternalForm( externalFormat );
        DefaultFactHandle handle;
        if (FACT_FORMAT_VERSION.equals( elements[0]) ) {
            handle = new DefaultFactHandle();
        } else if (EventFactHandle.EVENT_FORMAT_VERSION.equals( elements[0])) {
            handle = new EventFactHandle();
        } else {
            throw new RuntimeException( "Unknown fact handle version format: " + elements[0]);
        }
        populateFactHandleFromExternalForm( elements, handle );
        return handle;
    }

    private static String[] splitExternalForm( String externalFormat ) {
        String[] elements = externalFormat.split( ":" );
        if (elements.length < 6) {
            throw new IllegalArgumentException( "externalFormat did not have enough elements ["+externalFormat+"]" );
        }
        return elements;
    }

    private static void populateFactHandleFromExternalForm( String externalFormat, DefaultFactHandle handle ) {
        populateFactHandleFromExternalForm( splitExternalForm( externalFormat ), handle );
    }

    private static void populateFactHandleFromExternalForm( String[] elements, DefaultFactHandle handle ) {
        handle.id = Integer.parseInt( elements[1] );
        handle.identityHashCode = Integer.parseInt( elements[2] );
        handle.objectHashCode = Integer.parseInt( elements[3] );
        handle.recency = Long.parseLong( elements[4] );
        handle.setEntryPoint( ( StringUtils.isEmpty( elements[5] ) || "null".equals( elements[5].trim() ) ) ?
                            null :
                            new DisconnectedWorkingMemoryEntryPoint( elements[5].trim() ) );
        handle.disconnected = true;
        handle.traitType = elements.length > 6 ? TraitTypeEnum.valueOf( elements[6] ) : TraitTypeEnum.NON_TRAIT;
        handle.objectClassName = elements.length > 7 ? elements[7] : null;
    }

    private TraitTypeEnum determineTraitType() {
        if ( isTraitOrTraitable() ) {
            return TraitFactory.determineTraitType( object );
        } else {
            return TraitTypeEnum.NON_TRAIT;
        }
    }

    public boolean isTraitable() {
        return traitType == TraitTypeEnum.TRAITABLE || traitType == TraitTypeEnum.WRAPPED_TRAITABLE;
    }

    public boolean isTraiting() {
        return traitType == TraitTypeEnum.TRAIT;
    }

    public TraitTypeEnum getTraitType() {
        return traitType;
    }

    protected void setTraitType( TraitTypeEnum traitType ) {
        this.traitType = traitType;
    }

    public boolean isExpired() {
        return false;
    }

    public boolean isPendingRemoveFromStore() {
        return false;
    }

    protected static class SingleLinkedTuples implements LinkedTuples {
        private RightTuple firstRightTuple;
        private RightTuple lastRightTuple;

        private LeftTuple  firstLeftTuple;
        private LeftTuple  lastLeftTuple;

        public SingleLinkedTuples clone() {
            SingleLinkedTuples clone = new SingleLinkedTuples();
            clone.firstLeftTuple = this.firstLeftTuple;
            clone.lastLeftTuple = this.lastLeftTuple;
            clone.firstRightTuple = this.firstRightTuple;
            clone.lastRightTuple = this.lastRightTuple;
            return clone;
        }

        public void addFirstLeftTuple( LeftTuple leftTuple ) {
            LeftTuple previous = firstLeftTuple;
            if ( previous == null ) {
                // no other LeftTuples, just add.
                leftTuple.setHandlePrevious( null );
                leftTuple.setHandleNext( null );
                firstLeftTuple = leftTuple;
                lastLeftTuple = leftTuple;
            } else {
                leftTuple.setHandlePrevious( null );
                leftTuple.setHandleNext( previous );
                previous.setHandlePrevious( leftTuple );
                firstLeftTuple = leftTuple;
            }
        }

        public void addLastLeftTuple( LeftTuple leftTuple ) {
            LeftTuple previous = lastLeftTuple;
            if ( previous == null ) {
                // no other LeftTuples, just add.
                leftTuple.setHandlePrevious( null );
                leftTuple.setHandleNext( null );
                firstLeftTuple = leftTuple;
                lastLeftTuple = leftTuple;
            } else {
                leftTuple.setHandlePrevious( previous );
                leftTuple.setHandleNext( null );
                previous.setHandleNext( leftTuple );
                lastLeftTuple = leftTuple;
            }
        }

        public void addTupleInPosition( Tuple tuple ) {
            boolean left = tuple instanceof LeftTuple;
            ObjectTypeNode.Id otnId = tuple.getInputOtnId();
            if (otnId == null) { // can happen only in tests
                addLastTuple( tuple, left );
                return;
            }

            Tuple previous = left ? lastLeftTuple : lastRightTuple;
            if ( previous == null ) {
                // no other LeftTuples, just add.
                tuple.setHandlePrevious( null );
                tuple.setHandleNext( null );
                setFirstTuple( tuple, left );
                setLastTuple( tuple, left );
                return;
            } else if ( previous.getTupleSink() == null || !otnId.before( previous.getInputOtnId() ) ) {
                // the last LeftTuple comes before the new one so just add it at the end
                tuple.setHandlePrevious( previous );
                tuple.setHandleNext( null );
                previous.setHandleNext( tuple );
                setLastTuple( tuple, left );
                return;
            }

            Tuple next = previous;
            previous = previous.getHandlePrevious();
            while (previous != null && otnId.before( previous.getInputOtnId() ) ) {
                next = previous;
                previous = previous.getHandlePrevious();
            }
            tuple.setHandleNext( next );
            next.setHandlePrevious( tuple );
            tuple.setHandlePrevious( previous );
            if ( previous != null ) {
                previous.setHandleNext( tuple );
            } else {
                setFirstTuple( tuple, left );
            }
        }

        private void addLastTuple(Tuple tuple, boolean left) {
            if (left) {
                addLastLeftTuple( ( (LeftTuple) tuple ) );
            } else {
                addLastRightTuple( ( (RightTuple) tuple ) );
            }
        }

        private void setFirstTuple(Tuple tuple, boolean left) {
            if (left) {
                firstLeftTuple = ( (LeftTuple) tuple );
            } else {
                firstRightTuple = ( (RightTuple) tuple );
            }
        }

        private void setLastTuple(Tuple tuple, boolean left) {
            if (left) {
                lastLeftTuple = ( (LeftTuple) tuple );
            } else {
                lastRightTuple = ( (RightTuple) tuple );
            }
        }

        public void removeLeftTuple( LeftTuple leftTuple ) {
            LeftTuple previous = leftTuple.getHandlePrevious();
            LeftTuple next = leftTuple.getHandleNext();

            if ( previous != null && next != null ) {
                // remove  from middle
                previous.setHandleNext( next );
                next.setHandlePrevious( previous );
            } else if ( next != null ) {
                // remove from first
                next.setHandlePrevious( null );
                firstLeftTuple = next;
            } else if ( previous != null ) {
                // remove from end
                previous.setHandleNext( null );
                lastLeftTuple = previous;
            } else {
                // single remaining item, no previous or next
                firstLeftTuple = null;
                lastLeftTuple = null;
            }
            leftTuple.setHandlePrevious( null );
            leftTuple.setHandleNext( null );
        }

        public void addFirstRightTuple( RightTuple rightTuple ) {
            RightTuple previousFirst = firstRightTuple;
            firstRightTuple = rightTuple;
            if ( previousFirst == null ) {
                rightTuple.setHandlePrevious( null );
                rightTuple.setHandleNext( null );
                lastRightTuple = rightTuple;
            } else {
                rightTuple.setHandlePrevious( null );
                rightTuple.setHandleNext( previousFirst );
                previousFirst.setHandlePrevious( rightTuple );
            }
        }

        public void addLastRightTuple( RightTuple rightTuple ) {
            RightTuple previousLast = lastRightTuple;
            if( previousLast == null ){
                rightTuple.setHandlePrevious( null );
                rightTuple.setHandleNext( null );
                firstRightTuple = rightTuple;
                lastRightTuple = rightTuple;
            } else {
                rightTuple.setHandlePrevious( previousLast );
                rightTuple.setHandleNext( null );
                previousLast.setHandleNext( rightTuple );
                lastRightTuple = rightTuple;
            }
        }

        public void removeRightTuple( RightTuple rightTuple ) {
            RightTuple previous = rightTuple.getHandlePrevious();
            RightTuple next = rightTuple.getHandleNext();

            if ( previous != null && next != null ) {
                // remove  from middle
                previous.setHandleNext( next );
                next.setHandlePrevious( previous );
            } else if ( next != null ) {
                // remove from first
                next.setHandlePrevious( null );
                firstRightTuple = next;
            } else if ( previous != null ) {
                // remove from end
                previous.setHandleNext( null );
                lastRightTuple = previous;
            } else {
                // single remaining item, no previous or next
                firstRightTuple = null;
                lastRightTuple = null;
            }
            rightTuple.setHandlePrevious( null );
            rightTuple.setHandleNext( null );
        }

        public void clearLeftTuples() {
            firstLeftTuple = null;
            lastLeftTuple = null;
        }

        public void clearRightTuples() {
            firstRightTuple = null;
            lastRightTuple = null;
        }

        public void forEachRightTuple(Consumer rightTupleConsumer) {
            for (RightTuple rightTuple = firstRightTuple; rightTuple != null; ) {
                RightTuple nextRightTuple = rightTuple.getHandleNext();
                rightTupleConsumer.accept( rightTuple );
                rightTuple = nextRightTuple;
            }
        }

        public RightTuple findFirstRightTuple(Predicate rightTuplePredicate ) {
            for (RightTuple rightTuple = firstRightTuple; rightTuple != null; ) {
                RightTuple nextRightTuple = rightTuple.getHandleNext();
                if (rightTuplePredicate.test( rightTuple )) {
                    return rightTuple;
                }
                rightTuple = nextRightTuple;
            }
            return null;
        }

        public void forEachLeftTuple(Consumer leftTupleConsumer) {
            for ( LeftTuple leftTuple = firstLeftTuple; leftTuple != null; ) {
                LeftTuple nextLeftTuple = leftTuple.getHandleNext();
                leftTupleConsumer.accept( leftTuple );
                leftTuple = nextLeftTuple;
            }
        }

        public LeftTuple findFirstLeftTuple(Predicate lefttTuplePredicate ) {
            for ( LeftTuple leftTuple = firstLeftTuple; leftTuple != null; ) {
                LeftTuple nextLeftTuple = leftTuple.getHandleNext();
                if (lefttTuplePredicate.test( leftTuple )) {
                    return leftTuple;
                }
                leftTuple = nextLeftTuple;
            }
            return null;
        }

        public LeftTuple getFirstLeftTuple(int partition) {
            return getFirstLeftTuple();
        }

        LeftTuple getFirstLeftTuple() {
            return firstLeftTuple;
        }

        public void setFirstLeftTuple( LeftTuple firstLeftTuple, int partition ) {
            setFirstLeftTuple( firstLeftTuple );
        }

        void setFirstLeftTuple( LeftTuple firstLeftTuple ) {
            this.firstLeftTuple = firstLeftTuple;
        }

        public RightTuple getFirstRightTuple(int partition) {
            return getFirstRightTuple();
        }

        RightTuple getFirstRightTuple() {
            return firstRightTuple;
        }
    }

    public static class CompositeLinkedTuples implements LinkedTuples {

        private final SingleLinkedTuples[] partitionedTuples = new SingleLinkedTuples[RuleBasePartitionId.PARALLEL_PARTITIONS_NUMBER];

        public CompositeLinkedTuples() {
            for (int i = 0; i < partitionedTuples.length; i++) {
                partitionedTuples[i] = new SingleLinkedTuples();
            }
        }

        @Override
        public LinkedTuples clone() {
            CompositeLinkedTuples clone = new CompositeLinkedTuples();
            for (int i = 0; i < partitionedTuples.length; i++) {
                clone.partitionedTuples[i] = partitionedTuples[i].clone();
            }
            return clone;
        }

        private LinkedTuples getPartitionTuples(Tuple tuple) {
            return partitionedTuples[tuple.getTupleSink().getPartitionId().getParallelEvaluationSlot()];
        }

        @Override
        public void addFirstLeftTuple( LeftTuple leftTuple ) {
            getPartitionTuples(leftTuple).addFirstLeftTuple( leftTuple );
        }

        @Override
        public void addLastLeftTuple( LeftTuple leftTuple ) {
            getPartitionTuples(leftTuple).addLastLeftTuple( leftTuple );
        }

        @Override
        public void addTupleInPosition( Tuple tuple ) {
            getPartitionTuples(tuple).addTupleInPosition( tuple );
        }

        @Override
        public void removeLeftTuple( LeftTuple leftTuple ) {
            getPartitionTuples(leftTuple).removeLeftTuple( leftTuple );
        }

        @Override
        public void addFirstRightTuple( RightTuple rightTuple ) {
            getPartitionTuples(rightTuple).addFirstRightTuple( rightTuple );
        }

        @Override
        public void addLastRightTuple( RightTuple rightTuple ) {
            getPartitionTuples(rightTuple).addLastRightTuple( rightTuple );
        }

        @Override
        public void removeRightTuple( RightTuple rightTuple ) {
            if (rightTuple.getTupleSink() != null) {
                getPartitionTuples( rightTuple ).removeRightTuple( rightTuple );
            }
        }

        @Override
        public void clearLeftTuples() {
            for (int i = 0; i < partitionedTuples.length; i++) {
                clearLeftTuples(i);
            }
        }

        public void clearLeftTuples(int partition) {
            partitionedTuples[partition].clearLeftTuples();
        }

        @Override
        public void clearRightTuples() {
            for (int i = 0; i < partitionedTuples.length; i++) {
                clearRightTuples(i);
            }
        }

        public void clearRightTuples(int partition) {
            partitionedTuples[partition].clearRightTuples();
        }

        @Override
        public void forEachRightTuple( Consumer rightTupleConsumer ) {
            for (int i = 0; i < partitionedTuples.length; i++) {
                forEachRightTuple( i, rightTupleConsumer );
            }
        }

        public void forEachRightTuple( int partition, Consumer rightTupleConsumer ) {
            partitionedTuples[partition].forEachRightTuple( rightTupleConsumer );
        }

        @Override
        public RightTuple findFirstRightTuple( Predicate rightTuplePredicate ) {
            return Stream.of( partitionedTuples )
                         .map( t -> t.findFirstRightTuple( rightTuplePredicate ) )
                         .filter( Objects::nonNull )
                         .findFirst()
                         .orElse( null );
        }

        @Override
        public void forEachLeftTuple( Consumer leftTupleConsumer ) {
            for (int i = 0; i < partitionedTuples.length; i++) {
                forEachLeftTuple( i, leftTupleConsumer );
            }
        }

        public void forEachLeftTuple( int partition, Consumer leftTupleConsumer ) {
            partitionedTuples[partition].forEachLeftTuple( leftTupleConsumer );
        }

        @Override
        public LeftTuple findFirstLeftTuple( Predicate lefttTuplePredicate ) {
            return Stream.of( partitionedTuples )
                         .map( t -> t.findFirstLeftTuple( lefttTuplePredicate ) )
                         .filter( Objects::nonNull )
                         .findFirst()
                         .orElse( null );
        }

        @Override
        public LeftTuple getFirstLeftTuple(int partition) {
            return partitionedTuples[partition].getFirstLeftTuple();
        }

        @Override
        public void setFirstLeftTuple( LeftTuple firstLeftTuple, int partition ) {
            partitionedTuples[partition].setFirstLeftTuple(firstLeftTuple);
        }

        @Override
        public RightTuple getFirstRightTuple(int partition) {
            return partitionedTuples[partition].getFirstRightTuple();
        }
    }

    @Override
    public void forEachRightTuple(Consumer rightTupleConsumer) {
        linkedTuples.forEachRightTuple( rightTupleConsumer );
    }

    @Override
    public RightTuple findFirstRightTuple(Predicate rightTuplePredicate ) {
        return linkedTuples.findFirstRightTuple( rightTuplePredicate );
    }

    @Override
    public void forEachLeftTuple(Consumer leftTupleConsumer) {
        linkedTuples.forEachLeftTuple( leftTupleConsumer );
    }

    @Override
    public LeftTuple findFirstLeftTuple(Predicate lefttTuplePredicate ) {
        return linkedTuples.findFirstLeftTuple( lefttTuplePredicate );
    }

    @Override
    public LeftTuple getFirstLeftTuple() {
        if (linkedTuples instanceof SingleLinkedTuples) {
            return ( (SingleLinkedTuples) linkedTuples ).getFirstLeftTuple();
        }
        throw new UnsupportedOperationException();
    }

    @Override
    public void setFirstLeftTuple( LeftTuple firstLeftTuple ) {
        if (linkedTuples instanceof SingleLinkedTuples) {
            ( (SingleLinkedTuples) linkedTuples ).setFirstLeftTuple( firstLeftTuple );
        } else {
            throw new UnsupportedOperationException();
        }
    }

    @Override
    public RightTuple getFirstRightTuple() {
        if (linkedTuples instanceof SingleLinkedTuples) {
            return ( (SingleLinkedTuples) linkedTuples ).getFirstRightTuple();
        }
        throw new UnsupportedOperationException();
    }

    @Override
    public LinkedTuples getLinkedTuples() {
        return linkedTuples;
    }

    @Override
    public LinkedTuples detachLinkedTuples() {
        LinkedTuples detached = linkedTuples;
        linkedTuples = new SingleLinkedTuples();
        return detached;
    }

    @Override
    public LinkedTuples detachLinkedTuplesForPartition(int i) {
        LinkedTuples detached = ( (CompositeLinkedTuples) linkedTuples ).partitionedTuples[i];
        ( (CompositeLinkedTuples) linkedTuples ).partitionedTuples[i] = new SingleLinkedTuples();
        return detached;
    }

    @Override
    public InternalDataSource getDataSource() {
        return parentHandle != null ? parentHandle.getDataSource() : null;
    }

    public InternalFactHandle getParentHandle() {
        return parentHandle;
    }

    public void setParentHandle( InternalFactHandle parentHandle ) {
        this.parentHandle = parentHandle;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy