/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.wso2.siddhi.core.query.output.ratelimit.snapshot;
import org.wso2.siddhi.core.config.ExecutionPlanContext;
import org.wso2.siddhi.core.event.ComplexEvent;
import org.wso2.siddhi.core.event.ComplexEventChunk;
import org.wso2.siddhi.core.event.stream.StreamEventPool;
import org.wso2.siddhi.core.util.Scheduler;
import org.wso2.siddhi.core.util.parser.SchedulerParser;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
/**
* Parent implementation for per event periodic snapshot rate limiting. Multiple implementations of this will be
* there to represent different queries. Snapshot rate limiting will only emit current events representing the
* snapshot period.
*/
public class PerSnapshotOutputRateLimiter extends SnapshotOutputRateLimiter {
private final Long value;
private String id;
private ScheduledExecutorService scheduledExecutorService;
private ComplexEventChunk<ComplexEvent> eventChunk = new ComplexEventChunk<ComplexEvent>(false);
private ComplexEvent lastEvent;
private Scheduler scheduler;
private long scheduledTime;
private String queryName;
public PerSnapshotOutputRateLimiter(String id, Long value, ScheduledExecutorService scheduledExecutorService,
WrappedSnapshotOutputRateLimiter wrappedSnapshotOutputRateLimiter,
ExecutionPlanContext executionPlanContext, String queryName) {
super(wrappedSnapshotOutputRateLimiter, executionPlanContext);
this.queryName = queryName;
this.id = id;
this.value = value;
this.scheduledExecutorService = scheduledExecutorService;
}
@Override
public void process(ComplexEventChunk complexEventChunk) {
List<ComplexEventChunk<ComplexEvent>> outputEventChunks = new ArrayList<ComplexEventChunk<ComplexEvent>>();
complexEventChunk.reset();
synchronized (this) {
while (complexEventChunk.hasNext()) {
ComplexEvent event = complexEventChunk.next();
if (event.getType() == ComplexEvent.Type.TIMER) {
tryFlushEvents(outputEventChunks, event);
} else if (event.getType() == ComplexEvent.Type.CURRENT) {
complexEventChunk.remove();
tryFlushEvents(outputEventChunks, event);
lastEvent = event;
} else {
tryFlushEvents(outputEventChunks, event);
}
}
}
for (ComplexEventChunk eventChunk : outputEventChunks) {
sendToCallBacks(eventChunk);
}
}
private void tryFlushEvents(List<ComplexEventChunk<ComplexEvent>> outputEventChunks, ComplexEvent event) {
if (event.getTimestamp() >= scheduledTime) {
ComplexEventChunk<ComplexEvent> outputEventChunk = new ComplexEventChunk<ComplexEvent>(false);
if (lastEvent != null) {
outputEventChunk.add(cloneComplexEvent(lastEvent));
}
outputEventChunks.add(outputEventChunk);
scheduledTime += value;
scheduler.notifyAt(scheduledTime);
}
}
@Override
public SnapshotOutputRateLimiter clone(String key, WrappedSnapshotOutputRateLimiter
wrappedSnapshotOutputRateLimiter) {
return new PerSnapshotOutputRateLimiter(id + key, value, scheduledExecutorService,
wrappedSnapshotOutputRateLimiter, executionPlanContext, queryName);
}
@Override
public void start() {
scheduler = SchedulerParser.parse(scheduledExecutorService, this, executionPlanContext);
scheduler.setStreamEventPool(new StreamEventPool(0, 0, 0, 5));
scheduler.init(lockWrapper, queryName);
long currentTime = System.currentTimeMillis();
scheduledTime = currentTime + value;
scheduler.notifyAt(scheduledTime);
}
@Override
public void stop() {
//Nothing to stop
}
@Override
public Map<String, Object> currentState() {
Map<String, Object> state = new HashMap<>();
state.put("EventChunk", eventChunk.getFirst());
return state;
}
@Override
public void restoreState(Map<String, Object> state) {
eventChunk.clear();
eventChunk.add((ComplexEvent) state.get("EventList"));
}
}