From 24b4db3f5773cb739531f82eb6662dad9df2fe80 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Mon, 11 Aug 2008 06:57:13 +0000 Subject: [PATCH] JavaDoc for the bootstrap package --- .../org/jboss/netty/bootstrap/Bootstrap.java | 103 +++++++++++++- .../netty/bootstrap/ClientBootstrap.java | 120 +++++++++++++++- .../netty/bootstrap/ServerBootstrap.java | 132 ++++++++++++++++++ .../jboss/netty/bootstrap/package-info.java | 4 +- 4 files changed, 352 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jboss/netty/bootstrap/Bootstrap.java b/src/main/java/org/jboss/netty/bootstrap/Bootstrap.java index 0f4994091a..0335c3fd4c 100644 --- a/src/main/java/org/jboss/netty/bootstrap/Bootstrap.java +++ b/src/main/java/org/jboss/netty/bootstrap/Bootstrap.java @@ -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 options = new HashMap(); - 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 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 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 getOptions() { return new TreeMap(options); } + /** + * Sets the options which configures a new {@link Channel}. + */ public void setOptions(Map options) { if (options == null) { throw new NullPointerException("options"); @@ -149,6 +236,12 @@ public class Bootstrap { this.options = new HashMap(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"); diff --git a/src/main/java/org/jboss/netty/bootstrap/ClientBootstrap.java b/src/main/java/org/jboss/netty/bootstrap/ClientBootstrap.java index 07b92ace66..76506c841d 100644 --- a/src/main/java/org/jboss/netty/bootstrap/ClientBootstrap.java +++ b/src/main/java/org/jboss/netty/bootstrap/ClientBootstrap.java @@ -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. + * + *

Configuring a channel

+ * + * {@link #setOption(String, Object) Options} are used to configure a channel: + * + *
+ * ClientBootstrap b = ...;
+ *
+ * // Options for a new channel
+ * b.setOption("remoteAddress", new InetSocketAddress("example.com", 8080));
+ * b.setOption("tcpNoDelay", true);
+ * b.setOption("receiveBufferSize", 1048576);
+ * 
+ * + *

Configuring a channel pipeline

+ * + * 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: + * + *
+ * 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());
+ * 
+ * + * {@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: + * + *
+ * ClientBootstrap b = ...;
+ * b.setPipelineFactory(new MyPipelineFactory());
+ *
+ * public class MyPipelineFactory implements ChannelPipelineFactory {
+ *   // Create a new pipeline for a new channel and configure it here ...
+ * }
+ * 
+ * * @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: + * + *
+     * ClientBootstrap b = ...;
+     * b.connect(b.getOption("remoteAddress"), b.getOption("localAddress"));
+     * 
+ * + * @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: + * + *
+     * ClientBootstrap b = ...;
+     * b.connect(remoteAddress, b.getOption("localAddress"));
+     * 
+ * + * @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 futureQueue = diff --git a/src/main/java/org/jboss/netty/bootstrap/ServerBootstrap.java b/src/main/java/org/jboss/netty/bootstrap/ServerBootstrap.java index cbfdfc83c0..899e3a256e 100644 --- a/src/main/java/org/jboss/netty/bootstrap/ServerBootstrap.java +++ b/src/main/java/org/jboss/netty/bootstrap/ServerBootstrap.java @@ -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. + * + *

Parent channel and its children

+ * + * 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)}. + *

+ * Once successfully bound, the parent channel starts to accept incoming + * connections, and the accepted connections becomes the children of the + * parent channel. + * + *

Configuring channels

+ * + * {@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: + * + *
+ * 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);
+ * 
+ * + *

Configuring a parent channel pipeline

+ * + * 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 + * UID from + * a superuser 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. + * + *

Configuring a child channel pipeline

+ * + * 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: + * + *
+ * 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());
+ * 
+ * + * {@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: + * + *
+ * ServerBootstrap b = ...;
+ * b.setPipelineFactory(new MyPipelineFactory());
+ *
+ * public class MyPipelineFactory implements ChannelPipelineFactory {
+ *   // Create a new pipeline for a new child channel and configure it here ...
+ * }
+ * 
+ * * @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: + * + *
+     * ServerBootstrap b = ...;
+     * b.connect(b.getOption("localAddress"));
+     * 
+ * + * @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 futureQueue = new LinkedBlockingQueue(); diff --git a/src/main/java/org/jboss/netty/bootstrap/package-info.java b/src/main/java/org/jboss/netty/bootstrap/package-info.java index 2c4319540a..97343ca37a 100644 --- a/src/main/java/org/jboss/netty/bootstrap/package-info.java +++ b/src/main/java/org/jboss/netty/bootstrap/package-info.java @@ -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 */