code: @Override
      public DescriptorValue calculate(IAtomContainer atomContainer) {
          int hBondDonors = 0;
  
          IAtomContainer ac;
          try {
              ac = (IAtomContainer) atomContainer.clone();
          } catch (CloneNotSupportedException e) {
              return getDummyDescriptorValue(e);
          }
  
          //org.openscience.cdk.interfaces.IAtom[] atoms = ac.getAtoms();
          // iterate over all atoms of this AtomContainer; use label atomloop to allow for labelled continue
          atomloop: for (int atomIndex = 0; atomIndex < ac.getAtomCount(); atomIndex++) {
              IAtom atom = (IAtom) ac.getAtom(atomIndex);
              // checking for O and N atoms where the formal charge is >= 0
              if ((atom.getSymbol().equals("O") || atom.getSymbol().equals("N")) && atom.getFormalCharge() >= 0) {
                  // implicit hydrogens
                  Integer implicitH = atom.getImplicitHydrogenCount();
                  if (implicitH == CDKConstants.UNSET) implicitH = 0;
                  if (implicitH > 0) {
                      hBondDonors++;
                      continue atomloop; // we skip the explicit hydrogens part cause we found implicit hydrogens
                  }
                  // explicit hydrogens
                  java.util.List neighbours = ac.getConnectedAtomsList(atom);
                  for (Object neighbour : neighbours) {
                      if (((IAtom) neighbour).getSymbol().equals("H")) {
                          hBondDonors++;
                          continue atomloop;
                      }
                  }
              }
          }
  
          return new DescriptorValue(getSpecification(), getParameterNames(), getParameters(), new IntegerResult(
                  hBondDonors), getDescriptorNames());
      }
docs: Calculates the number of H bond donors.
  
  @param  atomContainer               AtomContainer
  @return                   number of H bond donors