/*
* Copyright 2010 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 org.drools.core.WorkingMemoryEntryPoint;
import org.drools.core.time.JobHandle;
import org.drools.core.time.TimerService;
import org.drools.core.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
public class EventFactHandle extends DefaultFactHandle implements Comparable<EventFactHandle> {
private static final long serialVersionUID = 510l;
static final String EVENT_FORMAT_VERSION = "5";
private long startTimestamp;
private long duration;
private boolean expired;
private boolean pendingRemoveFromStore;
private long activationsCount;
private int otnCount;
private EventFactHandle linkedFactHandle;
private AtomicInteger notExpiredPartitions;
private final transient LinkedList<JobHandle> jobs = new LinkedList<JobHandle>();
// ----------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------
public EventFactHandle() {
super();
this.startTimestamp = 0;
this.duration = 0;
}
/**
* Creates a new event fact handle.
*
* @param id this event fact handle ID
* @param object the event object encapsulated in this event fact handle
* @param recency the recency of this event fact handle
* @param timestamp the timestamp of the occurrence of this event
* @param duration the duration of this event. May be 0 (zero) in case this is a primitive event.
*/
public EventFactHandle(int id,
Object object,
long recency,
long timestamp,
long duration,
WorkingMemoryEntryPoint wmEntryPoint ) {
this( id, object, recency, timestamp, duration, wmEntryPoint, false );
}
public EventFactHandle(int id,
Object object,
long recency,
long timestamp,
long duration,
WorkingMemoryEntryPoint wmEntryPoint,
boolean isTraitOrTraitable ) {
super( id,
object,
recency,
wmEntryPoint,
isTraitOrTraitable );
this.startTimestamp = timestamp;
this.duration = duration;
if ( wmEntryPoint.getKnowledgeBase() != null && wmEntryPoint.getKnowledgeBase().getConfiguration().isMultithreadEvaluation() ) {
notExpiredPartitions = new AtomicInteger( RuleBasePartitionId.PARALLEL_PARTITIONS_NUMBER );
}
}
protected String getFormatVersion() {
return EVENT_FORMAT_VERSION;
}
/**
* @see Object
*/
public String toString() {
return toExternalForm();
}
/**
* Always returns true, since the EventFactHandle is
* only used for Events, and not for regular Facts
*/
public boolean isEvent() {
return true;
}
/**
* Returns the timestamp of the occurrence of this event.
* @return
*/
public long getStartTimestamp() {
return startTimestamp;
}
/**
* Returns the duration of this event. In case this is a primitive event,
* returns 0 (zero).
*
* @return
*/
public long getDuration() {
return duration;
}
/**
* Returns the end timestamp for this event. This is the same as:
*
* startTimestamp + duration
*
* @return
*/
public long getEndTimestamp() {
return this.startTimestamp + this.duration;
}
public EventFactHandle getLinkedFactHandle() {
return linkedFactHandle;
}
@Override
public void invalidate() {
if ( linkedFactHandle != null ) {
linkedFactHandle.invalidate();
} else {
super.invalidate();
}
}
@Override
public boolean isValid() {
if ( linkedFactHandle != null ) {
return linkedFactHandle.isValid();
} else {
return super.isValid();
}
}
@Override
public boolean isExpired() {
if ( linkedFactHandle != null ) {
return linkedFactHandle.isExpired();
} else {
return expired;
}
}
public boolean expirePartition() {
if ( linkedFactHandle != null ) {
return linkedFactHandle.expirePartition();
} else {
return notExpiredPartitions == null || notExpiredPartitions.decrementAndGet() == 0;
}
}
public void setExpired(boolean expired) {
if ( linkedFactHandle != null ) {
linkedFactHandle.setExpired(expired);
} else {
this.expired = expired;
}
}
public boolean isPendingRemoveFromStore() {
if ( linkedFactHandle != null ) {
return linkedFactHandle.isPendingRemoveFromStore();
} else {
return pendingRemoveFromStore;
}
}
public void setPendingRemoveFromStore(boolean pendingRemove) {
if ( linkedFactHandle != null ) {
linkedFactHandle.setPendingRemoveFromStore(pendingRemove);
} else {
this.pendingRemoveFromStore = pendingRemove;
}
}
public long getActivationsCount() {
if ( linkedFactHandle != null ) {
return linkedFactHandle.getActivationsCount();
} else {
return activationsCount;
}
}
public void setActivationsCount(long activationsCount) {
if ( linkedFactHandle != null ) {
linkedFactHandle.setActivationsCount( activationsCount );
} else {
this.activationsCount = activationsCount;
}
}
public void increaseActivationsCount() {
if ( linkedFactHandle != null ) {
linkedFactHandle.increaseActivationsCount();
} else {
this.activationsCount++;
}
}
public void decreaseActivationsCount() {
if ( linkedFactHandle != null ) {
linkedFactHandle.decreaseActivationsCount();
} else {
this.activationsCount--;
}
}
public void increaseOtnCount() {
otnCount++;
}
public void decreaseOtnCount() {
otnCount--;
}
public int getOtnCount() {
return otnCount;
}
public void setOtnCount( int otnCount ) {
this.otnCount = otnCount;
}
public EventFactHandle clone() {
EventFactHandle clone = new EventFactHandle( getId(),
getObject(),
getRecency(),
getStartTimestamp(),
getDuration(),
getEntryPoint(),
isTraitOrTraitable() );
clone.setActivationsCount( getActivationsCount() );
clone.setOtnCount( getOtnCount() );
clone.setExpired( isExpired() );
clone.setEntryPoint( getEntryPoint() );
clone.setEqualityKey( getEqualityKey() );
clone.linkedTuples = this.linkedTuples.clone();
clone.setObjectHashCode(getObjectHashCode());
return clone;
}
private EventFactHandle cloneWithoutTuples() {
EventFactHandle clone = new EventFactHandle( getId(),
getObject(),
getRecency(),
getStartTimestamp(),
getDuration(),
getEntryPoint(),
isTraitOrTraitable() );
clone.setActivationsCount( getActivationsCount() );
clone.setOtnCount( getOtnCount() );
clone.setExpired( isExpired() );
clone.setEntryPoint( getEntryPoint() );
clone.setEqualityKey( getEqualityKey() );
clone.setObjectHashCode(getObjectHashCode());
return clone;
}
public EventFactHandle cloneAndLink() {
EventFactHandle clone = cloneWithoutTuples();
clone.linkedFactHandle = this;
return clone;
}
public void quickCloneUpdate(DefaultFactHandle clone) {
clone.setObject( getObject() );
clone.setRecency( getRecency() );
clone.setEqualityKey( getEqualityKey() );
clone.setObjectHashCode( getObjectHashCode() );
clone.setIdentityHashCode( getIdentityHashCode() );
clone.setTraitType( getTraitType() );
clone.setDisconnected( isDisconnected() );
clone.setNegated( isNegated() );
}
public int compareTo(EventFactHandle e) {
return (getStartTimestamp() < e.getStartTimestamp()) ? -1 : (getStartTimestamp() == e.getStartTimestamp() ? 0 : 1);
}
public void addJob(JobHandle job) {
synchronized (jobs) {
jobs.add(job);
}
}
public void removeJob(JobHandle job) {
synchronized (jobs) {
// the job could have been already removed if the event has been just retracted
// and then the unscheduleAllJobs method has been invoked concurrently
if (jobs.contains(job)) {
jobs.remove(job);
}
}
}
public void unscheduleAllJobs(InternalWorkingMemory workingMemory) {
if (!jobs.isEmpty()) {
synchronized (jobs) {
TimerService clock = workingMemory.getTimerService();
while ( !jobs.isEmpty() ) {
JobHandle job = jobs.removeFirst();
clock.removeJob(job);
}
}
}
}
}