/** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public Message get(Message request) throws DNSException {
    LOGGER.trace("get(Message) Entered");
    /* for testing time out cases
    try
    {
    	Thread.sleep(1000000);
    }
    catch (Exception e)
    {

    }
       */
    if (request == null) throw new DNSException(DNSError.newError(Rcode.FORMERR));

    Header header = request.getHeader();
    if (header.getFlag(Flags.QR) || header.getRcode() != Rcode.NOERROR)
      throw new DNSException(DNSError.newError(Rcode.FORMERR));

    if (header.getOpcode() != Opcode.QUERY) throw new DNSException(DNSError.newError(Rcode.NOTIMP));

    Record question = request.getQuestion();

    if (question == null || question.getDClass() != DClass.IN) {
      throw new DNSException(DNSError.newError(Rcode.NOTIMP));
    }

    Record queryRecord = request.getQuestion();
    Name name = queryRecord.getName();
    int type = queryRecord.getType();

    if (LOGGER.isDebugEnabled()) {
      StringBuilder builder = new StringBuilder("Recieved Query Request:");
      builder.append("\r\n\tName: " + name.toString());
      builder.append("\r\n\tType: " + type);
      builder.append("\r\n\tDClass: " + queryRecord.getDClass());
      LOGGER.debug(builder.toString());
    }

    Collection<Record> lookupRecords = null;
    switch (question.getType()) {
      case Type.A:
      case Type.MX:
      case Type.SOA:
      case Type.SRV:
      case Type.NS:
      case Type.CNAME:
        {
          try {
            final RRset set = processGenericRecordRequest(name.toString(), type);

            if (set != null) {
              lookupRecords = new ArrayList<Record>();
              Iterator<Record> iter = set.rrs();
              while (iter.hasNext()) lookupRecords.add(iter.next());
            }

          } catch (Exception e) {
            throw new DNSException(
                DNSError.newError(Rcode.SERVFAIL),
                "DNS service proxy call failed: " + e.getMessage(),
                e);
          }
          break;
        }
      case Type.CERT:
        {
          final RRset set = processCERTRecordRequest(name.toString());

          if (set != null) {
            lookupRecords = new ArrayList<Record>();
            Iterator<Record> iter = set.rrs();
            while (iter.hasNext()) lookupRecords.add(iter.next());
          }

          break;
        }
      case Type.ANY:
        {
          Collection<Record> genRecs = processGenericANYRecordRequest(name.toString());
          RRset certRecs = processCERTRecordRequest(name.toString());

          if (genRecs != null || certRecs != null) {
            lookupRecords = new ArrayList<Record>();
            if (genRecs != null) lookupRecords.addAll(genRecs);

            if (certRecs != null) {
              Iterator<Record> iter = certRecs.rrs();
              while (iter.hasNext()) lookupRecords.add(iter.next());
            }
          }

          break;
        }
      default:
        {
          LOGGER.debug("Query Type " + type + " not implemented");
          throw new DNSException(
              DNSError.newError(Rcode.NOTIMP), "Query Type " + type + " not implemented");
        }
    }

    if (lookupRecords == null || lookupRecords.size() == 0) {
      LOGGER.debug("No records found.");
      return null;
    }

    final Message response = new Message(request.getHeader().getID());
    response.getHeader().setFlag(Flags.QR);
    if (request.getHeader().getFlag(Flags.RD)) response.getHeader().setFlag(Flags.RD);
    response.addRecord(queryRecord, Section.QUESTION);

    final Iterator<Record> iter = lookupRecords.iterator();
    while (iter.hasNext()) response.addRecord(iter.next(), Section.ANSWER);

    // we are authoritative only
    response.getHeader().setFlag(Flags.AA);
    // look for an SOA record
    final Record soaRecord = checkForSoaRecord(name.toString());
    if (soaRecord != null) response.addRecord(soaRecord, Section.AUTHORITY);

    LOGGER.trace("get(Message) Exit");

    return response;
  }