/**
* 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.handler;
import static net.dsys.snio.impl.handler.HandlerType.MULTI_THREADED;
import static net.dsys.snio.impl.handler.HandlerType.SINGLE_THREADED;
import java.io.IOException;
import java.net.SocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
import net.dsys.commons.api.exception.Bug;
import net.dsys.snio.api.buffer.MessageBufferConsumer;
import net.dsys.snio.api.channel.AcceptListener;
import net.dsys.snio.api.channel.MessageChannel;
import net.dsys.snio.api.handler.MessageConsumer;
import net.dsys.snio.api.handler.MessageConsumerFactory;
import net.dsys.snio.api.handler.MessageHandler;
/**
* @author Ricardo Padilha
*/
final class MessageHandlerImpl<T> implements MessageHandler<T> {
private final HandlerType type;
private final ExecutorService executor;
private final ConsumerThreadFactory<T> threads;
private final MessageConsumerFactory<T> factory;
private final MessageConsumer<T> consumer;
private final AcceptListener<T> delegate;
private final AcceptListener<T> listener;
private final AtomicBoolean started;
MessageHandlerImpl(@Nonnull final ExecutorService executor,
@Nonnull final ConsumerThreadFactory<T> threads,
@Nonnull final MessageConsumerFactory<T> factory,
@Nonnull final AcceptListener<T> delegate) {
if (executor == null) {
throw new NullPointerException("executor == null");
}
if (threads == null) {
throw new NullPointerException("threads == null");
}
if (factory == null) {
throw new NullPointerException("factory == null");
}
this.type = MULTI_THREADED;
this.executor = executor;
this.threads = threads;
this.factory = factory;
this.consumer = null;
this.delegate = delegate;
this.listener = new DefaultListener();
this.started = null;
}
MessageHandlerImpl(@Nonnull final ExecutorService executor,
@Nonnull final ConsumerThreadFactory<T> factory,
@Nonnull final MessageConsumer<T> consumer,
@Nonnull final AcceptListener<T> delegate) {
if (executor == null) {
throw new NullPointerException("executor == null");
}
if (factory == null) {
throw new NullPointerException("factory == null");
}
if (consumer == null) {
throw new NullPointerException("consumer == null");
}
this.type = SINGLE_THREADED;
this.executor = executor;
this.threads = factory;
this.consumer = consumer;
this.factory = null;
this.delegate = delegate;
this.listener = new DefaultListener();
this.started = new AtomicBoolean();
}
/**
* {@inheritDoc}
*/
@Override
public AcceptListener<T> getAcceptListener() {
return listener;
}
void accept(@Nonnull final SocketAddress remote, @Nonnull final MessageChannel<T> channel) {
if (delegate != null) {
delegate.connectionAccepted(remote, channel);
}
switch (type) {
case MULTI_THREADED: {
final MessageBufferConsumer<T> in = channel.getInputBuffer();
final MessageConsumer<T> handler = factory.newInstance(remote, channel);
final Runnable runnable = threads.newInstance(in, handler);
executor.execute(runnable);
break;
}
case SINGLE_THREADED:
if (started.compareAndSet(false, true)) {
final MessageBufferConsumer<T> in = channel.getInputBuffer();
final Runnable runnable = threads.newInstance(in, consumer);
executor.execute(runnable);
}
break;
default: {
throw new Bug("Unsupported HandlerType + " + type);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void close() throws IOException {
executor.shutdownNow();
}
/**
* @author Ricardo Padilha
*/
private class DefaultListener implements AcceptListener<T> {
DefaultListener() {
return;
}
/**
* {@inheritDoc}
*/
@Override
public void connectionAccepted(final SocketAddress remote, final MessageChannel<T> channel) {
accept(remote, channel);
}
}
}