JavaDoc for the bootstrap package

This commit is contained in:
Trustin Lee 2008-08-11 06:57:13 +00:00
parent ad805a1f70
commit 24b4db3f57
4 changed files with 352 additions and 7 deletions

View File

@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelPipeline;
@ -42,6 +43,13 @@ import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
/**
* Helper class which helps a user initialize a {@link Channel}. This class
* provides the common data structure for its subclasses which implements an
* actual channel initialization from the common data structure. Please refer
* to {@link ClientBootstrap} and {@link ServerBootstrap} for client side and
* server-side channel initialization respectively.
*
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
@ -58,14 +66,31 @@ public class Bootstrap {
private volatile ChannelPipelineFactory pipelineFactory = pipelineFactory(pipeline);
private volatile Map<String, Object> options = new HashMap<String, Object>();
public Bootstrap() {
/**
* Creates a new instance with no {@link ChannelFactory} set.
* {@link #setFactory(ChannelFactory)} must be called at once before any
* I/O operation is requested.
*/
protected Bootstrap() {
super();
}
public Bootstrap(ChannelFactory channelFactory) {
/**
* Creates a new instance with the specified initial {@link ChannelFactory}.
*/
protected Bootstrap(ChannelFactory channelFactory) {
setFactory(channelFactory);
}
/**
* Returns the {@link ChannelFactory} that will be used to perform an
* I/O operation.
*
* @throws IllegalStateException
* if the factory is not set for this bootstrap yet.
* The factory can be set in the constructor or
* {@link #setFactory(ChannelFactory)}.
*/
public ChannelFactory getFactory() {
ChannelFactory factory = this.factory;
if (factory == null) {
@ -75,6 +100,14 @@ public class Bootstrap {
return factory;
}
/**
* Sets the {@link ChannelFactory} that will be used to perform an I/O
* operation. This method can be called only once and can't be called at
* all if the factory was specified in the constructor.
*
* @throws IllegalStateException
* if the factory is already set
*/
public void setFactory(ChannelFactory factory) {
if (this.factory != null) {
throw new IllegalStateException(
@ -86,10 +119,27 @@ public class Bootstrap {
this.factory = factory;
}
/**
* Returns the default {@link ChannelPipeline} which is cloned when a new
* {@link Channel} is created. Bootstrap creates a new pipeline which has
* the same entries with the returned pipeline for a new {@link Channel}.
*
* @return the default {@link ChannelPipeline}. {@code null} if
* {@link #setPipelineFactory(ChannelPipelineFactory)} was
* called last time.
*/
public ChannelPipeline getPipeline() {
return pipeline;
}
/**
* Sets the default {@link ChannelPipeline} which is cloned when a new
* {@link Channel} is created. Bootstrap creates a new pipeline which has
* the same entries with the specified pipeline for a new channel. Calling
* this method also sets the {@code pipelineFactory} property to an
* internal {@link ChannelPipelineFactory} implementation which returns
* a copy of the specified pipeline.
*/
public void setPipeline(ChannelPipeline pipeline) {
if (pipeline == null) {
throw new NullPointerException("pipeline");
@ -98,6 +148,14 @@ public class Bootstrap {
pipelineFactory = pipelineFactory(pipeline);
}
/**
* Convenience method for {@link #getPipeline()} which returns the default
* pipeline of this bootstrap as an ordered map.
*
* @throws IllegalStateException
* if {@link #setPipelineFactory(ChannelPipelineFactory)} is in
* use to create a new pipeline
*/
public Map<String, ChannelHandler> getPipelineAsMap() {
ChannelPipeline pipeline = this.pipeline;
if (pipeline == null) {
@ -106,6 +164,13 @@ public class Bootstrap {
return pipeline.toMap();
}
/**
* Convenience method for {@link #setPipeline} which sets the default
* pipeline of this bootstrap from an ordered map.
*
* @throws IllegalArgumentException
* if the specified map is not an ordered map
*/
public void setPipelineAsMap(Map<String, ChannelHandler> pipelineMap) {
if (pipelineMap == null) {
throw new NullPointerException("pipelineMap");
@ -126,10 +191,26 @@ public class Bootstrap {
setPipeline(pipeline);
}
/**
* Returns the {@link ChannelPipelineFactory} which creates a new
* {@link ChannelPipeline} for a new {@link Channel}.
*
* @see #getPipeline()
*/
public ChannelPipelineFactory getPipelineFactory() {
return pipelineFactory;
}
/**
* Sets the {@link ChannelPipelineFactory} which creates a new
* {@link ChannelPipeline} for a new {@link Channel}. Calling this method
* invalidates the current {@code pipeline} property of this bootstrap.
* Subsequent {@link #getPipeline()} and {@link #getPipelineAsMap()} calls
* will raise {@link IllegalStateException}.
*
* @see #setPipeline(ChannelPipeline)
* @see #setPipelineAsMap(Map)
*/
public void setPipelineFactory(ChannelPipelineFactory pipelineFactory) {
if (pipelineFactory == null) {
throw new NullPointerException("pipelineFactory");
@ -138,10 +219,16 @@ public class Bootstrap {
this.pipelineFactory = pipelineFactory;
}
/**
* Returns the options which configures a new {@link Channel}.
*/
public Map<String, Object> getOptions() {
return new TreeMap<String, Object>(options);
}
/**
* Sets the options which configures a new {@link Channel}.
*/
public void setOptions(Map<String, Object> options) {
if (options == null) {
throw new NullPointerException("options");
@ -149,6 +236,12 @@ public class Bootstrap {
this.options = new HashMap<String, Object>(options);
}
/**
* Returns the value of the option with the specified key.
*
* @return the option value if the option is found.
* {@code null} otherwise.
*/
public Object getOption(String key) {
if (key == null) {
throw new NullPointerException("key");
@ -156,6 +249,12 @@ public class Bootstrap {
return options.get(key);
}
/**
* Sets an option with the specified key and value. If there's already
* an option with the same key, it's replaced with the new value. If the
* specified value is {@code null}, an existing option with the specified
* key is removed.
*/
public void setOption(String key, Object value) {
if (key == null) {
throw new NullPointerException("key");

View File

@ -29,17 +29,66 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.channel.ChannelPipelineException;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
/**
* Helper class which helps a user create a new client-side {@link Channel}
* and make a connection attempt.
*
* <h3>Configuring a channel</h3>
*
* {@link #setOption(String, Object) Options} are used to configure a channel:
*
* <pre>
* ClientBootstrap b = ...;
*
* // Options for a new channel
* b.setOption("remoteAddress", new InetSocketAddress("example.com", 8080));
* b.setOption("tcpNoDelay", true);
* b.setOption("receiveBufferSize", 1048576);
* </pre>
*
* <h3>Configuring a channel pipeline</h3>
*
* Every channel has its own {@link ChannelPipeline} and you can configure it
* in two ways.
*
* {@linkplain #setPipeline(ChannelPipeline) The first approach} is to use
* the default pipeline and let the bootstrap to clone it for each new channel:
*
* <pre>
* ClientBootstrap b = ...;
* ChannelPipeline p = b.getPipeline();
*
* // Add handlers to the pipeline.
* p.addLast("encoder", new EncodingHandler());
* p.addLast("decoder", new DecodingHandler());
* p.addLast("logic", new LogicHandler());
* </pre>
*
* {@linkplain #setPipelineFactory(ChannelPipelineFactory) The second approach}
* is to specify a {@link ChannelPipelineFactory} by yourself and have full
* control over how a new pipeline is created, at the cost of more complexity:
*
* <pre>
* ClientBootstrap b = ...;
* b.setPipelineFactory(new MyPipelineFactory());
*
* public class MyPipelineFactory implements ChannelPipelineFactory {
* // Create a new pipeline for a new channel and configure it here ...
* }
* </pre>
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
@ -49,30 +98,95 @@ import org.jboss.netty.channel.SimpleChannelHandler;
*/
public class ClientBootstrap extends Bootstrap {
/**
* Creates a new instance with no {@link ChannelFactory} set.
* {@link #setFactory(ChannelFactory)} must be called at once before any
* I/O operation is requested.
*/
public ClientBootstrap() {
super();
}
/**
* Creates a new instance with the specified initial {@link ChannelFactory}.
*/
public ClientBootstrap(ChannelFactory channelFactory) {
super(channelFactory);
}
/**
* Attempts a new connection with the current {@code "remoteAddress"} and
* {@code "localAddress"} option. If the {@code "localAddress"} option is
* not set, the local address of a new channel is determined automatically.
* This method is similar to the following code:
*
* <pre>
* ClientBootstrap b = ...;
* b.connect(b.getOption("remoteAddress"), b.getOption("localAddress"));
* </pre>
*
* @return a future object which notifies when this connection attempt
* succeeds or fails
*
* @throws IllegalStateException
* if {@code "remoteAddress"} option was not set
* @throws ClassCastException
* if {@code "remoteAddress"} or {@code "localAddress"} option's
* value is neither a {@link SocketAddress} nor {@code null}
* @throws ChannelPipelineException
* if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory}
* failed to create a new {@link ChannelPipeline}
*/
public ChannelFuture connect() {
SocketAddress remoteAddress = (SocketAddress) getOption("remoteAddress");
if (remoteAddress == null) {
throw new IllegalStateException("remoteAddress option is not set.");
}
SocketAddress localAddress = (SocketAddress) getOption("localAddress");
return connect(remoteAddress, localAddress);
return connect(remoteAddress);
}
/**
* Attempts a new connection with the specified {@code remoteAddress} and
* the current {@code "localAddress"} option. If the {@code "localAddress"}
* option is not set, the local address of a new channel is determined
* automatically. This method is identical with the following code:
*
* <pre>
* ClientBootstrap b = ...;
* b.connect(remoteAddress, b.getOption("localAddress"));
* </pre>
*
* @return a future object which notifies when this connection attempt
* succeeds or fails
*
* @throws ClassCastException
* if {@code "localAddress"} option's value is
* neither a {@link SocketAddress} nor {@code null}
* @throws ChannelPipelineException
* if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory}
* failed to create a new {@link ChannelPipeline}
*/
public ChannelFuture connect(SocketAddress remoteAddress) {
if (remoteAddress == null) {
throw new NullPointerException("remotedAddress");
}
return connect(remoteAddress, null);
SocketAddress localAddress = (SocketAddress) getOption("localAddress");
return connect(remoteAddress, localAddress);
}
/**
* Attempts a new connection with the specified {@code remoteAddress} and
* the specified {@code localAddress}. If the specified local address is
* {@code null}, the local address of a new channel is determined
* automatically.
*
* @return a future object which notifies when this connection attempt
* succeeds or fails
*
* @throws ChannelPipelineException
* if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory}
* failed to create a new {@link ChannelPipeline}
*/
public ChannelFuture connect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
final BlockingQueue<ChannelFuture> futureQueue =

View File

@ -40,12 +40,91 @@ import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
/**
* Helper class which helps a user create a new server-side {@link Channel}
* and accept incoming connections.
*
* <h3>Parent channel and its children</h3>
*
* A parent channel is a channel which is supposed to accept incoming
* connections. It is created by this bootstrap's
* {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory} or
* {@link #setPipeline(ChannelPipeline) pipeline} property via {@link #bind()}
* and {@link #bind(SocketAddress)}.
* <p>
* Once successfully bound, the parent channel starts to accept incoming
* connections, and the accepted connections becomes the children of the
* parent channel.
*
* <h3>Configuring channels</h3>
*
* {@link #setOption(String, Object) Options} are used to configure both a
* parent channel and its child channels. To configure the child channels,
* prepend {@code "child."} prefix to the actual option names of a child
* channel:
*
* <pre>
* ServerBootstrap b = ...;
*
* // Options for a parent channel
* b.setOption("localAddress", new InetSocketAddress(8080));
* b.setOption("reuseAddress", true);
*
* // Options for its children
* b.setOption("child.tcpNoDelay", true);
* b.setOption("child.receiveBufferSize", 1048576);
* </pre>
*
* <h3>Configuring a parent channel pipeline</h3>
*
* It is rare to configure the pipeline of a parent channel because what it's
* supposed to do is very typical. However, you might want to add a handler
* to deal with some special needs such as degrading the process
* <a href="http://en.wikipedia.org/wiki/User_identifier_(Unix)">UID</a> from
* a <a href="http://en.wikipedia.org/wiki/Superuser">superuser</a> to a
* normal user and changing the current VM security manager for better
* security. To support such a case,
* the {@link #setParentHandler(ChannelHandler) parentHandler} property is
* provided.
*
* <h3>Configuring a child channel pipeline</h3>
*
* Every child channel has its own {@link ChannelPipeline} and you can
* configure it in two ways.
*
* {@linkplain #setPipeline(ChannelPipeline) The first approach} is to use
* the default pipeline property and let the bootstrap to clone it for each
* new child channel:
*
* <pre>
* ServerBootstrap b = ...;
* ChannelPipeline p = b.getPipeline();
*
* // Add handlers to the pipeline.
* p.addLast("encoder", new EncodingHandler());
* p.addLast("decoder", new DecodingHandler());
* p.addLast("logic", new LogicHandler());
* </pre>
*
* {@linkplain #setPipelineFactory(ChannelPipelineFactory) The second approach}
* is to specify a {@link ChannelPipelineFactory} by yourself and have full
* control over how a new pipeline is created, at the cost of more complexity:
*
* <pre>
* ServerBootstrap b = ...;
* b.setPipelineFactory(new MyPipelineFactory());
*
* public class MyPipelineFactory implements ChannelPipelineFactory {
* // Create a new pipeline for a new child channel and configure it here ...
* }
* </pre>
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
@ -57,22 +136,66 @@ public class ServerBootstrap extends Bootstrap {
private volatile ChannelHandler parentHandler;
/**
* Creates a new instance with no {@link ChannelFactory} set.
* {@link #setFactory(ChannelFactory)} must be called at once before any
* I/O operation is requested.
*/
public ServerBootstrap() {
super();
}
/**
* Creates a new instance with the specified initial {@link ChannelFactory}.
*/
public ServerBootstrap(ChannelFactory channelFactory) {
super(channelFactory);
}
/**
* Returns an optional {@link ChannelHandler} which intercepts an event
* of a new bound server-side channel which accepts incoming connections.
*
* @return the parent channel handler.
* {@code null} if no parent channel handler is set.
*/
public ChannelHandler getParentHandler() {
return parentHandler;
}
/**
* Sets an optional {@link ChannelHandler} which intercepts an event of
* a new bound server-side channel which accepts incoming connections.
*
* @param parentHandler
* the parent channel handler.
* {@code null} to unset the current parent channel handler.
*/
public void setParentHandler(ChannelHandler parentHandler) {
this.parentHandler = parentHandler;
}
/**
* Creates a new channel which is bound to the local address which were
* specified in the current {@code "localAddress"} option. This method is
* similar to the following code:
*
* <pre>
* ServerBootstrap b = ...;
* b.connect(b.getOption("localAddress"));
* </pre>
*
* @return a new bound channel which accepts incoming connections
*
* @throws IllegalStateException
* if {@code "localAddress"} option was not set
* @throws ClassCastException
* if {@code "localAddress"} option's value is
* neither a {@link SocketAddress} nor {@code null}
* @throws ChannelException
* if failed to create a new channel and
* bind it to the local address
*/
public Channel bind() {
SocketAddress localAddress = (SocketAddress) getOption("localAddress");
if (localAddress == null) {
@ -81,6 +204,15 @@ public class ServerBootstrap extends Bootstrap {
return bind(localAddress);
}
/**
* Creates a new channel which is bound to the specified local address.
*
* @return a new bound channel which accepts incoming connections
*
* @throws ChannelException
* if failed to create a new channel and
* bind it to the local address
*/
public Channel bind(final SocketAddress localAddress) {
final BlockingQueue<ChannelFuture> futureQueue =
new LinkedBlockingQueue<ChannelFuture>();

View File

@ -22,8 +22,8 @@
*/
/**
* Helper classes which enable an easy implementation of typical client and
* server socket initialization.
* Helper classes which enable an easy implementation of typical client side
* and server side channel initialization.
*
* @apiviz.landmark
*/