/**
   * entry method to the TypeCode reader logic
   *
   * @param logger used to log informational/debug information
   * @param in the InputStream from which should be read from
   * @param recursiveTCMap Map that should be used to store the buffer positions of not completely
   *     read in TypeCodes
   * @param repeatedTCMap Map that should be used to store the buffer positions of completely read
   *     in TypeCodes
   */
  public TypeCode readTypeCode(
      Logger logger, CDRInputStream in, Map recursiveTCMap, Map repeatedTCMap) {
    in.mark(0);

    final int kind = in.read_long();
    final int start_pos = in.get_pos() - 4;

    try {
      in.reset();
    } catch (IOException e) {
      assert false;
      throw new RuntimeException("should not happen");
    }

    if (logger.isDebugEnabled()) {
      logger.debug(
          in.getIndentString() + "read TypeCode kind " + kind + " at startposition " + start_pos);
    }

    final TypeCode result = doReadTypeCode(in, recursiveTCMap, repeatedTCMap, kind);

    if (logger.isDebugEnabled()) {
      logger.debug(
          in.getIndentString()
              + "return "
              + result
              + " ("
              + result.getClass().getName()
              + "@"
              + System.identityHashCode(result)
              + ")");
    }

    return result;
  }
  /**
   * Run method. Inherited from runnable, this method is used to stay listening to the socket for
   * new messages.
   */
  @Override
  public void run() {
    // create incomplete table if doesn't exist
    if (incompleteMessages == null) {
      incompleteMessages = new HashMap<String, FragmentedMessage>();
    }

    // allocates a buffer
    byte[] buffer = new byte[packetMaxSize];

    while (connected) {
      try {
        // if the number of messages in incomplete table is greater than a
        // specified threshold we inspect this table to clear incomplete packets
        // collections.
        if (incompleteMessages.size() > incompleteMessagesThreshold) {
          dropIncompleteMessages();
        }

        // creates a new datagram to be read
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        try {
          // wait for the datagram
          socket.receive(packet);
        } catch (SocketTimeoutException ste) {
          continue;
        } catch (InterruptedIOException e) {
          throw new org.omg.CORBA.TRANSIENT("Interrupted I/O: " + e);
        } catch (IOException se) {
          throw to_COMM_FAILURE(se);
        }
        // the packet was received successfully.
        CDRInputStream in = new CDRInputStream(configuration.getORB(), packet.getData());

        // Read the header
        //
        // Manually read in the stream rather than using the generated
        // PacketHeader_1_0Helper
        // as we may need to alter endian half way through.
        org.omg.MIOP.PacketHeader_1_0 header = new org.omg.MIOP.PacketHeader_1_0();
        header.magic = new char[4];
        in.read_char_array(header.magic, 0, 4);

        // Verify the message is MIOP
        if (!MulticastUtil.matchMIOPMagic(header.magic)) {
          // if it isn't a MIOP message I can ignore it
          continue;
        }

        // We know it is MIOP from now on.
        header.hdr_version = in.read_octet();
        header.flags = in.read_octet();

        // Set endian for the stream
        in.setLittleEndian((0x01 & header.flags) != 0);

        header.packet_length = in.read_ushort();
        header.packet_number = in.read_ulong();
        header.number_of_packets = in.read_ulong();
        header.Id = org.omg.MIOP.UniqueIdHelper.read(in);

        int pos = in.get_pos();
        // difference to next MulticastUtil.BOUNDARY (which is an 8 byte boundary)
        int header_padding = MulticastUtil.BOUNDARY - (pos % MulticastUtil.BOUNDARY);
        header_padding = (header_padding == MulticastUtil.BOUNDARY) ? 0 : header_padding;

        // skip header_padding bytes anyway, because if no body is
        // present, nobody will try to read it
        in.skip(header_padding);

        // read the GIOP data
        byte data[] = new byte[header.packet_length];
        if (in.available() < data.length) {
          throw new MARSHAL(
              "Impossible length in MIOP header. Header denotes length of "
                  + header.packet_length
                  + " but only "
                  + in.available()
                  + " is available.");
        }
        in.read_octet_array(data, 0, header.packet_length);

        String messageId = new String(header.Id);
        FragmentedMessage message = incompleteMessages.get(messageId);

        // verify if it's the first message to arrive
        if (message == null) {
          // If this is the first fragment of the message create a  fragmented message
          message = new FragmentedMessage();
          try {
            message.configure(configuration);
          } catch (ConfigurationException e) {
            logger.error("couldn't create a Fragmented message", e);
            throw new IllegalArgumentException("wrong configuration: " + e);
          }
          incompleteMessages.put(messageId, message);
        }

        if (logger.isDebugEnabled()) {
          logger.debug(
              "Received message number "
                  + (header.packet_number + 1)
                  + " out of "
                  + header.number_of_packets
                  + " and adding fragment of size "
                  + data.length);
        }
        message.addFragment(header, data);

        // verify if it's the last message to arrive
        if (message.isComplete()) {
          synchronized (this) {
            incompleteMessages.remove(messageId);
            fullMessages.addLast(message.buildMessage());
            notifyAll();
          }
        }
      } catch (COMM_FAILURE e) {
        if (logger.isDebugEnabled()) {
          logger.debug("Transport to " + connection_info + ": stream closed " + e.getMessage());
        }
        if (connected) {
          close();
        }
      } catch (SystemException e) {
        if (logger.isWarnEnabled()) {
          logger.warn("ServerMIOPConnection caught exception.", e);
        }
      } catch (Throwable e) {
        if (logger.isErrorEnabled()) {
          logger.error("ServerMIOPConnection caught exception.", e);
        }
      }
    }
  }