/**
   * method to extract the next monitor entry from the instrumentation memory. assumes that
   * nextEntry is the offset into the byte array at which to start the search for the next entry.
   * method leaves next entry pointing to the next entry or to the end of data.
   */
  protected Monitor getNextMonitorEntry() throws MonitorException {
    Monitor monitor = null;

    // entries are always 4 byte aligned.
    if ((nextEntry % 4) != 0) {
      throw new MonitorStructureException("Entry index not properly aligned: " + nextEntry);
    }

    // protect against a corrupted shared memory region.
    if ((nextEntry < 0) || (nextEntry > buffer.limit())) {
      throw new MonitorStructureException(
          "Entry index out of bounds: nextEntry = " + nextEntry + ", limit = " + buffer.limit());
    }

    // check for the end of the buffer
    if (nextEntry == buffer.limit()) {
      lognl("getNextMonitorEntry():" + " nextEntry == buffer.limit(): returning");
      return null;
    }

    buffer.position(nextEntry);

    int entryStart = buffer.position();
    int entryLength = buffer.getInt();

    // check for valid entry length
    if ((entryLength < 0) || (entryLength > buffer.limit())) {
      throw new MonitorStructureException("Invalid entry length: entryLength = " + entryLength);
    }

    // check if last entry occurs before the eof.
    if ((entryStart + entryLength) > buffer.limit()) {
      throw new MonitorStructureException(
          "Entry extends beyond end of buffer: "
              + " entryStart = "
              + entryStart
              + " entryLength = "
              + entryLength
              + " buffer limit = "
              + buffer.limit());
    }

    if (entryLength == 0) {
      // end of data
      return null;
    }

    int nameLength = buffer.getInt();
    int vectorLength = buffer.getInt();
    byte dataType = buffer.get();
    byte flags = buffer.get();
    Units u = Units.toUnits(buffer.get());
    Variability v = Variability.toVariability(buffer.get());
    boolean supported = (flags & 0x01) != 0;

    // defend against corrupt entries
    if ((nameLength <= 0) || (nameLength > entryLength)) {
      throw new MonitorStructureException("Invalid Monitor name length: " + nameLength);
    }

    if ((vectorLength < 0) || (vectorLength > entryLength)) {
      throw new MonitorStructureException("Invalid Monitor vector length: " + vectorLength);
    }

    // read in the perfData item name, casting bytes to chars. skip the
    // null terminator
    //
    byte[] nameBytes = new byte[nameLength - 1];
    for (int i = 0; i < nameLength - 1; i++) {
      nameBytes[i] = buffer.get();
    }

    // convert name into a String
    String name = new String(nameBytes, 0, nameLength - 1);

    if (v == Variability.INVALID) {
      throw new MonitorDataException(
          "Invalid variability attribute:" + " entry index = " + perfDataItem + " name = " + name);
    }
    if (u == Units.INVALID) {
      throw new MonitorDataException(
          "Invalid units attribute: " + " entry index = " + perfDataItem + " name = " + name);
    }

    int offset;
    if (vectorLength == 0) {
      // scalar Types
      if (dataType == BasicType.LONG.intValue()) {
        offset = entryStart + entryLength - 8; /* 8 = sizeof(long) */
        buffer.position(offset);
        LongBuffer lb = buffer.asLongBuffer();
        lb.limit(1);
        monitor = new PerfLongMonitor(name, u, v, supported, lb);
        perfDataItem++;
      } else {
        // bad data types.
        throw new MonitorTypeException(
            "Invalid Monitor type:"
                + " entry index = "
                + perfDataItem
                + " name = "
                + name
                + " type = "
                + dataType);
      }
    } else {
      // vector types
      if (dataType == BasicType.BYTE.intValue()) {
        if (u != Units.STRING) {
          // only byte arrays of type STRING are currently supported
          throw new MonitorTypeException(
              "Invalid Monitor type:"
                  + " entry index = "
                  + perfDataItem
                  + " name = "
                  + name
                  + " type = "
                  + dataType);
        }

        offset = entryStart + PERFDATA_NAME_OFFSET + nameLength;
        buffer.position(offset);
        ByteBuffer bb = buffer.slice();
        bb.limit(vectorLength);
        bb.position(0);

        if (v == Variability.CONSTANT) {
          monitor = new PerfStringConstantMonitor(name, supported, bb);
        } else if (v == Variability.VARIABLE) {
          monitor = new PerfStringVariableMonitor(name, supported, bb, vectorLength - 1);
        } else {
          // Monotonically increasing byte arrays are not supported
          throw new MonitorDataException(
              "Invalid variability attribute:"
                  + " entry index = "
                  + perfDataItem
                  + " name = "
                  + name
                  + " variability = "
                  + v);
        }
        perfDataItem++;
      } else {
        // bad data types.
        throw new MonitorTypeException(
            "Invalid Monitor type:"
                + " entry index = "
                + perfDataItem
                + " name = "
                + name
                + " type = "
                + dataType);
      }
    }

    // setup index to next entry for next iteration of the loop.
    nextEntry = entryStart + entryLength;
    return monitor;
  }