private Map<String, byte[]> digestJar(final File file) throws IOException {
    Map<String, byte[]> digest = CACHE.get(file);
    if (digest == null) {
      digest = new HashMap<String, byte[]>();
      JarFile jar = new JarFile(file);
      try {
        for (Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements(); ) {
          JarEntry entry = entries.nextElement();
          String path = entry.getName();
          if (path.endsWith(".class")) {
            String type = toJavaType(path);
            try {
              digest.put(type, digester.digest(ClassFileReader.read(jar, path)));
            } catch (ClassFormatException e) {
              // the class file is old for sure, according to jdt
            }
          }
        }
      } finally {
        jar.close();
      }
      CACHE.put(file, digest);
    }

    return digest;
  }
  private Map<String, byte[]> digestDirectory(final File directory) throws IOException {
    Map<String, byte[]> digest = CACHE.get(directory);
    if (digest == null) {
      digest = new HashMap<String, byte[]>();
      DirectoryScanner scanner = new DirectoryScanner();
      scanner.setBasedir(directory);
      scanner.setIncludes(new String[] {"**/*.class"});
      scanner.scan();
      for (String path : scanner.getIncludedFiles()) {
        String type = toJavaType(path);
        try {
          digest.put(type, digester.digest(ClassFileReader.read(new File(directory, path))));
        } catch (ClassFormatException e) {
          // as far as jdt is concerned, the type does not exist
        }
      }
      CACHE.put(directory, digest);
    }

    return digest;
  }