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