/*
* 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.phreak;
import java.util.Iterator;
import org.drools.core.common.InternalWorkingMemory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SynchronizedPropagationList implements PropagationList {
protected static final transient Logger log = LoggerFactory.getLogger( SynchronizedPropagationList.class );
protected final InternalWorkingMemory workingMemory;
protected volatile PropagationEntry head;
protected volatile PropagationEntry tail;
private volatile boolean disposed = false;
private volatile boolean hasEntriesDeferringExpiration = false;
public SynchronizedPropagationList(InternalWorkingMemory workingMemory) {
this.workingMemory = workingMemory;
}
@Override
public void addEntry(final PropagationEntry entry) {
if (entry.requiresImmediateFlushing()) {
if (entry.isCalledFromRHS()) {
entry.execute(workingMemory);
} else {
workingMemory.getAgenda().executeTask( new ExecutableEntry() {
@Override
public void execute() {
if (entry instanceof PhreakTimerNode.TimerAction) {
( (PhreakTimerNode.TimerAction) entry ).execute( workingMemory, true );
} else {
entry.execute( workingMemory );
}
}
@Override
public void enqueue() {
internalAddEntry( entry );
}
} );
}
} else {
internalAddEntry( entry );
}
}
synchronized void internalAddEntry( PropagationEntry entry ) {
if ( head == null ) {
head = entry;
notifyWaitOnRest();
} else {
tail.setNext( entry );
}
tail = entry;
hasEntriesDeferringExpiration |= entry.defersExpiration();
}
@Override
public void dispose() {
disposed = true;
}
@Override
public void flush() {
flush( workingMemory, takeAll() );
}
@Override
public void flush(PropagationEntry currentHead) {
flush( workingMemory, currentHead );
}
private void flush( InternalWorkingMemory workingMemory, PropagationEntry currentHead ) {
for (PropagationEntry entry = currentHead; !disposed && entry != null; entry = entry.getNext()) {
entry.execute(workingMemory);
}
}
public boolean hasEntriesDeferringExpiration() {
return hasEntriesDeferringExpiration;
}
@Override
public synchronized PropagationEntry takeAll() {
PropagationEntry currentHead = head;
head = null;
tail = null;
hasEntriesDeferringExpiration = false;
return currentHead;
}
@Override
public synchronized void reset() {
head = null;
tail = null;
disposed = false;
}
@Override
public synchronized boolean isEmpty() {
return head == null;
}
public synchronized void waitOnRest() {
workingMemory.onSuspend();
try {
wait();
} catch (InterruptedException e) {
// do nothing
}
}
@Override
public synchronized void notifyWaitOnRest() {
notifyAll();
workingMemory.onResume();
}
@Override
public synchronized Iterator<PropagationEntry> iterator() {
return new PropagationEntryIterator(head);
}
public static class PropagationEntryIterator implements Iterator<PropagationEntry> {
private PropagationEntry next;
public PropagationEntryIterator(PropagationEntry head) {
this.next = head;
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public PropagationEntry next() {
PropagationEntry current = next;
next = current.getNext();
return current;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
public void onEngineInactive() { }
}