View Javadoc

1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.bootstrap;
17  
18  import static org.jboss.netty.channel.Channels.*;
19  
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.TreeMap;
27  
28  import org.jboss.netty.channel.Channel;
29  import org.jboss.netty.channel.ChannelFactory;
30  import org.jboss.netty.channel.ChannelHandler;
31  import org.jboss.netty.channel.ChannelPipeline;
32  import org.jboss.netty.channel.ChannelPipelineFactory;
33  import org.jboss.netty.util.ExternalResourceReleasable;
34  
35  /**
36   * A helper class which initializes a {@link Channel}.  This class provides
37   * the common data structure for its subclasses which actually initialize
38   * {@link Channel}s and their child {@link Channel}s using the common data
39   * structure.  Please refer to {@link ClientBootstrap}, {@link ServerBootstrap},
40   * and {@link ConnectionlessBootstrap} for client side, server-side, and
41   * connectionless (e.g. UDP) channel initialization respectively.
42   *
43   * @apiviz.uses org.jboss.netty.channel.ChannelFactory
44   */
45  public class Bootstrap implements ExternalResourceReleasable {
46  
47      private volatile ChannelFactory factory;
48      private volatile ChannelPipeline pipeline = pipeline();
49      private volatile ChannelPipelineFactory pipelineFactory = pipelineFactory(pipeline);
50      private volatile Map<String, Object> options = new HashMap<String, Object>();
51  
52      /**
53       * Creates a new instance with no {@link ChannelFactory} set.
54       * {@link #setFactory(ChannelFactory)} must be called at once before any
55       * I/O operation is requested.
56       */
57      protected Bootstrap() {
58          super();
59      }
60  
61      /**
62       * Creates a new instance with the specified initial {@link ChannelFactory}.
63       */
64      protected Bootstrap(ChannelFactory channelFactory) {
65          setFactory(channelFactory);
66      }
67  
68      /**
69       * Returns the {@link ChannelFactory} that will be used to perform an
70       * I/O operation.
71       *
72       * @throws IllegalStateException
73       *         if the factory is not set for this bootstrap yet.
74       *         The factory can be set in the constructor or
75       *         {@link #setFactory(ChannelFactory)}.
76       */
77      public ChannelFactory getFactory() {
78          ChannelFactory factory = this.factory;
79          if (factory == null) {
80              throw new IllegalStateException(
81                      "factory is not set yet.");
82          }
83          return factory;
84      }
85  
86      /**
87       * Sets the {@link ChannelFactory} that will be used to perform an I/O
88       * operation.  This method can be called only once and can't be called at
89       * all if the factory was specified in the constructor.
90       *
91       * @throws IllegalStateException
92       *         if the factory is already set
93       */
94      public void setFactory(ChannelFactory factory) {
95          if (factory == null) {
96              throw new NullPointerException("factory");
97          }
98          if (this.factory != null) {
99              throw new IllegalStateException(
100                     "factory can't change once set.");
101         }
102         this.factory = factory;
103     }
104 
105     /**
106      * Returns the default {@link ChannelPipeline} which is cloned when a new
107      * {@link Channel} is created.  {@link Bootstrap} creates a new pipeline
108      * which has the same entries with the returned pipeline for a new
109      * {@link Channel}.
110      * <p>
111      * Please note that this method is a convenience method that works only
112      * when <b>1)</b> you create only one channel from this bootstrap (e.g.
113      * one-time client-side or connectionless channel) or <b>2)</b> all handlers
114      * in the pipeline is stateless.  You have to use
115      * {@link #setPipelineFactory(ChannelPipelineFactory)} if <b>1)</b> your
116      * pipeline contains a stateful {@link ChannelHandler} and <b>2)</b> one or
117      * more channels are going to be created by this bootstrap (e.g. server-side
118      * channels).
119      *
120      * @return the default {@link ChannelPipeline}
121      *
122      * @throws IllegalStateException
123      *         if {@link #setPipelineFactory(ChannelPipelineFactory)} was
124      *         called by a user last time.
125      */
126     public ChannelPipeline getPipeline() {
127         ChannelPipeline pipeline = this.pipeline;
128         if (pipeline == null) {
129             throw new IllegalStateException(
130                     "getPipeline() cannot be called " +
131                     "if setPipelineFactory() was called.");
132         }
133         return pipeline;
134     }
135 
136     /**
137      * Sets the default {@link ChannelPipeline} which is cloned when a new
138      * {@link Channel} is created.  {@link Bootstrap} creates a new pipeline
139      * which has the same entries with the specified pipeline for a new channel.
140      * <p>
141      * Calling this method also sets the {@code pipelineFactory} property to an
142      * internal {@link ChannelPipelineFactory} implementation which returns
143      * a shallow copy of the specified pipeline.
144      * <p>
145      * Please note that this method is a convenience method that works only
146      * when <b>1)</b> you create only one channel from this bootstrap (e.g.
147      * one-time client-side or connectionless channel) or <b>2)</b> all handlers
148      * in the pipeline is stateless.  You have to use
149      * {@link #setPipelineFactory(ChannelPipelineFactory)} if <b>1)</b> your
150      * pipeline contains a stateful {@link ChannelHandler} and <b>2)</b> one or
151      * more channels are going to be created by this bootstrap (e.g. server-side
152      * channels).
153      */
154     public void setPipeline(ChannelPipeline pipeline) {
155         if (pipeline == null) {
156             throw new NullPointerException("pipeline");
157         }
158         this.pipeline = pipeline;
159         pipelineFactory = pipelineFactory(pipeline);
160     }
161 
162     /**
163      * Dependency injection friendly convenience method for
164      * {@link #getPipeline()} which returns the default pipeline of this
165      * bootstrap as an ordered map.
166      * <p>
167      * Please note that this method is a convenience method that works only
168      * when <b>1)</b> you create only one channel from this bootstrap (e.g.
169      * one-time client-side or connectionless channel) or <b>2)</b> all handlers
170      * in the pipeline is stateless.  You have to use
171      * {@link #setPipelineFactory(ChannelPipelineFactory)} if <b>1)</b> your
172      * pipeline contains a stateful {@link ChannelHandler} and <b>2)</b> one or
173      * more channels are going to be created by this bootstrap (e.g. server-side
174      * channels).
175      *
176      * @throws IllegalStateException
177      *         if {@link #setPipelineFactory(ChannelPipelineFactory)} was
178      *         called by a user last time.
179      */
180     public Map<String, ChannelHandler> getPipelineAsMap() {
181         ChannelPipeline pipeline = this.pipeline;
182         if (pipeline == null) {
183             throw new IllegalStateException("pipelineFactory in use");
184         }
185         return pipeline.toMap();
186     }
187 
188     /**
189      * Dependency injection friendly convenience method for
190      * {@link #setPipeline(ChannelPipeline)} which sets the default pipeline of
191      * this bootstrap from an ordered map.
192      * <p>
193      * Please note that this method is a convenience method that works only
194      * when <b>1)</b> you create only one channel from this bootstrap (e.g.
195      * one-time client-side or connectionless channel) or <b>2)</b> all handlers
196      * in the pipeline is stateless.  You have to use
197      * {@link #setPipelineFactory(ChannelPipelineFactory)} if <b>1)</b> your
198      * pipeline contains a stateful {@link ChannelHandler} and <b>2)</b> one or
199      * more channels are going to be created by this bootstrap (e.g. server-side
200      * channels).
201      *
202      * @throws IllegalArgumentException
203      *         if the specified map is not an ordered map
204      */
205     public void setPipelineAsMap(Map<String, ChannelHandler> pipelineMap) {
206         if (pipelineMap == null) {
207             throw new NullPointerException("pipelineMap");
208         }
209 
210         if (!isOrderedMap(pipelineMap)) {
211             throw new IllegalArgumentException(
212                     "pipelineMap is not an ordered map. " +
213                     "Please use " +
214                     LinkedHashMap.class.getName() + ".");
215         }
216 
217         ChannelPipeline pipeline = pipeline();
218         for (Map.Entry<String, ChannelHandler> e: pipelineMap.entrySet()) {
219             pipeline.addLast(e.getKey(), e.getValue());
220         }
221 
222         setPipeline(pipeline);
223     }
224 
225     /**
226      * Returns the {@link ChannelPipelineFactory} which creates a new
227      * {@link ChannelPipeline} for each new {@link Channel}.
228      *
229      * @see #getPipeline()
230      */
231     public ChannelPipelineFactory getPipelineFactory() {
232         return pipelineFactory;
233     }
234 
235     /**
236      * Sets the {@link ChannelPipelineFactory} which creates a new
237      * {@link ChannelPipeline} for each new {@link Channel}.  Calling this
238      * method invalidates the current {@code pipeline} property of this
239      * bootstrap.  Subsequent {@link #getPipeline()} and {@link #getPipelineAsMap()}
240      * calls will raise {@link IllegalStateException}.
241      *
242      * @see #setPipeline(ChannelPipeline)
243      * @see #setPipelineAsMap(Map)
244      */
245     public void setPipelineFactory(ChannelPipelineFactory pipelineFactory) {
246         if (pipelineFactory == null) {
247             throw new NullPointerException("pipelineFactory");
248         }
249         pipeline = null;
250         this.pipelineFactory = pipelineFactory;
251     }
252 
253     /**
254      * Returns the options which configures a new {@link Channel} and its
255      * child {@link Channel}s.  The names of the child {@link Channel} options
256      * are prepended with {@code "child."} (e.g. {@code "child.keepAlive"}).
257      */
258     public Map<String, Object> getOptions() {
259         return new TreeMap<String, Object>(options);
260     }
261 
262     /**
263      * Sets the options which configures a new {@link Channel} and its child
264      * {@link Channel}s.  To set the options of a child {@link Channel}, prepend
265      * {@code "child."} to the option name (e.g. {@code "child.keepAlive"}).
266      */
267     public void setOptions(Map<String, Object> options) {
268         if (options == null) {
269             throw new NullPointerException("options");
270         }
271         this.options = new HashMap<String, Object>(options);
272     }
273 
274     /**
275      * Returns the value of the option with the specified key.  To retrieve
276      * the option value of a child {@link Channel}, prepend {@code "child."}
277      * to the option name (e.g. {@code "child.keepAlive"}).
278      *
279      * @param key  the option name
280      *
281      * @return the option value if the option is found.
282      *         {@code null} otherwise.
283      */
284     public Object getOption(String key) {
285         if (key == null) {
286             throw new NullPointerException("key");
287         }
288         return options.get(key);
289     }
290 
291     /**
292      * Sets an option with the specified key and value.  If there's already
293      * an option with the same key, it is replaced with the new value.  If the
294      * specified value is {@code null}, an existing option with the specified
295      * key is removed.  To set the option value of a child {@link Channel},
296      * prepend {@code "child."} to the option name (e.g. {@code "child.keepAlive"}).
297      *
298      * @param key    the option name
299      * @param value  the option value
300      */
301     public void setOption(String key, Object value) {
302         if (key == null) {
303             throw new NullPointerException("key");
304         }
305         if (value == null) {
306             options.remove(key);
307         } else {
308             options.put(key, value);
309         }
310     }
311 
312     /**
313      * This method simply delegates the call to
314      * {@link ChannelFactory#releaseExternalResources()}.
315      */
316     public void releaseExternalResources() {
317         ChannelFactory factory = this.factory;
318         if (factory != null) {
319             factory.releaseExternalResources();
320         }
321     }
322 
323     /**
324      * Returns {@code true} if and only if the specified {@code map} is an
325      * ordered map, like {@link LinkedHashMap} is.
326      */
327     @SuppressWarnings({ "unchecked", "rawtypes" })
328     static boolean isOrderedMap(Map<?, ?> map) {
329         Class<?> mapType = map.getClass();
330         if (LinkedHashMap.class.isAssignableFrom(mapType)) {
331             // LinkedHashMap is an ordered map.
332             return true;
333         }
334 
335         // Not a LinkedHashMap - start autodetection.
336 
337         // Detect Apache Commons Collections OrderedMap implementations.
338         Class<?> type = mapType;
339         while (type != null) {
340             for (Class<?> i: type.getInterfaces()) {
341                 if (i.getName().endsWith("OrderedMap")) {
342                     // Seems like it's an ordered map - guessed from that
343                     // it implements OrderedMap interface.
344                     return true;
345                 }
346             }
347             type = type.getSuperclass();
348         }
349 
350         // Does not implement OrderedMap interface.  As a last resort, try to
351         // create a new instance and test if the insertion order is maintained.
352         Map newMap;
353         try {
354             newMap = (Map) mapType.newInstance();
355         } catch (Exception e) {
356             // No default constructor - cannot proceed anymore.
357             return false;
358         }
359 
360         // Run some tests.
361         List<String> expectedKeys = new ArrayList<String>();
362         String dummyValue = "dummyValue";
363         for (short element: ORDER_TEST_SAMPLES) {
364             String key = String.valueOf(element);
365             newMap.put(key, dummyValue);
366             expectedKeys.add(key);
367 
368             Iterator<String> it = expectedKeys.iterator();
369             for (Object actualKey: newMap.keySet()) {
370                 if (!it.next().equals(actualKey)) {
371                     // Did not pass the test.
372                     return false;
373                 }
374             }
375         }
376 
377         // The specified map passed the insertion order test.
378         return true;
379     }
380 
381     private static final short[] ORDER_TEST_SAMPLES = {
382         682, 807, 637, 358, 570, 828, 407, 319,
383         105,  41, 563, 544, 518, 298, 418,  50,
384         156, 769, 984, 503, 191, 578, 309, 710,
385         327, 720, 591, 939, 374, 707,  43, 463,
386         227, 174,  30, 531, 135, 930, 190, 823,
387         925, 835, 328, 239, 415, 500, 144, 460,
388          83, 774, 921,   4,  95, 468, 687, 493,
389         991, 436, 245, 742, 149, 821, 142, 782,
390         297, 918, 917, 424, 978, 992,  79, 906,
391         535, 515, 850,  80, 125, 378, 307, 883,
392         836, 160,  27, 630, 668, 226, 560, 698,
393         467, 829, 476, 163, 977, 367, 325, 184,
394         204, 312, 486,  53, 179, 592, 252, 750,
395         893, 517, 937, 124, 148, 719, 973, 566,
396         405, 449, 452, 777, 349, 761, 167, 783,
397         220, 802, 117, 604, 216, 363, 120, 621,
398         219, 182, 817, 244, 438, 465, 934, 888,
399         628, 209, 631,  17, 870, 679, 826, 945,
400         680, 848, 974, 573, 626, 865, 109, 317,
401          91, 494, 965, 473, 725, 388, 302, 936,
402         660, 150, 122, 949, 295, 392,  63, 634,
403         772, 143, 990, 895, 538,  59, 541,  32,
404         669, 321, 811, 756,  82, 955, 953, 636,
405         390, 162, 688, 444,  70, 590, 183, 745,
406         543, 666, 951, 642, 747, 765,  98, 469,
407         884, 929, 178, 721, 994, 840, 353, 726,
408         940, 759, 624, 919, 667, 629, 272, 979,
409         326, 608, 453,  11, 322, 347, 647, 354,
410         381, 746, 472, 890, 249, 536, 733, 404,
411         170, 959,  34, 899, 195, 651, 140, 856,
412         201, 237,  51, 933, 268, 849, 294, 115,
413         157,  14, 854, 373, 186, 872,  71, 523,
414         931, 952, 655, 561, 607, 862, 554, 661,
415         313, 909, 511, 752, 986, 311, 287, 775,
416         505, 878, 422, 103, 299, 119, 107, 344,
417         487, 776, 445, 218, 549, 697, 454,   6,
418         462, 455,  52, 481, 594, 126, 112,  66,
419         877, 172, 153, 912, 834, 741, 610, 915,
420         964, 831, 575, 714, 250, 461, 814, 913,
421         369, 542, 882, 851, 427, 838, 867, 507,
422         434, 569,  20, 950, 792, 605, 798, 962,
423         923, 258, 972, 762, 809, 843, 674, 448,
424         280, 495, 285, 822, 283, 147, 451, 993,
425         794, 982, 748, 189, 274,  96,  73, 810,
426         401, 261, 277, 346, 527, 645, 601, 868,
427         248, 879, 371, 428, 559, 278, 265,  62,
428         225, 853, 483, 771,   9,   8, 339, 653,
429         263,  28, 477, 995, 208, 880, 292, 480,
430         516, 457, 286, 897,  21, 852, 971, 658,
431         623, 528, 316, 471, 860, 306, 638, 711,
432         875, 671, 108, 158, 646,  24, 257, 724,
433         193, 341, 902, 599, 565, 334, 506, 684,
434         960, 780, 429, 801, 910, 308, 383, 901,
435         489,  81, 512, 164, 755, 514, 723, 141,
436         296, 958, 686,  15, 799, 579, 598, 558,
437         414,  64, 420, 730, 256, 131,  45, 129,
438         259, 338, 999, 175, 740, 790, 324, 985,
439         896, 482, 841, 606, 377, 111, 372, 699,
440         988, 233, 243, 203, 781, 969, 903, 662,
441         632, 301,  44, 981,  36, 412, 946, 816,
442         284, 447, 214, 672, 758, 954, 804,   2,
443         928, 886, 421, 596, 574,  16, 892,  68,
444         546, 522, 490, 873, 656, 696, 864, 130,
445          40, 393, 926, 394, 932, 876, 664, 293,
446         154, 916,  55, 196, 842, 498, 177, 948,
447         540, 127, 271, 113, 844, 576, 132, 943,
448          12, 123, 291,  31, 212, 529, 547, 171,
449         582, 609, 793, 830, 221, 440, 568, 118,
450         406, 194, 827, 360, 622, 389, 800, 571,
451         213, 262, 403, 408, 881, 289, 635, 967,
452         432, 376, 649, 832, 857, 717, 145, 510,
453         159, 980, 683, 580, 484, 379, 246,  88,
454         567, 320, 643,   7, 924, 397,  10, 787,
455         845, 779, 670, 716,  19, 600, 382,   0,
456         210, 665, 228,  97, 266,  90, 304, 456,
457         180, 152, 425, 310, 768, 223, 702, 997,
458         577, 663, 290, 537, 416, 426, 914, 691,
459          23, 281, 497, 508,  48, 681, 581, 728,
460          99, 795, 530, 871, 957, 889, 206, 813,
461         839, 709, 805, 253, 151, 613,  65, 654,
462          93, 639, 784, 891, 352,  67, 430, 754,
463          76, 187, 443, 676, 362, 961, 874, 330,
464         331, 384,  85, 217, 855, 818, 738, 361,
465         314,   3, 615, 520, 355, 920, 689,  22,
466         188,  49, 904, 935, 136, 475, 693, 749,
467         519, 812, 100, 207, 963, 364, 464, 572,
468         731, 230, 833, 385, 499, 545, 273, 232,
469         398, 478, 975, 564, 399, 504,  35, 562,
470         938, 211,  26, 337,  54, 614, 586, 433,
471         450, 763, 238, 305, 941, 370, 885, 837,
472         234, 110, 137, 395, 368, 695, 342, 907,
473         396, 474, 176, 737, 796, 446,  37, 894,
474         727, 648, 431,   1, 366, 525, 553, 704,
475         329, 627, 479,  33, 492, 260, 241,  86,
476         185, 491, 966, 247,  13, 587, 602, 409,
477         335, 650, 235, 611, 470, 442, 597, 254,
478         343, 539, 146, 585, 593, 641, 770,  94,
479         976, 705, 181, 255, 315, 718, 526, 987,
480         692, 983, 595, 898, 282, 133, 439, 633,
481         534, 861, 269, 619, 677, 502, 375, 224,
482         806, 869, 417, 584, 612, 803,  58,  84,
483         788, 797,  38, 700, 751, 603, 652,  57,
484         240, 947, 350, 270, 333, 116, 736,  69,
485          74, 104, 767, 318, 735, 859, 357, 555,
486         411, 267, 712, 675, 532, 825, 496, 927,
487         942, 102,  46, 192, 114, 744, 138, 998,
488          72, 617, 134, 846, 166,  77, 900,   5,
489         303, 387, 400,  47, 729, 922, 222, 197,
490         351, 509, 524, 165, 485, 300, 944, 380,
491         625, 778, 685,  29, 589, 766, 161, 391,
492         423,  42, 734, 552, 215, 824, 908, 229,
493          89, 251, 199, 616,  78, 644, 242, 722,
494          25, 437, 732, 956, 275, 200, 970, 753,
495         791, 336, 556, 847, 703, 236, 715,  75,
496         863, 713, 785, 911, 786, 620, 551, 413,
497          39, 739, 820, 808, 764, 701, 819, 173,
498         989, 345, 690, 459,  60, 106, 887, 996,
499         365, 673, 968, 513,  18, 419, 550, 588,
500         435, 264, 789, 340, 659, 466, 356, 288,
501          56, 708, 557, 488, 760, 332, 402, 168,
502         202, 521, 757, 205, 706, 441, 773, 231,
503         583, 386, 678, 618, 815, 279,  87, 533,
504          61, 548,  92, 169, 694, 905, 198, 121,
505         410, 139, 657, 640, 743, 128, 458, 866,
506         501, 348, 155, 276, 101, 858, 323, 359,
507     };
508 }