/*
* Copyright (C) 2012-2013 Facebook, Inc.
*
* 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 io.nettythrift.core;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.thrift.TBaseProcessor;
import io.netty.channel.ChannelHandler;
import io.netty.util.concurrent.DefaultExecutorServiceFactory;
import io.nettythrift.protocol.DefaultProtocolFactorySelectorFactory;
import io.nettythrift.protocol.ProtocolFactorySelectorFactory;
/**
* Builder for the Thrift Server descriptor. Example : <code>
* new ThriftServerDefBuilder()
* .listen(config.getServerPort())
* .limitFrameSizeTo(config.getMaxFrameSize())
* .withProcessor(new FacebookService.Processor(new MyFacebookBase()))
* .using(Executors.newFixedThreadPool(5))
* .build();
* <p/>
* <p/>
* You can then pass ThriftServerDef to guice via a multibinder.
* <p/>
* </code>
*/
public abstract class ThriftServerDefBuilderBase<T extends ThriftServerDefBuilderBase<T>> {
private static final AtomicInteger ID = new AtomicInteger(1);
private String name = "netty5thrift-" + ID.getAndIncrement();
private int serverPort = 8081;
private int maxFrameSize = MAX_FRAME_SIZE;
private int maxConnections;
private int queuedResponseLimit = 16;
@SuppressWarnings("rawtypes")
private TBaseProcessor processor;
private NettyProcessorFactory nettyProcessorFactory;// hasDefault
private ChannelHandler contextHandlerInstaller;// hasDefault
private ExecutorService executor;// hasDefault
private long clientIdleTimeout = 15000;// hasDefault
private ProtocolFactorySelectorFactory protocolFactorySelectorFactory;// hasDefault
private HttpResourceHandler httpResourceHandler;// hasDefault
private boolean voidMethodDirectReturn;// hasDefault:false
private HttpHandlerFactory httpHandlerFactory;// hasDefault
private TrafficForecastFactory trafficForecastFactory;// hasDefault
private LogicExecutionStatistics logicExecutionStatistics;// hasDefault
/**
* The default maximum allowable size for a single incoming thrift request
* or outgoing thrift response. A server can configure the actual maximum to
* be much higher (up to 0x7FFFFFFF or almost 2 GB). This default could also
* be safely bumped up, but 64MB is chosen simply because it seems
* reasonable that if you are sending requests or responses larger than
* that, it should be a conscious decision (something you must manually
* configure).
*/
private static final int MAX_FRAME_SIZE = 64 * 1024 * 1024;
/**
* Create a ThriftServerDefBuilder with common defaults
*/
public ThriftServerDefBuilderBase() {
}
/**
* Give the endpoint a more meaningful name.
*/
@SuppressWarnings("unchecked")
public T name(String name) {
this.name = name;
return (T) this;
}
/**
* Listen to this port.
*/
@SuppressWarnings("unchecked")
public T listen(int serverPort) {
this.serverPort = serverPort;
return (T) this;
}
/**
* Specify the TProcessor.
*/
@SuppressWarnings("unchecked")
public T withNettyProcessorFactory(final NettyProcessorFactory nettyProcessorFactory) {
this.nettyProcessorFactory = nettyProcessorFactory;
return (T) this;
}
@SuppressWarnings("unchecked")
public T withProcessor(@SuppressWarnings("rawtypes") TBaseProcessor processor) {
this.processor = processor;
return (T) this;
}
@SuppressWarnings("unchecked")
public T protocolFactorySelectorFactory(ProtocolFactorySelectorFactory protocolFactorySelectorFactory) {
this.protocolFactorySelectorFactory = protocolFactorySelectorFactory;
return (T) this;
}
/**
* Set frame size limit. Default is MAX_FRAME_SIZE
*/
@SuppressWarnings("unchecked")
public T limitFrameSizeTo(int maxFrameSize) {
this.maxFrameSize = maxFrameSize;
return (T) this;
}
/**
* Set maximum number of connections. Default is 0 (unlimited)
*/
@SuppressWarnings("unchecked")
public T limitConnectionsTo(int maxConnections) {
this.maxConnections = maxConnections;
return (T) this;
}
/**
* Limit number of queued responses per connection, before pausing reads to
* catch up.
*/
@SuppressWarnings("unchecked")
public T limitQueuedResponsesPerConnection(int queuedResponseLimit) {
this.queuedResponseLimit = queuedResponseLimit;
return (T) this;
}
/**
* Specify timeout during which if connected client doesn't send a message,
* server will disconnect the client
*/
@SuppressWarnings("unchecked")
public T clientIdleTimeout(long clientIdleTimeout) {
this.clientIdleTimeout = clientIdleTimeout;
return (T) this;
}
/**
* Specify an executor for thrift processor invocations ( i.e. = THaHsServer
* ) By default invocation happens in Netty single thread ( i.e. =
* TNonBlockingServer )
*/
@SuppressWarnings("unchecked")
public T using(ExecutorService exe) {
this.executor = exe;
return (T) this;
}
@SuppressWarnings("unchecked")
public T contextHandlerInstaller(ChannelHandler contextHandlerInstaller) {
this.contextHandlerInstaller = contextHandlerInstaller;
return (T) this;
}
@SuppressWarnings("unchecked")
public T httpResourceHandler(HttpResourceHandler httpResourceHandler) {
this.httpResourceHandler = httpResourceHandler;
return (T) this;
}
@SuppressWarnings("unchecked")
public T voidMethodDirectReturn(boolean voidMethodDirectReturn) {
this.voidMethodDirectReturn = voidMethodDirectReturn;
return (T) this;
}
@SuppressWarnings("unchecked")
public T httpHandlerFactory(HttpHandlerFactory httpHandlerFactory) {
this.httpHandlerFactory = httpHandlerFactory;
return (T) this;
}
@SuppressWarnings("unchecked")
public T trafficForecastFactory(TrafficForecastFactory trafficForecast) {
this.trafficForecastFactory = trafficForecast;
return (T) this;
}
@SuppressWarnings("unchecked")
public T logicExecutionStatistics(LogicExecutionStatistics logicExecutionStatistics) {
this.logicExecutionStatistics = logicExecutionStatistics;
return (T) this;
}
/**
* Build the ThriftServerDef
*/
public ThriftServerDef build() {
checkState(processor != null, "Processor not defined!");
checkState(maxConnections >= 0, "maxConnections should be 0 (for unlimited) or positive");
if (executor == null) {
executor = new DefaultExecutorServiceFactory("NettyThrift")
.newExecutorService(Runtime.getRuntime().availableProcessors() + 1);
}
if (protocolFactorySelectorFactory == null) {
protocolFactorySelectorFactory = new DefaultProtocolFactorySelectorFactory();
}
if (httpResourceHandler == null) {
httpResourceHandler = new HttpFileResourceHandler();
}
return new ThriftServerDef(name, serverPort, maxFrameSize, maxConnections, queuedResponseLimit,
nettyProcessorFactory, contextHandlerInstaller, processor, executor, clientIdleTimeout,
protocolFactorySelectorFactory, httpResourceHandler, voidMethodDirectReturn, httpHandlerFactory,
trafficForecastFactory, logicExecutionStatistics);
}
/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression
* a boolean expression
* @throws IllegalStateException
* if {@code expression} is false
*/
public static void checkState(boolean expression) {
if (!expression) {
throw new IllegalStateException();
}
}
/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression
* a boolean expression
* @param errorMessage
* the exception message to use if the check fails; will be
* converted to a string using {@link String#valueOf(Object)}
* @throws IllegalStateException
* if {@code expression} is false
*/
public static void checkState(boolean expression, Object errorMessage) {
if (!expression) {
throw new IllegalStateException(String.valueOf(errorMessage));
}
}
}