Package com.darylteo.deploy.modules

Source Code of com.darylteo.deploy.modules.ModuleLoader

package com.darylteo.deploy.modules;

import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;

public class ModuleLoader {
  private final ModuleLoader that = this;
  private final Path folder;

  private final WatchService watcher;
  private final Map<WatchKey, String> keyModuleMap;

  private final ModuleLoaderDelegate delegate;

  public ModuleLoader(Path folder, ModuleLoaderDelegate delegate)
      throws Exception {
    this.folder = folder;

    System.out.printf("Looking for Modules In %s\n", this.folder);

    File f = this.folder.toFile();
    if (!f.exists()) {
      // Modules Directory does not exist
      throw new Exception("Modules Directory %s Does Not Exist!");
    }

    this.delegate = delegate;

    this.watcher = FileSystems.getDefault().newWatchService();
    this.keyModuleMap = new HashMap<>();

    loadExistingModules();
    setupWatchService();
  }

  private void loadExistingModules() {
    try {
      Files.walkFileTree(this.folder, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir,
            BasicFileAttributes attrs) throws IOException {

          /*
           * Do a non-recursive watch on the root folder to detect
           * module installation/uninstallation
           */
          if (dir.equals(that.folder)) {
            that.registerRoot();
            return FileVisitResult.CONTINUE;
          }

          /*
           * Recursively watch module directory to detect module
           * modification
           */
          String moduleName = that.folder.relativize(dir).getName(0)
              .toString();
          that.registerAll(dir, moduleName);
          that.delegate.moduleInstalled(moduleName);

          return FileVisitResult.SKIP_SUBTREE;
        }
      });
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  /* WatchService methods */

  /**
   * Sets up the Watch Service
   */
  private void setupWatchService() throws IOException {
    new Thread(new Runnable() {
      @Override
      public void run() {
        that.watch();
      }
    }).start();
  }

  /**
   * Register the given directory with the WatchService
   */
  private void registerRoot() throws IOException {
    WatchKey key = this.folder
        .register(watcher, ENTRY_CREATE, ENTRY_DELETE);
    this.keyModuleMap.put(key, "");

  }

  private void register(Path dir, String moduleName) throws IOException {
    WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_MODIFY,
        ENTRY_DELETE);
    this.keyModuleMap.put(key, moduleName);

    System.out.printf("%s, %s -> %s\n", moduleName, key, dir);
  }

  /**
   * Register the given directory, and all its sub-directories, with the
   * WatchService, linked to a ModuleName.
   */
  private void registerAll(final Path start, final String moduleName)
      throws IOException {
    // register directory and sub-directories
    Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
      @Override
      public FileVisitResult preVisitDirectory(Path dir,
          BasicFileAttributes attrs) throws IOException {
        /* Register the Directory */
        register(dir, moduleName);
        return FileVisitResult.CONTINUE;
      }
    });
  }

  private void watch() {
    boolean exit = false;
    while (!exit) {
      WatchKey key;

      try {
        key = this.watcher.take();
      } catch (InterruptedException e) {
        return;
      }

      String moduleName = this.keyModuleMap.get(key);

      try {
        if (moduleName.equals("")) {
          handleRootEvent(key);
        } else {
          handleModuleEvent(key, moduleName);
        }
      } catch (IOException e) {
        // TODO: Error Handling
        e.printStackTrace();
      }

    }
  }

  private void handleRootEvent(WatchKey key) throws IOException {

    for (WatchEvent<?> event : key.pollEvents()) {

      if (event.kind() == OVERFLOW) {
        continue;
      }

      String moduleName = event.context().toString();
      Path targetPath = this.folder.resolve(moduleName);

      /* Add new module to watchservice, notify handler of installation */
      if (event.kind() == ENTRY_CREATE) {
        /* Ignore non-module files. Modules must be directories */
        if (!Files.isDirectory(targetPath, NOFOLLOW_LINKS)) {
          continue;
        }

        this.registerAll(targetPath, moduleName);
        this.delegate.moduleInstalled(moduleName);

      } else /* notify handler of deletion */
      {
        /*
         * if not ENTRY_CREATE then must be ENTRY_DELETE as we're not
         * tracking ENTRY_MODIFY
         */
        /* Notify */
        this.delegate.moduleUninstalled(moduleName);
      }
    }

    /* Returns False if key is invalidated */
    if (!key.reset()) {
      /*
       * TODO: Exception Handling... this key is for root, should never be
       * invalidated
       */
      System.out.println("Bad Error: Root WatchKey Invalidated");
      this.keyModuleMap.remove(key);
    }
  }

  private void handleModuleEvent(WatchKey key, String moduleName)
      throws IOException {

    for (WatchEvent<?> event : key.pollEvents()) {

      if (event.kind() == OVERFLOW) {
        continue;
      }

      Path targetPath = this.folder.resolve(moduleName);

      /* Register any new directories for watching */
      if (event.kind() == ENTRY_CREATE) {
        /* Ignore non-directories */
        if (!Files.isDirectory(targetPath, NOFOLLOW_LINKS)) {
          continue;
        }

        this.registerAll(targetPath, moduleName);
      }

      /* Notify */
      this.delegate.moduleModified(moduleName);
    }

    /* Returns False if key is invalidated */
    if (!key.reset()) {
      System.out.println("Key Invalidated: " + moduleName);
      this.keyModuleMap.remove(key);
    }
  }
}
TOP

Related Classes of com.darylteo.deploy.modules.ModuleLoader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.