/**
* Copyright 2014 Ricardo Padilha
*
* 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 net.dsys.snio.impl.buffer;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import net.dsys.commons.api.lang.Factory;
import net.dsys.snio.api.buffer.MessageBufferConsumer;
import net.dsys.snio.api.buffer.MessageBufferProducer;
import net.dsys.snio.api.buffer.MessageBufferProvider;
import net.dsys.snio.api.pool.KeyProcessor;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.WaitStrategy;
/**
* @author Ricardo Padilha
*/
public final class RingBufferProvider<T> implements MessageBufferProvider<T> {
private final WakeupWaitStrategy waitOut;
private final WaitStrategy waitIn;
private final RingBuffer<T> out; // app -> channel
private final RingBuffer<T> in; // channel -> app
private final Object[] attachOut;
private final Object[] attachIn;
private final RingBufferProducer<T> appOut; // app producer
private final RingBufferConsumer<T> chnIn; // channel consumer
private final MessageBufferProducer<T> chnOut; // channel producer
private final MessageBufferConsumer<T> appIn; // app consumer
private final boolean internalConsumer;
RingBufferProvider(@Nonnegative final int capacity, @Nonnull final Factory<T> factory) {
this.waitOut = new WakeupWaitStrategy();
this.waitIn = new BlockingWaitStrategy();
final EventFactory<T> evfactory = wrapFactory(factory);
this.out = RingBuffer.createMultiProducer(evfactory, capacity, waitOut);
this.in = RingBuffer.createSingleProducer(evfactory, capacity, waitIn);
this.attachOut = new Object[capacity];
this.attachIn = new Object[capacity];
this.appOut = new RingBufferProducer<>(out, attachOut);
this.chnIn = new RingBufferConsumer<>(out, attachOut);
this.chnOut = new RingBufferProducer<>(in, attachIn);
this.appIn = new RingBufferConsumer<>(in, attachIn);
this.internalConsumer = true;
}
RingBufferProvider(@Nonnegative final int capacity, @Nonnull final Factory<T> factory,
@Nonnull final MessageBufferConsumer<T> appIn) {
if (appIn == null) {
throw new NullPointerException("appIn == null");
}
this.waitOut = new WakeupWaitStrategy();
this.waitIn = null;
final EventFactory<T> evfactory = wrapFactory(factory);
this.out = RingBuffer.createMultiProducer(evfactory, capacity, waitOut);
this.in = null;
this.attachOut = new Object[capacity];
this.attachIn = null;
this.appOut = new RingBufferProducer<>(out, attachOut);
this.chnIn = new RingBufferConsumer<>(out, attachOut);
this.chnOut = appIn.createProducer();
this.appIn = appIn;
this.internalConsumer = false;
}
/**
* {@inheritDoc}
*/
@Override
public MessageBufferProducer<T> getAppOutput(final KeyProcessor<T> processor) {
waitOut.setProcessor(processor);
return appOut;
}
/**
* {@inheritDoc}
*/
@Override
public MessageBufferConsumer<T> getChannelInput() {
return chnIn;
}
/**
* {@inheritDoc}
*/
@Override
public MessageBufferProducer<T> getChannelOutput() {
return chnOut;
}
/**
* {@inheritDoc}
*/
@Override
public MessageBufferConsumer<T> getAppInput() {
return appIn;
}
/**
* {@inheritDoc}
*/
@Override
public void close() {
chnIn.close();
appOut.close();
if (internalConsumer) {
((RingBufferProducer<?>) chnOut).close();
((RingBufferConsumer<?>) appIn).close();
}
}
/**
* Convert a {@link Factory} into an {@link EventFactory}
*/
private static <T> EventFactory<T> wrapFactory(@Nonnull final Factory<T> factory) {
if (factory == null) {
throw new NullPointerException("factory == null");
}
return new EventFactory<T>() {
@Override
public T newInstance() {
return factory.newInstance();
}
};
}
public static <T> RingBufferConsumer<T> createConsumer(@Nonnegative final int capacity,
@Nonnull final Factory<T> factory) {
final EventFactory<T> evfactory = wrapFactory(factory);
final RingBuffer<T> buffer = RingBuffer.createMultiProducer(evfactory, capacity);
final Object[] attachments = new Object[capacity];
final RingBufferConsumer<T> consumer = new RingBufferConsumer<>(buffer, attachments);
return consumer;
}
public static <T> MessageBufferProvider<T> createProvider(@Nonnegative final int capacity,
@Nonnull final Factory<T> factory) {
return new RingBufferProvider<>(capacity, factory);
}
public static <T> Factory<MessageBufferProvider<T>> createProviderFactory(@Nonnegative final int capacity,
@Nonnull final Factory<T> factory) {
return new ProviderFactory<>(capacity, factory);
}
public static <T> MessageBufferProvider<T> createProvider(@Nonnegative final int capacity,
@Nonnull final Factory<T> factory, @Nonnull final MessageBufferConsumer<T> consumer) {
return new RingBufferProvider<>(capacity, factory, consumer);
}
public static <T> Factory<MessageBufferProvider<T>> createProviderFactory(@Nonnegative final int capacity,
@Nonnull final Factory<T> factory, @Nonnull final MessageBufferConsumer<T> consumer) {
return new ProviderFactory<>(capacity, factory, consumer);
}
private static final class ProviderFactory<T> implements Factory<MessageBufferProvider<T>> {
private final int capacity;
private final Factory<T> factory;
private final MessageBufferConsumer<T> consumer;
ProviderFactory(@Nonnegative final int capacity, @Nonnull final Factory<T> factory) {
if (capacity < 1) {
throw new IllegalArgumentException("capacity < 1");
}
if (factory == null) {
throw new NullPointerException("factory == null");
}
this.capacity = capacity;
this.factory = factory;
this.consumer = null;
}
ProviderFactory(@Nonnegative final int capacity, @Nonnull final Factory<T> factory,
@Nonnull final MessageBufferConsumer<T> consumer) {
if (capacity < 1) {
throw new IllegalArgumentException("capacity < 1");
}
if (factory == null) {
throw new NullPointerException("factory == null");
}
if (consumer == null) {
throw new NullPointerException("consumer == null");
}
this.capacity = capacity;
this.factory = factory;
this.consumer = consumer;
}
@Override
public MessageBufferProvider<T> newInstance() {
if (consumer != null) {
return new RingBufferProvider<>(capacity, factory, consumer);
}
return new RingBufferProvider<>(capacity, factory);
}
}
}