/** * Copyright 2010 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.rule; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import org.drools.common.InternalWorkingMemory; import org.drools.common.PropagationContextImpl; import org.drools.reteoo.RightTuple; import org.drools.spi.PropagationContext; /** * A length window behavior implementation * * @author etirelli */ public class SlidingLengthWindow implements Externalizable, Behavior { private int size; public SlidingLengthWindow() { this( 0 ); } /** * @param size */ public SlidingLengthWindow(final int size) { super(); this.size = size; } /** * @inheritDoc * * @see java.io.Externalizable#readExternal(java.io.ObjectInput) */ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { this.size = in.readInt(); } /** * @inheritDoc * * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) */ public void writeExternal(final ObjectOutput out) throws IOException { out.writeInt( this.size ); } public BehaviorType getType() { return BehaviorType.LENGTH_WINDOW; } /** * @return the size */ public long getSize() { return size; } /** * @param size the size to set */ public void setSize(final int size) { this.size = size; } public Object createContext() { return new SlidingLengthWindowContext( this.size ); } /** * @inheritDoc * * @see org.drools.rule.Behavior#assertRightTuple(java.lang.Object, org.drools.reteoo.RightTuple, org.drools.common.InternalWorkingMemory) */ public boolean assertRightTuple(final Object context, final RightTuple rightTuple, final InternalWorkingMemory workingMemory) { SlidingLengthWindowContext window = (SlidingLengthWindowContext) context; window.pos = (window.pos + 1) % window.rightTuples.length; if ( window.rightTuples[window.pos] != null ) { final RightTuple tuple = window.rightTuples[window.pos]; // retract previous final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(), PropagationContext.EXPIRATION, null, null, tuple.getFactHandle() ); tuple.getRightTupleSink().retractRightTuple( tuple, propagationContext, workingMemory ); tuple.unlinkFromRightParent(); } window.rightTuples[window.pos] = rightTuple; return true; } /** * @inheritDoc * * @see org.drools.rule.Behavior#retractRightTuple(java.lang.Object, org.drools.reteoo.RightTuple, org.drools.common.InternalWorkingMemory) */ public void retractRightTuple(final Object context, final RightTuple rightTuple, final InternalWorkingMemory workingMemory) { SlidingLengthWindowContext window = (SlidingLengthWindowContext) context; final int last = (window.pos == 0) ? window.rightTuples.length - 1 : window.pos - 1; // we start the loop on current pos because the most common scenario is to retract the // right tuple referenced by the current "pos" position, causing this loop to only execute // the first iteration for ( int i = window.pos; i != last; i = (i + 1) % window.rightTuples.length ) { if ( window.rightTuples[i] == rightTuple ) { window.rightTuples[i] = null; break; } } } public void expireTuples(Object context, InternalWorkingMemory workingMemory) { // do nothing } /** * Length windows don't change expiration offset, so * always return -1 */ public long getExpirationOffset() { return -1; } public String toString() { return "SlidingLengthWindow( size=" + size + " )"; } /** * A Context object for length windows * * @author etirelli */ private static class SlidingLengthWindowContext implements Externalizable { public RightTuple[] rightTuples; public int pos = 0; public SlidingLengthWindowContext(final int size) { this.rightTuples = new RightTuple[size]; } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.pos = in.readInt(); this.rightTuples = (RightTuple[]) in.readObject(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt( this.pos ); out.writeObject( this.rightTuples ); } } }