/*
* Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com]
* 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 de.ks.executor.group;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
public class LastExecutionGroup<T> implements Runnable {
private static final Logger log = LoggerFactory.getLogger(LastExecutionGroup.class);
protected final LinkedBlockingDeque<ExecutionGroupEvent<T>> queue = new LinkedBlockingDeque<>();
private final String desc;
protected final long waitTime;
protected ExecutorService executor;
protected final AtomicBoolean running = new AtomicBoolean(false);
protected volatile CompletableFuture<T> result;
public LastExecutionGroup(String desc, long waitTime, ExecutorService executor) {
this.desc = desc;
this.waitTime = waitTime;
this.executor = executor;
}
public CompletableFuture<T> schedule(Supplier<T> supplier) {
queue.add(new ExecutionGroupEvent<T>(supplier));
if (running.compareAndSet(false, true)) {
result = new CompletableFuture<>();
executor.submit(this);
}
return result;
}
public void setExecutor(ExecutorService executor) {
this.executor = executor;
}
public void run() {
log.trace("Starting {}.", this);
try {
T value = getValueFromQueue();
if (log.isDebugEnabled()) {
String strVal = String.valueOf(value);
if (strVal.length() > 100) {
strVal = strVal.substring(0, 100);
}
log.trace("Finished {} with value {}", this, strVal);
}
result.complete(value);
} catch (Throwable t) {
log.error("Error while running {}", this, t);
result.completeExceptionally(t);
} finally {
running.set(false);
}
}
protected T getValueFromQueue() {
T value = null;
while (!queue.isEmpty()) {
T nextValue = getValue();
if (nextValue != null) {
value = nextValue;
}
}
return value;
}
protected T getValue() {
ExecutionGroupEvent<T> lastEvent = null;
while (true) {
try {
ExecutionGroupEvent<T> poll = queue.poll(waitTime, TimeUnit.MILLISECONDS);
if (poll == null) {
if (lastEvent != null) {
T value = lastEvent.getDelegate().get();
return value;
} else {
return null;
}
} else {
lastEvent = poll;
}
} catch (InterruptedException e) {
if (lastEvent != null) {
return lastEvent.getDelegate().get();
} else {
return null;
}
}
}
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("LastExecutionGroup{");
sb.append("desc='").append(desc).append('\'');
sb.append(", waitTime=").append(waitTime);
sb.append('}');
return sb.toString();
}
}