public void process(File f) throws Exception {
      if (f.isDirectory()) {
        File[] files =
            f.listFiles(
                new FilenameFilter() {

                  @Override
                  public boolean accept(File dir, String name) {
                    return name.matches(FILE_PATTERN);
                  }
                });
        for (File ff : files) {
          byte[] bindingBytes = Files.toByteArray(ff);
          this.addCurrentBinding(bindingBytes, ff.getName(), "file:" + ff.getAbsolutePath());
        }
      } else {
        String digest = new BigInteger(Files.getDigest(f, Digest.MD5.get())).abs().toString(16);
        CURRENT_PROPS.put(BINDING_CACHE_JAR_PREFIX + f.getName(), digest);
        final JarFile jar = new JarFile(f);
        final List<JarEntry> jarList = Collections.list(jar.entries());
        for (final JarEntry j : jarList) {
          try {
            if (j.getName().matches(FILE_PATTERN)) {
              byte[] bindingBytes = ByteStreams.toByteArray(jar.getInputStream(j));
              String bindingName = j.getName();
              String bindingFullPath = "jar:file:" + f.getAbsolutePath() + "!/" + bindingName;
              this.addCurrentBinding(bindingBytes, bindingName, bindingFullPath);
            } else if (j.getName().matches(".*\\.class.{0,1}")) {
              final String classGuess =
                  j.getName().replaceAll("/", ".").replaceAll("\\.class.{0,1}", "");
              final Class candidate = ClassLoader.getSystemClassLoader().loadClass(classGuess);
              if (MSG_BASE_CLASS.isAssignableFrom(candidate)
                  || MSG_DATA_CLASS.isAssignableFrom(candidate)) {
                InputSupplier<InputStream> classSupplier =
                    Resources.newInputStreamSupplier(ClassLoader.getSystemResource(j.getName()));
                File destClassFile = SubDirectory.CLASSCACHE.getChildFile(j.getName());
                if (!destClassFile.exists()) {
                  Files.createParentDirs(destClassFile);
                  Files.copy(classSupplier, destClassFile);
                  Logs.extreme()
                      .debug("Caching: " + j.getName() + " => " + destClassFile.getAbsolutePath());
                }
                BINDING_CLASS_MAP.putIfAbsent(classGuess, candidate);
              }
            }
          } catch (RuntimeException ex) {
            LOG.error(ex, ex);
            jar.close();
            throw ex;
          }
        }
        jar.close();
      }
    }
  enum BindingFileSearch implements Predicate<URI> {
    INSTANCE;
    private static final String BINDING_EMPTY = "<binding>\n</binding>";
    private static final Boolean BINDING_DEBUG = System.getProperty("euca.binding.debug") != null;
    private static final Boolean BINDING_DEBUG_EXTREME =
        System.getProperty("euca.binding.debug.extreme") != null;
    private static List<URI> BINDING_LIST = Lists.newArrayList();
    private static ConcurrentMap<String, Class> BINDING_CLASS_MAP = Maps.newConcurrentMap();
    private static final String BINDING_CACHE_JAR_PREFIX = "jar.";
    private static final String BINDING_CACHE_BINDING_PREFIX = "binding.";
    private static final String BINDING_CACHE_DIGEST_LIST = "classcache.properties";
    private static final File CACHE_LIST =
        SubDirectory.CLASSCACHE.getChildFile(BINDING_CACHE_DIGEST_LIST);
    private final ClassLoader CACHE_CLASS_LOADER;
    private final Class<?> MSG_BASE_CLASS;
    private final Class<?> MSG_DATA_CLASS;
    private static final String FILE_PATTERN =
        System.getProperty("euca.binding.pattern", ".*\\-binding.xml");
    private static final Properties CURRENT_PROPS = new Properties();

    private BindingFileSearch() {
      try {
        CACHE_CLASS_LOADER =
            new URLClassLoader(new URL[] {SubDirectory.CLASSCACHE.getFile().toURL()});
        MSG_BASE_CLASS = Class.forName("edu.ucsb.eucalyptus.msgs.BaseMessage");
        MSG_DATA_CLASS = Class.forName("edu.ucsb.eucalyptus.msgs.EucalyptusData");
      } catch (Exception ex) {
        LOG.error(ex, ex);
        throw Exceptions.toUndeclared(ex);
      }
    }

    public boolean check() {
      final Properties oldProps = new Properties();
      if (BindingFileSearch.CACHE_LIST.exists()) {
        try {
          Reader propIn = Files.newReader(BindingFileSearch.CACHE_LIST, Charset.defaultCharset());
          oldProps.load(propIn);
        } catch (Exception ex) {
          LOG.debug(ex, ex);
        }
      }
      Map<String, String> oldBindings = Maps.fromProperties(oldProps);
      Map<String, String> newBindings = Maps.fromProperties(BindingFileSearch.CURRENT_PROPS);
      if (oldBindings.equals(newBindings)) {
        LOG.info("Found up-to-date binding class cache: skipping message binding.");
        return true;
      } else {
        MapDifference<String, String> diffBindings = Maps.difference(oldBindings, newBindings);
        LOG.info("Binding class cache expired (old,new): \n" + diffBindings.entriesDiffering());
        try {
          Files.deleteRecursively(SubDirectory.CLASSCACHE.getFile());
        } catch (IOException ex) {
          LOG.error(ex, ex);
        }
        SubDirectory.CLASSCACHE.getFile().mkdir();
        return false;
      }
    }

    public void store() throws IOException {
      Writer propOut = new FileWriter(CACHE_LIST);
      try {
        try {
          CURRENT_PROPS.store(propOut, "Binding class cache generated on: ");
          propOut.close();
        } catch (Exception ex) {
          LOG.error(ex, ex);
          propOut.close();
        }
      } catch (IOException ex) {
        for (File f : SubDirectory.CLASSCACHE.getFile().listFiles()) {
          try {
            LOG.info("Cleaning up class cache: " + f.getCanonicalPath());
            Files.deleteRecursively(f);
          } catch (IOException ex1) {
            LOG.error(ex1, ex1);
          }
        }
        throw ex;
      }
    }

    public void process(File f) throws Exception {
      if (f.isDirectory()) {
        File[] files =
            f.listFiles(
                new FilenameFilter() {

                  @Override
                  public boolean accept(File dir, String name) {
                    return name.matches(FILE_PATTERN);
                  }
                });
        for (File ff : files) {
          byte[] bindingBytes = Files.toByteArray(ff);
          this.addCurrentBinding(bindingBytes, ff.getName(), "file:" + ff.getAbsolutePath());
        }
      } else {
        String digest = new BigInteger(Files.getDigest(f, Digest.MD5.get())).abs().toString(16);
        CURRENT_PROPS.put(BINDING_CACHE_JAR_PREFIX + f.getName(), digest);
        final JarFile jar = new JarFile(f);
        final List<JarEntry> jarList = Collections.list(jar.entries());
        for (final JarEntry j : jarList) {
          try {
            if (j.getName().matches(FILE_PATTERN)) {
              byte[] bindingBytes = ByteStreams.toByteArray(jar.getInputStream(j));
              String bindingName = j.getName();
              String bindingFullPath = "jar:file:" + f.getAbsolutePath() + "!/" + bindingName;
              this.addCurrentBinding(bindingBytes, bindingName, bindingFullPath);
            } else if (j.getName().matches(".*\\.class.{0,1}")) {
              final String classGuess =
                  j.getName().replaceAll("/", ".").replaceAll("\\.class.{0,1}", "");
              final Class candidate = ClassLoader.getSystemClassLoader().loadClass(classGuess);
              if (MSG_BASE_CLASS.isAssignableFrom(candidate)
                  || MSG_DATA_CLASS.isAssignableFrom(candidate)) {
                InputSupplier<InputStream> classSupplier =
                    Resources.newInputStreamSupplier(ClassLoader.getSystemResource(j.getName()));
                File destClassFile = SubDirectory.CLASSCACHE.getChildFile(j.getName());
                if (!destClassFile.exists()) {
                  Files.createParentDirs(destClassFile);
                  Files.copy(classSupplier, destClassFile);
                  Logs.extreme()
                      .debug("Caching: " + j.getName() + " => " + destClassFile.getAbsolutePath());
                }
                BINDING_CLASS_MAP.putIfAbsent(classGuess, candidate);
              }
            }
          } catch (RuntimeException ex) {
            LOG.error(ex, ex);
            jar.close();
            throw ex;
          }
        }
        jar.close();
      }
    }

    private void addCurrentBinding(
        byte[] bindingBytes, String bindingName, String bindingFullPath) {
      LOG.debug("Binding cache: loading binding from: " + bindingFullPath);
      BINDING_LIST.add(URI.create(bindingFullPath));
      String digest = new BigInteger(Digest.MD5.get().digest(bindingBytes)).abs().toString(16);
      String entryName = BINDING_CACHE_BINDING_PREFIX + bindingName;
      if (!CURRENT_PROPS.containsKey(entryName)) {
        CURRENT_PROPS.put(entryName, digest);
      } else {
        // TODO:GRZE finish up this case.
        LOG.info("Duplicate binding entry: " + CURRENT_PROPS.getProperty(entryName));
      }
    }

    @Override
    public boolean apply(URI input) {
      try {
        String shortPath = input.toURL().getPath().replaceAll(".*!/", "");
        String sname = Utility.bindingFromFileName(shortPath);
        //        BindingDefinition def = Utility.loadBinding( input.toASCIIString( ), sname,
        // input.toURL( ).openStream( ), input.toURL( ), true );
        ValidationContext vctx = BindingElement.newValidationContext();
        BindingElement root =
            BindingElement.validateBinding(
                input.toASCIIString(), input.toURL(), input.toURL().openStream(), vctx);
        Predicate<BindingElement> writeFile =
            new Predicate<BindingElement>() {

              @SuppressWarnings("unchecked")
              @Override
              public boolean apply(BindingElement input) {
                for (ElementBase child : (List<ElementBase>) input.topChildren()) {
                  try {
                    if (child instanceof MappingElement) {
                      MappingElementBase mapping = (MappingElementBase) child;
                      ClassFile classFile = mapping.getHandledClass().getClassFile();
                      String classFileName = classFile.getName().replace(".", "/") + ".class";
                      InputSupplier<InputStream> classSupplier =
                          Resources.newInputStreamSupplier(
                              ClassLoader.getSystemResource(classFileName));
                      File destClassFile = SubDirectory.CLASSCACHE.getChildFile(classFileName);
                      if (!destClassFile.exists()) {
                        Files.createParentDirs(destClassFile);
                        Files.copy(classSupplier, destClassFile);
                      }
                      ClassFile cf = ClassFile.getClassFile(classFile.getName());
                      Logs.extreme()
                          .debug(
                              "Caching: "
                                  + classFile.getName()
                                  + " => "
                                  + destClassFile.getAbsolutePath());
                    } else if (child instanceof IncludeElement) {
                      IncludeElement includeElement = (IncludeElement) child;
                      BindingElement bind = includeElement.getBinding();
                      if (bind != null) {
                        this.apply(bind);
                      } else {
                        Files.write(
                            BINDING_EMPTY.getBytes(),
                            SubDirectory.CLASSCACHE.getChildFile(
                                includeElement.getIncludePath().replace("classpath:", "")));
                      }
                    }
                  } catch (Exception ex) {
                    LOG.error(ex, ex);
                  }
                }
                return true;
              }
            };
        if (!writeFile.apply(root)) {
          writeFile.apply(root);
        }
        return true;
      } catch (Exception ex) {
        throw Exceptions.toUndeclared(ex);
      }
    }

    public static void compile() {
      LOG.info("Binding cache: processing message and binding files.");
      processFiles();
      if (BindingFileSearch.INSTANCE.check()) {
        LOG.info("Binding cache: nothing to do.");
      } else {
        LOG.info("Binding cache: regenerating cache.");
        try {
          LOG.info("Binding cache: generating internal bindings.");
          // generate msgs-binding
          InternalSoapBindingGenerator gen = new InternalSoapBindingGenerator();
          for (Class genBindClass : BindingFileSearch.BINDING_CLASS_MAP.values()) {
            Logs.extreme().debug("Generating binding: " + genBindClass);
            gen.processClass(genBindClass);
          }
          gen.close();
          BINDING_LIST.add(gen.getOutFile().toURI());
          LOG.info("Binding cache: populating cache from transitive closure of bindings.");
          // load *-binding.xml, populate cache w/ all referenced files
          BindingFileSearch.reset(Utility.getClassPaths());
          Iterables.all(BindingFileSearch.BINDING_LIST, BindingFileSearch.INSTANCE);
          BindingFileSearch.reset(Utility.getClassPaths());
          LOG.info("Binding cache: loading and validating bindings.");
          Map<URI, BindingDefinition> bindingDefs = Maps.newHashMap();
          PrintStream oldOut = System.out, oldErr = System.err;

          for (URI binding : BINDING_LIST) {
            String shortPath = binding.toURL().getPath().replaceAll(".*!/", "");
            String sname = Utility.bindingFromFileName(shortPath);
            BindingDefinition def =
                Utility.loadBinding(
                    binding.toASCIIString(),
                    sname,
                    binding.toURL().openStream(),
                    binding.toURL(),
                    true);
            bindingDefs.put(binding, def);
            def.print();
          }
          LOG.info("Binding cache: compiling bindings.");
          for (Entry<URI, BindingDefinition> def : bindingDefs.entrySet()) {
            try {
              LOG.debug("Binding cache: " + def.getKey());
              def.getValue()
                  .generateCode(
                      BindingFileSearch.BINDING_DEBUG, BindingFileSearch.BINDING_DEBUG_EXTREME);
            } catch (RuntimeException e) {
              throw new JiBXException(
                  "\n*** Error during code generation for file '"
                      + def.getKey()
                      + "' -\n this may be due to an error in "
                      + "your binding or classpath, or to an error in the "
                      + "JiBX code ***\n",
                  e);
            }
          }
          ClassFile[][] lists = MungedClass.fixDispositions();
          for (BindingDefinition def : bindingDefs.values()) {
            def.addClassList(lists[0], lists[1]);
          }
          MungedClass.writeChanges();
          LOG.info("Binding cache: wrote " + lists[0].length + " files");
          LOG.info("Binding cache: kept " + lists[1].length + " files unchanged:");
          LOG.info("Binding cache: deleted " + lists[2].length + " files:");
          BindingFileSearch.INSTANCE.store();
          System.exit(123); // success! now we restart.
        } catch (Exception ex) {
          LOG.error(ex, ex);
          System.exit(1);
          throw new Error(
              "Failed to prepare the system while trying to compile bindings: " + ex.getMessage(),
              ex);
        }
      }
    }

    public static void processFiles() {
      final File libDir = new File(BaseDirectory.LIB.toString());
      for (final File f : libDir.listFiles()) {
        if (f.getName().startsWith("eucalyptus")
            && f.getName().endsWith(".jar")
            && !f.getName().matches(".*-ext-.*")) {
          EventRecord.here(
                  ServiceJarDiscovery.class, EventType.BOOTSTRAP_INIT_SERVICE_JAR, f.getName())
              .info();
          try {
            BindingFileSearch.INSTANCE.process(f);
          } catch (final Throwable e) {
            LOG.error(e.getMessage());
            continue;
          }
        }
      }
      for (String pathName : ClassPath.SYSTEM_CLASS_PATH.getClassPath().split(File.pathSeparator)) {
        File pathFile = new File(pathName);
        if (pathFile.isDirectory()) {
          try {
            BindingFileSearch.INSTANCE.process(pathFile);
          } catch (final Throwable e) {
            LOG.error(e.getMessage());
            continue;
          }
          ;
        }
      }
    }

    public static String[] reset(String[] paths) {
      ClassCache.setPaths(paths);
      ClassFile.setPaths(paths);
      ClasspathUrlExtender.setClassLoader(ClassFile.getClassLoader());
      BoundClass.reset();
      MungedClass.reset();
      BindingDefinition.reset();
      BranchWrapper.setTracking(false);
      BranchWrapper.setErrorOverride(false);
      return paths;
    }
  }