/*
* Copyright 2015 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.
*
* 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.spi.Tuple;
public class TupleSetsImpl<T extends Tuple> implements TupleSets<T> {
private T insertFirst;
private T deleteFirst;
private T updateFirst;
private T normalizedDeleteFirst;
private int insertSize;
public TupleSetsImpl() { }
TupleSetsImpl( T insertFirst, T updateFirst, T deleteFirst, T normalizedDeleteFirst, int insertSize ) {
this.insertFirst = insertFirst;
this.updateFirst = updateFirst;
this.deleteFirst = deleteFirst;
this.normalizedDeleteFirst = normalizedDeleteFirst;
this.insertSize = insertSize;
}
public int getInsertSize() {
return insertSize;
}
public T getInsertFirst() {
return this.insertFirst;
}
protected void setInsertFirst( T insertFirst ) {
this.insertFirst = insertFirst;
}
public T getDeleteFirst() {
return this.deleteFirst;
}
protected void setDeleteFirst( T deleteFirst ) {
this.deleteFirst = deleteFirst;
}
public T getUpdateFirst() {
return this.updateFirst;
}
protected void setUpdateFirst( T updateFirst ) {
this.updateFirst = updateFirst;
}
public T getNormalizedDeleteFirst() {
return normalizedDeleteFirst;
}
protected void setNormalizedDeleteFirst( T normalizedDeleteFirst ) {
this.normalizedDeleteFirst = normalizedDeleteFirst;
}
public void resetAll() {
setInsertFirst( null );
setDeleteFirst( null );
setUpdateFirst( null );
setNormalizedDeleteFirst( null );
insertSize = 0;
}
public boolean addInsert(T tuple) {
if ( getStagedType( tuple ) == Tuple.UPDATE) {
// do nothing, it's already staged as an update, which means it's already scheduled for eval too.
return false;
}
setStagedType( tuple, Tuple.INSERT );
if ( insertFirst == null ) {
insertFirst = tuple;
insertSize = 1;
return true;
}
setNextTuple( tuple, insertFirst );
setPreviousTuple( insertFirst, tuple );
insertFirst = tuple;
insertSize++;
return false;
}
public boolean addDelete(T tuple) {
switch ( getStagedType( tuple ) ) {
// handle clash with already staged entries
case Tuple.INSERT:
removeInsert( tuple );
return deleteFirst == null;
case Tuple.UPDATE:
removeUpdate( tuple );
break;
}
setStagedType( tuple, Tuple.DELETE );
if ( deleteFirst == null ) {
deleteFirst = tuple;
return true;
}
setNextTuple( tuple, deleteFirst );
setPreviousTuple( deleteFirst, tuple );
deleteFirst = tuple;
return false;
}
public boolean addNormalizedDelete(T tuple) {
setStagedType( tuple, Tuple.NORMALIZED_DELETE );
if ( normalizedDeleteFirst == null ) {
normalizedDeleteFirst = tuple;
return true;
}
setNextTuple( tuple, normalizedDeleteFirst );
setPreviousTuple( normalizedDeleteFirst, tuple );
normalizedDeleteFirst = tuple;
return false;
}
public boolean addUpdate(T tuple) {
if ( getStagedType( tuple ) != Tuple.NONE) {
// do nothing, it's already staged as insert, which means it's already scheduled for eval too.
return false;
}
setStagedType( tuple, Tuple.UPDATE );
if ( updateFirst == null ) {
updateFirst = tuple;
return true;
}
setNextTuple( tuple, updateFirst );
setPreviousTuple( updateFirst, tuple );
updateFirst = tuple;
return false;
}
public void removeInsert(T tuple) {
if ( tuple == insertFirst ) {
T next = getNextTuple( tuple );
if ( next != null ) {
setPreviousTuple( next, null );
}
setInsertFirst( next );
} else {
T next = getNextTuple( tuple );
T previous = getPreviousTuple( tuple );
if ( next != null ) {
setPreviousTuple( next, previous );
}
setNextTuple( previous, next );
}
tuple.clearStaged();
insertSize--;
}
public void removeDelete(T tuple) {
if ( tuple == deleteFirst ) {
T next = getNextTuple( tuple );
if ( next != null ) {
setPreviousTuple( next, null );
}
deleteFirst = next;
} else {
T next = getNextTuple( tuple );
T previous = getPreviousTuple( tuple );
if ( next != null ) {
setPreviousTuple( next, previous );
}
setNextTuple( previous, next );
}
tuple.clearStaged();
}
public void removeUpdate(Tuple tuple) {
if ( tuple == updateFirst ) {
T next = getNextTuple( (T) tuple );
if ( next != null ) {
setPreviousTuple( next, null );
}
updateFirst = next;
} else {
T next = getNextTuple( (T) tuple );
T previous = getPreviousTuple( (T) tuple );
if ( next != null ) {
setPreviousTuple( next, previous );
}
setNextTuple( previous, next );
}
tuple.clearStaged();
}
private void addAllInserts(TupleSets<T> tupleSets) {
if ( tupleSets.getInsertFirst() != null ) {
if ( insertFirst == null ) {
setInsertFirst( tupleSets.getInsertFirst() );
insertSize = tupleSets.getInsertSize();
} else {
T current = insertFirst;
T last = null;
while ( current != null ) {
last = current;
current = getNextTuple( current );
}
T tuple = tupleSets.getInsertFirst();
setNextTuple( last, tuple );
setPreviousTuple( tuple, last );
insertSize = insertSize + tupleSets.getInsertSize();
}
( (TupleSetsImpl) tupleSets ).setInsertFirst( null );
}
}
private void addAllDeletes(TupleSets<T> tupleSets) {
if ( tupleSets.getDeleteFirst() != null ) {
if ( deleteFirst == null ) {
setDeleteFirst( tupleSets.getDeleteFirst() );
} else {
T current = deleteFirst;
T last = null;
while ( current != null ) {
last = current;
current = getNextTuple( current );
}
T tuple = tupleSets.getDeleteFirst();
setNextTuple( last, tuple );
setPreviousTuple( tuple, last );
}
((TupleSetsImpl) tupleSets).setDeleteFirst( null );
}
}
private void addAllUpdates(TupleSets<T> tupleSets) {
if ( tupleSets.getUpdateFirst() != null ) {
if ( updateFirst == null ) {
setUpdateFirst( tupleSets.getUpdateFirst() );
} else {
T current = updateFirst;
T last = null;
while ( current != null ) {
last = current;
current = getNextTuple( current );
}
T tuple = tupleSets.getUpdateFirst();
setNextTuple( last, tuple );
setPreviousTuple( tuple, last );
}
( (TupleSetsImpl) tupleSets ).setUpdateFirst( null );
}
}
public void addAll(TupleSets<T> source) {
addAllInserts( source );
addAllDeletes( source );
addAllUpdates( source );
}
public void addTo(TupleSets<T> target) {
target.addAll( this );
}
@Override
public TupleSets<T> takeAll() {
TupleSets<T> clone = new TupleSetsImpl(insertFirst, updateFirst, deleteFirst, normalizedDeleteFirst, insertSize);
resetAll();
return clone;
}
public void clear() {
clear( getInsertFirst() );
clear( getDeleteFirst() );
clear( getUpdateFirst() );
clear( getNormalizedDeleteFirst() );
resetAll();
}
private void clear( T tuple ) {
while ( tuple != null ) {
T next = getNextTuple( tuple );
tuple.clearStaged();
tuple = next;
}
}
@Override
public boolean isEmpty() {
return insertFirst == null && deleteFirst == null && updateFirst == null && normalizedDeleteFirst == null;
}
@Override
public String toStringSizes() {
return "TupleSets[hasInsert=" + (insertFirst != null) + ", hasDelete=" + (deleteFirst != null) + ", hasUpdate=" + (updateFirst != null) + "]";
}
public String toString() {
StringBuilder sbuilder = new StringBuilder();
sbuilder.append( "Inserted:\n" );
appendSet( sbuilder, getInsertFirst() );
sbuilder.append( "Deleted:\n" );
appendSet( sbuilder, getDeleteFirst() );
sbuilder.append( "Updated:\n" );
appendSet( sbuilder, getUpdateFirst() );
sbuilder.append( "Normalized Deleted:\n" );
appendSet( sbuilder, getNormalizedDeleteFirst() );
return sbuilder.toString();
}
private void appendSet( StringBuilder sbuilder, Tuple tuple ) {
for ( ; tuple != null; tuple = getNextTuple( (T) tuple ) ) {
sbuilder.append( " " ).append( tuple ).append( "\n" );
}
}
protected T getPreviousTuple( T tuple ) {
return (T) tuple.getStagedPrevious();
}
protected void setPreviousTuple( T tuple, T stagedPrevious ) {
tuple.setStagedPrevious( stagedPrevious );
}
protected T getNextTuple( T tuple ) {
return tuple.getStagedNext();
}
protected void setNextTuple( T tuple, T stagedNext ) {
tuple.setStagedNext( stagedNext );
}
protected void setStagedType( T tuple, short type ) {
tuple.setStagedType( type );
}
protected short getStagedType( T tuple ) {
return tuple.getStagedType();
}
}