@SuppressWarnings("unchecked")
  public void execute() throws Exception {
    // Read in the zone
    List<Record> records = ZoneUtils.readZoneFile(state.inputfile, null);
    if (records == null || records.size() == 0) {
      System.err.println("error: empty RRset file");
      state.usage();
    }
    // Construct the RRset. Complain if the records in the input file
    // consist of more than one RRset.
    RRset rrset = null;

    for (Record r : records) {
      // skip RRSIGs
      if (r.getType() == Type.RRSIG || r.getType() == Type.SIG) {
        continue;
      }

      // Handle the first record.
      if (rrset == null) {
        rrset = new RRset();
        rrset.addRR(r);
        continue;
      }
      // Ensure that the remaining records all belong to the same rrset.
      if (rrset.getName().equals(r.getName())
          && rrset.getType() == r.getType()
          && rrset.getDClass() == r.getDClass()) {
        rrset.addRR(r);
      } else {
        System.err.println("Records do not all belong to the same RRset.");
        state.usage();
      }
    }

    if (rrset.size() == 0) {
      System.err.println("No records found in inputfile.");
      state.usage();
    }

    // Load the key pairs.

    if (state.keyFiles.length == 0) {
      System.err.println("error: at least one keyfile must be specified");
      state.usage();
    }

    List<DnsKeyPair> keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);

    // Make sure that all the keypairs have the same name.
    // This will be used as the zone name, too.

    Name keysetName = null;
    for (DnsKeyPair pair : keypairs) {
      if (keysetName == null) {
        keysetName = pair.getDNSKEYName();
        continue;
      }
      if (!pair.getDNSKEYName().equals(keysetName)) {
        System.err.println("Keys do not all have the same name.");
        state.usage();
      }
    }

    // default the output file, if not set.
    if (state.outputfile == null && !state.inputfile.equals("-")) {
      state.outputfile = state.inputfile + ".signed";
    }

    JCEDnsSecSigner signer = new JCEDnsSecSigner();

    List<RRSIGRecord> sigs = signer.signRRset(rrset, keypairs, state.start, state.expire);
    for (RRSIGRecord s : sigs) {
      rrset.addRR(s);
    }

    // write out the signed RRset
    List<Record> signed_records = new ArrayList<Record>();
    for (Iterator<Record> i = rrset.rrs(); i.hasNext(); ) {
      signed_records.add(i.next());
    }
    for (Iterator<Record> i = rrset.sigs(); i.hasNext(); ) {
      signed_records.add(i.next());
    }

    // write out the signed zone
    ZoneUtils.writeZoneFile(signed_records, state.outputfile);

    if (state.verifySigs) {
      log.fine("verifying generated signatures");
      boolean res = verifySigs(keysetName, signed_records, keypairs);

      if (res) {
        System.out.println("Generated signatures verified");
        // log.info("Generated signatures verified");
      } else {
        System.out.println("Generated signatures did not verify.");
        // log.warn("Generated signatures did not verify.");
      }
    }
  }
  /**
   * Processes all DNS CERT requests.
   *
   * @param name The record name. In many cases this a email address.
   * @return Returns a set of record responses to the request.
   * @throws DNSException
   */
  @SuppressWarnings("unused")
  protected RRset processCERTRecordRequest(String name) throws DNSException {
    if (name.endsWith(".")) name = name.substring(0, name.length() - 1);

    Certificate[] certs;

    // use the certificate configuration service
    try {
      certs = proxy.getCertificatesForOwner(name, null);
    } catch (Exception e) {
      throw new DNSException(
          DNSError.newError(Rcode.SERVFAIL),
          "DNS service proxy call for certificates failed: " + e.getMessage(),
          e);
    }

    if (certs == null || certs.length == 0) {
      // unless the call above was for an org level cert, it will probably always fail because the
      // "name" parameter has had all instances of "@" replaced with ".".  The certificate service
      // stores owners using "@".
      // This is horrible, but try hitting the cert service replacing each "." with "@" one by one.
      // Start at the beginning of the address because this is more than likely where the "@"
      // character
      // will be.
      int previousIndex = 0;
      int replaceIndex = 0;
      while ((replaceIndex = name.indexOf(".", previousIndex)) > -1) {
        char[] chars = name.toCharArray();
        chars[replaceIndex] = '@';
        try {
          certs = proxy.getCertificatesForOwner(String.copyValueOf(chars), null);
        } catch (Exception e) {
          throw new DNSException(
              DNSError.newError(Rcode.SERVFAIL),
              "DNS service proxy call for certificates failed: " + e.getMessage(),
              e);
        }
        if (certs != null && certs.length > 0) break;

        if (replaceIndex >= (name.length() - 1)) break;

        previousIndex = replaceIndex + 1;
      }
    }

    if (certs == null || certs.length == 0) return null;

    if (!name.endsWith(".")) name += ".";

    RRset retVal = new RRset();
    try {
      for (Certificate cert : certs) {
        int certRecordType = CERTRecord.PKIX;
        byte[] retData = null;

        X509Certificate xCert = null;
        try {
          // need to convert to cert container because this might be
          // a certificate with wrapped private key data
          final CertUtils.CertContainer cont = CertUtils.toCertContainer(cert.getData());
          xCert = cont.getCert();
          // check if this is a compliant certificate with the configured policy... if not, move on
          if (!isCertCompliantWithPolicy(xCert)) continue;

          retData = xCert.getEncoded();
        } catch (CertificateConversionException e) {
          // probably not a Certificate... might be a URL
        }

        if (xCert == null) {
          // see if it's a URL
          try {
            retData = cert.getData();
            URL url = new URL(new String(retData));
            certRecordType = CERTRecord.URI;
          } catch (Exception e) {
            throw new DNSException(
                DNSError.newError(Rcode.SERVFAIL),
                "Failure while parsing CERT record data: " + e.getMessage(),
                e);
          }
        }

        int keyTag = 0;
        int alg = 0;
        if (xCert != null && xCert.getPublicKey() instanceof RSAKey) {
          RSAKey key = (RSAKey) xCert.getPublicKey();
          byte[] modulus = key.getModulus().toByteArray();

          keyTag = (modulus[modulus.length - 2] << 8) & 0xFF00;

          keyTag |= modulus[modulus.length - 1] & 0xFF;
          alg = 5;
        }

        CERTRecord rec =
            new CERTRecord(
                Name.fromString(name),
                DClass.IN,
                86400L,
                certRecordType,
                keyTag,
                alg /*public key alg, RFC 4034*/,
                retData);

        retVal.addRR(rec);
      }
    } catch (Exception e) {
      throw new DNSException(
          DNSError.newError(Rcode.SERVFAIL),
          "Failure while parsing CERT record data: " + e.getMessage(),
          e);
    }

    // because of policy filtering, it's possible that we could have filtered out every cert
    // resulting in an empty RR set
    return (retVal.size() == 0) ? null : retVal;
  }