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