package com.google.code.joto.eventrecorder.impl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.google.code.joto.eventrecorder.RecordEventData;
import com.google.code.joto.eventrecorder.RecordEventStore;
import com.google.code.joto.eventrecorder.RecordEventStoreChange;
import com.google.code.joto.eventrecorder.RecordEventSummary;
import com.google.code.joto.eventrecorder.RecordEventStoreChange.AddRecordEventStoreEvent;
import com.google.code.joto.eventrecorder.RecordEventStoreChange.TruncateRecordEventStoreEvent;
/**
* in-memory cyclic implementation of RecordEventStore
*/
public class CyclicBufferRecordEventStore extends DefaultMemoryRecordEventStore {
public static final int DEFAULT_MAX_EVENT_COUNT = 500;
/** Factory pattern for RecordEventStore */
public static class CyclicBufferRecordEventStoreFactory implements RecordEventStoreFactory {
/** internal for java.io.Serializable */
private static final long serialVersionUID = 1L;
int maxEventCount = DEFAULT_MAX_EVENT_COUNT;
public CyclicBufferRecordEventStoreFactory() {
}
public CyclicBufferRecordEventStoreFactory(int maxEventCount) {
this();
this.maxEventCount = maxEventCount;
}
public RecordEventStore create() {
return new CyclicBufferRecordEventStore();
}
}
private int maxEventCount = DEFAULT_MAX_EVENT_COUNT;
// ------------------------------------------------------------------------
public CyclicBufferRecordEventStore() {
}
public CyclicBufferRecordEventStore(int maxEventCount) {
this();
this.maxEventCount = maxEventCount;
}
// ------------------------------------------------------------------------
public int getMaxEventCount() {
return maxEventCount;
}
public void setMaxEventCount(int p) {
this.maxEventCount = p;
checkNeedTruncate();
}
// ------------------------------------------------------------------------
@Override
public synchronized RecordEventData addEvent(RecordEventSummary eventInfo, Serializable objData) {
RecordEventData eventData = doAddEvent(eventInfo, objData);
AddRecordEventStoreEvent addEvent = new AddRecordEventStoreEvent(eventData);
if (maxEventCount != -1 || eventDataList.size() < maxEventCount) {
// no need truncate
fireStoreEvent(addEvent);
} else {
// need truncate
RecordEventData truncatedEvent = super.eventDataList.remove(0);
int truncatedEventId = truncatedEvent.getEventId();
List<RecordEventSummary> truncatedEvents = new ArrayList<RecordEventSummary>(1);
truncatedEvents.add(truncatedEvent.getEventSummary());
TruncateRecordEventStoreEvent truncEvent = onTruncateSetFirstEventId(truncatedEventId + 1, truncatedEvents);
List<RecordEventStoreChange> firedEvents = new ArrayList<RecordEventStoreChange>(2);
firedEvents.add(truncEvent);
firedEvents.add(addEvent);
fireStoreEvents(firedEvents);
}
return eventData;
}
// internal
// ------------------------------------------------------------------------
protected void checkNeedTruncate() {
if (maxEventCount == -1 || eventDataList.size() < maxEventCount) {
return;
}
// get truncated info
int truncatedLen = eventDataList.size() - maxEventCount;
List<RecordEventSummary> truncateEvents = eventDataListToEventHandleList(eventDataList.subList(0, truncatedLen));
int fromEventId = truncateEvents.get(0).getEventId();
int toEventId = truncateEvents.get(truncatedLen - 1).getEventId() + 1;
// do truncate
int checkTruncatedLen = eventDataList.truncateHeadForMaxRows(maxEventCount);
assert checkTruncatedLen == truncatedLen;
// fire truncated event
fireStoreEvent(new TruncateRecordEventStoreEvent(fromEventId, toEventId, truncateEvents));
}
}