/** {@inheritDoc} */
  public Document encodeXML() throws InvalidLLRPMessageException {
    try {
      Namespace ns = Namespace.getNamespace("llrp", LLRPConstants.LLRPNAMESPACE);

      Element root = new Element("GET_ACCESSSPECS_RESPONSE", ns);
      //	Element root = new Element("GET_ACCESSSPECS_RESPONSE");
      root.addNamespaceDeclaration(Namespace.getNamespace("llrp", LLRPConstants.LLRPNAMESPACE));

      if (version == null) {
        throw new InvalidLLRPMessageException("Version not set");
      } else {
        root.setAttribute("Version", version.toInteger().toString());
      }

      if (messageID == null) {
        throw new InvalidLLRPMessageException("MessageID not set");
      } else {
        root.setAttribute("MessageID", messageID.toString(10));
      }

      // parameters
      if (lLRPStatus == null) {
        LOGGER.info("lLRPStatus not set");
        throw new MissingParameterException("lLRPStatus not set");
      } else {
        root.addContent(lLRPStatus.encodeXML(lLRPStatus.getClass().getSimpleName(), ns));
      }

      if (accessSpecList == null) {
        LOGGER.info("accessSpecList not set");
      } else {
        for (AccessSpec field : accessSpecList) {
          root.addContent(
              field.encodeXML(
                  field
                      .getClass()
                      .getName()
                      .replaceAll(field.getClass().getPackage().getName() + ".", ""),
                  ns));
        }
      }

      Document doc = new Document(root);

      if (isValidXMLMessage(doc, LLRPConstants.LLRPMESSAGESCHEMAPATH)) {
        return doc;
      } else {
        return null;
      }
    } catch (IllegalArgumentException e) {
      throw new InvalidLLRPMessageException(e.getMessage());
    } catch (MissingParameterException e) {
      throw new InvalidLLRPMessageException(e.getMessage());
    }
  }
  /** {@inheritDoc} */
  protected LLRPBitList encodeBinarySpecific() throws InvalidLLRPMessageException {
    LLRPBitList resultBits = new LLRPBitList();

    if (lLRPStatus == null) {
      // single parameter, may not be null
      LOGGER.warn(" lLRPStatus not set");
      throw new InvalidLLRPMessageException(" lLRPStatus not set");
    } else {
      resultBits.append(lLRPStatus.encodeBinary());
    }

    if (accessSpecList == null) {
      // just warn - it is optional
      LOGGER.info(" accessSpecList not set");
    } else {
      for (AccessSpec field : accessSpecList) {
        resultBits.append(field.encodeBinary());
      }
    }

    return resultBits;
  }
  /** {@inheritDoc} */
  protected void decodeBinarySpecific(LLRPBitList binary) throws InvalidLLRPMessageException {
    int position = 0;
    int tempByteLength;
    int tempLength = 0;
    int count;
    SignedShort type;
    int fieldCount;
    Custom custom;

    // look ahead to see type
    // may be optional or exactly once
    type = null;
    tempByteLength = 0;
    tempLength = 0;

    try {
      // if first bit is one it is a TV Parameter
      if (binary.get(position)) {
        // do not take the first bit as it is always 1
        type = new SignedShort(binary.subList(position + 1, 7));
      } else {
        type = new SignedShort(binary.subList(position + RESERVEDLENGTH, TYPENUMBERLENGTH));
        tempByteLength =
            new UnsignedShort(
                    binary.subList(
                        position + RESERVEDLENGTH + TYPENUMBERLENGTH, UnsignedShort.length()))
                .toShort();
        tempLength = 8 * tempByteLength;
      }
    } catch (IllegalArgumentException le) {
      // if an IllegalArgumentException is thrown, list was not long enough so the parameter is
      // missing
      LOGGER.warn("GET_ACCESSSPECS_RESPONSE misses non optional parameter of type LLRPStatus");
      throw new InvalidLLRPMessageException(
          "GET_ACCESSSPECS_RESPONSE misses non optional parameter of type LLRPStatus");
    }

    if (binary.get(position)) {
      // length can statically be determined for TV Parameters
      tempLength = lLRPStatus.length();
    }

    if ((type != null) && type.equals(LLRPStatus.TYPENUM)) {
      lLRPStatus = new LLRPStatus(binary.subList(position, tempLength));
      position += tempLength;
      LOGGER.debug(" lLRPStatus is instantiated with LLRPStatus with length" + tempLength);
    } else {
      LOGGER.warn("GET_ACCESSSPECS_RESPONSE misses non optional parameter of type LLRPStatus");
      throw new InvalidLLRPMessageException(
          "GET_ACCESSSPECS_RESPONSE misses non optional parameter of type LLRPStatus");
    }

    // list of parameters
    accessSpecList = new LinkedList<AccessSpec>();
    LOGGER.debug("decoding parameter accessSpecList ");

    while (position < binary.length()) {
      // store if one parameter matched
      boolean atLeastOnce = false;

      // look ahead to see type
      // if first bit is one it is a TV Parameter
      if (binary.get(position)) {
        // do not take the first bit as it is always 1
        type = new SignedShort(binary.subList(position + 1, 7));
      } else {
        type = new SignedShort(binary.subList(position + RESERVEDLENGTH, TYPENUMBERLENGTH));
        tempByteLength =
            new UnsignedShort(
                    binary.subList(
                        position + RESERVEDLENGTH + TYPENUMBERLENGTH, UnsignedShort.length()))
                .toShort();
        tempLength = 8 * tempByteLength;
      }

      // add parameter to list if type number matches
      if ((type != null) && type.equals(AccessSpec.TYPENUM)) {
        // if first bit is 1 it is a TV Parameter
        if (binary.get(position)) {
          // length can statically be determined for TV Parameters
          tempLength = AccessSpec.length();
        }

        accessSpecList.add(new AccessSpec(binary.subList(position, tempLength)));
        LOGGER.debug("adding AccessSpec to accessSpecList ");
        atLeastOnce = true;
        position += tempLength;
      }

      if (!atLeastOnce) {
        // no parameter matched therefore we jump out of the loop
        break;
      }
    }

    // if list is still empty no parameter matched
    if (accessSpecList.isEmpty()) {
      LOGGER.info("encoded message does not contain parameter for optional accessSpecList");
    }
  }