package reactor.spring.context;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.TopicProcessor;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.SmartLifecycle;
/**
* Implementation of {@link org.springframework.context.ApplicationEventPublisher} that uses a {@link
* reactor.util.concurrent.RingBuffer} to dispatch events.
*
* @author Jon Brisbin
*/
public class RingBufferApplicationEventPublisher implements ApplicationEventPublisher,
ApplicationContextAware,
SmartLifecycle {
private final Logger log = LoggerFactory.getLogger(getClass());
private final boolean autoStartup;
private final TopicProcessor<ApplicationEvent> processor;
private volatile boolean running = false;
private ApplicationContext appCtx;
public RingBufferApplicationEventPublisher(int backlog, boolean autoStartup) {
this.autoStartup = autoStartup;
this.processor = TopicProcessor.share("ringBufferAppEventPublisher", backlog);
if(autoStartup) {
start();
}
}
@Override
public void setApplicationContext(ApplicationContext appCtx) throws BeansException {
this.appCtx = appCtx;
}
@Override
public boolean isAutoStartup() {
return autoStartup;
}
@Override
public void stop(Runnable callback) {
processor.onComplete();
if(null != callback) {
callback.run();
}
synchronized(this) {
running = false;
}
}
@Override
public void start() {
synchronized(this) {
processor.subscribe(new Subscriber<ApplicationEvent>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(ApplicationEvent applicationEvent) {
appCtx.publishEvent(applicationEvent);
}
@Override
public void onError(Throwable t) {
log.error("", t);
}
@Override
public void onComplete() {
log.trace("AppEvent Publisher has shutdown");
}
});
running = true;
}
}
@Override
public void stop() {
stop(null);
}
@Override
public boolean isRunning() {
synchronized(this) {
return running;
}
}
@Override
public int getPhase() {
return 0;
}
@Override
public void publishEvent(ApplicationEvent event) {
processor.onNext(event);
}
}