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 }