/** * 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.channel.builder; import java.nio.ByteBuffer; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import net.dsys.commons.api.lang.Factory; import net.dsys.commons.impl.builder.Mandatory; import net.dsys.commons.impl.builder.OptionGroup; import net.dsys.commons.impl.builder.Optional; import net.dsys.commons.impl.lang.ByteBufferFactory; import net.dsys.commons.impl.lang.DirectByteBufferFactory; import net.dsys.snio.api.buffer.MessageBufferConsumer; import net.dsys.snio.api.buffer.MessageBufferProvider; import net.dsys.snio.api.pool.SelectorPool; import net.dsys.snio.impl.buffer.BlockingQueueProvider; import net.dsys.snio.impl.buffer.RingBufferProvider; /** * @author Ricardo Padilha */ public final class ChannelConfig<T> { /** * Value obtained empirically on a 3rd gen Core i7. Lower values means * lower throughput, higher values mean more erratic throughput. */ private static final int DEFAULT_CAPACITY = 256; private static final int DEFAULT_BUFFER_SIZE = 0xFFFF; private SelectorPool pool; private int capacity; private int sendBufferSize; private int receiveBufferSize; private boolean useDirectBuffer; private boolean useRingBuffer; private boolean singleInputBuffer; private MessageBufferConsumer<T> consumer; public ChannelConfig() { this.pool = null; this.capacity = DEFAULT_CAPACITY; this.sendBufferSize = DEFAULT_BUFFER_SIZE; this.receiveBufferSize = DEFAULT_BUFFER_SIZE; this.useDirectBuffer = false; this.useRingBuffer = false; this.singleInputBuffer = false; this.consumer = null; } @Nonnull @Mandatory(restrictions = "pool != null") public ChannelConfig<T> setPool(@Nonnull final SelectorPool pool) { if (pool == null) { throw new NullPointerException("pool == null"); } this.pool = pool; return this; } @Nonnull @Optional(defaultValue = "256", restrictions = "capacity > 0") public ChannelConfig<T> setBufferCapacity(@Nonnegative final int capacity) { if (capacity < 1) { throw new IllegalArgumentException("capacity < 1"); } this.capacity = capacity; return this; } @Nonnull @Optional(defaultValue = "0xFFFF", restrictions = "sendBufferSize > 0") public ChannelConfig<T> setSendBufferSize(@Nonnegative final int sendBufferSize) { if (sendBufferSize < 1) { throw new IllegalArgumentException("sendBufferSize < 1"); } this.sendBufferSize = sendBufferSize; return this; } @Nonnull @Optional(defaultValue = "0xFFFF", restrictions = "receiveBufferSize > 0") public ChannelConfig<T> setReceiveBufferSize(@Nonnegative final int receiveBufferSize) { if (receiveBufferSize < 1) { throw new IllegalArgumentException("receiveBufferSize < 1"); } this.receiveBufferSize = receiveBufferSize; return this; } @Nonnull @Optional(defaultValue = "useHeapBuffer()") @OptionGroup(name = "bufferType", seeAlso = "useHeapBuffer()") public ChannelConfig<T> useDirectBuffer() { this.useDirectBuffer = true; return this; } @Nonnull @Optional(defaultValue = "useHeapBuffer()") @OptionGroup(name = "bufferType", seeAlso = "useDirectBuffer()") public ChannelConfig<T> useHeapBuffer() { this.useDirectBuffer = false; return this; } @Nonnull @Optional(defaultValue = "useBlockingQueue()", restrictions = "requires disruptor library") @OptionGroup(name = "bufferImplementation", seeAlso = "useBlockingQueue()") public ChannelConfig<T> useRingBuffer() { this.useRingBuffer = true; return this; } @Nonnull @Optional(defaultValue = "useBlockingQueue()") @OptionGroup(name = "bufferImplementation", seeAlso = "useRingBuffer()") public ChannelConfig<T> useBlockingQueue() { this.useRingBuffer = false; return this; } @Nonnull @Optional(defaultValue = "useMultipleInputBuffers()") @OptionGroup(name = "inputBuffer", seeAlso = "useSingleInputBuffer(consumer), useMultipleInputBuffers()") public ChannelConfig<T> useSingleInputBuffer() { this.singleInputBuffer = true; this.consumer = null; return this; } @Nonnull @Optional(defaultValue = "useMultipleInputBuffers()", restrictions = "consumer != null") @OptionGroup(name = "inputBuffer", seeAlso = "useSingleInputBuffer(), useMultipleInputBuffers()") public ChannelConfig<T> useSingleInputBuffer(@Nonnull final MessageBufferConsumer<T> consumer) { if (consumer == null) { throw new NullPointerException("consumer == null"); } this.singleInputBuffer = true; this.consumer = consumer; return this; } @Nonnull @Optional(defaultValue = "useMultipleInputBuffers()") @OptionGroup(name = "inputBuffer", seeAlso = "useSingleInputBuffer(), useSingleInputBuffer(consumer)") public ChannelConfig<T> useMultipleInputBuffers() { this.singleInputBuffer = false; this.consumer = null; return this; } @Nonnull public SelectorPool getPool() { if (pool == null) { throw new IllegalStateException("pool is undefined"); } return pool; } @Nonnegative public int getCapacity() { return capacity; } @Nonnegative public int getSendBufferSize() { return sendBufferSize; } @Nonnegative public int getReceiveBufferSize() { return receiveBufferSize; } public boolean isDirectBuffer() { return useDirectBuffer; } @Nonnull public Factory<ByteBuffer> getFactory(@Nonnegative final int length) { if (useDirectBuffer) { return new DirectByteBufferFactory(length); } return new ByteBufferFactory(length); } public boolean isRingBuffer() { return useRingBuffer; } @Nonnull public MessageBufferProvider<T> getProvider(@Nonnull final Factory<T> factory) { final MessageBufferProvider<T> provider; if (useRingBuffer) { if (singleInputBuffer) { MessageBufferConsumer<T> cons = consumer; if (cons == null) { cons = RingBufferProvider.createConsumer(capacity, factory); } provider = RingBufferProvider.createProvider(capacity, factory, cons); } else { provider = RingBufferProvider.createProvider(capacity, factory); } } else { if (singleInputBuffer) { MessageBufferConsumer<T> cons = consumer; if (cons == null) { cons = BlockingQueueProvider.createConsumer(capacity, factory); } provider = RingBufferProvider.createProvider(capacity, factory, cons); } else { provider = RingBufferProvider.createProvider(capacity, factory); } } return provider; } @Nonnull public Factory<MessageBufferProvider<T>> getProviderFactory(@Nonnull final Factory<T> factory) { final Factory<MessageBufferProvider<T>> provider; if (useRingBuffer) { if (singleInputBuffer) { MessageBufferConsumer<T> cons = consumer; if (cons == null) { cons = RingBufferProvider.createConsumer(capacity, factory); } provider = RingBufferProvider.createProviderFactory(capacity, factory, cons); } else { provider = RingBufferProvider.createProviderFactory(capacity, factory); } } else { if (singleInputBuffer) { MessageBufferConsumer<T> cons = consumer; if (cons == null) { cons = BlockingQueueProvider.createConsumer(capacity, factory); } provider = BlockingQueueProvider.createProviderFactory(capacity, factory, cons); } else { provider = BlockingQueueProvider.createProviderFactory(capacity, factory); } } return provider; } }