/**
   * Examines the channel buffer and attempts to match the protocol of the request and invoke the
   * matching {@link ProtocolInitiator}.
   *
   * @param ctx The channel handler context
   * @param channel The channel
   * @param bufferx The message buffer
   * @param e The channel event
   * @return The channel buffer to send upstream, or null if we need more bytes
   */
  protected ChannelBuffer protocolSwitch(
      ChannelHandlerContext ctx, Channel channel, ChannelBuffer bufferx, ChannelEvent e) {
    ChannelBuffer cb = preSwitchedBuffer.get(channel);
    if (cb != null) {
      cb.writeBytes(bufferx);
      cb.resetReaderIndex();
    } else {
      cb = bufferx;
    }
    // this guy will be set with a matching initiator
    ProtocolInitiator selectedInitiator = null;
    // this guy will be set to false if at least 1 initiator had insufficient bytes to match
    boolean sufficientBytes = true;
    // ths guy has the total bytes available in the buffer
    final int bytesAvailable = cb.readableBytes();

    for (ProtocolInitiator pi : initiators.values()) {
      if (pi.requiredBytes() > bytesAvailable) {
        sufficientBytes = false;
      } else {
        if (pi.match(cb)) {
          selectedInitiator = pi;
          break;
        }
      }
    }

    if (selectedInitiator == null) {
      // we did not get a match
      if (!sufficientBytes) {
        // ok, we did not have enough bytes
        DynamicChannelBuffer dcb = preSwitchedBuffer.get(channel);
        if (dcb == null) {
          dcb = new DynamicChannelBuffer(cb.order(), 1024, chanelBufferFactory);
          preSwitchedBuffer.set(channel, dcb);
        }
        dcb.writeBytes(cb);
        dcb.resetReaderIndex();
        return null;
      }
      // darn, we have enough bytes for any of the inits,
      // but none matched
      throw new RuntimeException("Failed to match any protocol initiator");
    }
    preSwitchedBuffer.remove(channel);
    // we matched on an initiator, so have it modify the pipeline
    selectedInitiator.modifyPipeline(ctx, channel, cb);
    return cb;

    // if we get here, it means we did not find a protocol match
    // so pass to the default protocol initiator.
  }
 /**
  * Registers a new protocol initiator
  *
  * @param initiator the protocol initiator to register
  */
 public void registerProtocolInitiator(ProtocolInitiator initiator) {
   if (initiator == null) throw new IllegalArgumentException("The passed initiator was null");
   String key = initiator.getProtocol();
   if (key == null || key.trim().isEmpty())
     throw new RuntimeException(
         "The passed initiator had a null or empty protocol [" + initiator + "]");
   key = key.trim().toLowerCase();
   if (!initiators.containsKey(key)) {
     synchronized (initiators) {
       if (!initiators.containsKey(key)) {
         initiators.put(key, initiator);
         return;
       }
     }
   }
   throw new RuntimeException(
       "An initiator for protocol [" + key + "] has already been registered");
 }