private boolean unzipModule(
      final ModuleIdentifier modID, final ModuleZipInfo zipInfo, boolean deleteZip) {
    // We synchronize to prevent a race whereby it tries to unzip the same module at the
    // same time (e.g. deployModule for the same module name has been called in parallel)
    String modName = modID.toString();
    synchronized (modName.intern()) {
      if (!checkModDirs()) {
        return false;
      }

      File fdest = new File(modRoot, modName);
      File sdest = new File(systemModRoot, modName);
      if (fdest.exists() || sdest.exists()) {
        // This can happen if the same module is requested to be installed
        // at around the same time
        // It's ok if this happens
        log.warn("Module " + modID + " is already installed");
        return true;
      }

      // Unzip into temp dir first
      File tdest = unzipIntoTmpDir(zipInfo, deleteZip);
      if (tdest == null) {
        return false;
      }

      // Check if it's a system module
      JsonObject conf = loadModuleConfig(modID, tdest);
      ModuleFields fields = new ModuleFields(conf);

      boolean system = fields.isSystem();

      // Now copy it to the proper directory
      String moveFrom = tdest.getAbsolutePath();
      try {
        vertx
            .fileSystem()
            .moveSync(moveFrom, system ? sdest.getAbsolutePath() : fdest.getAbsolutePath());
      } catch (Exception e) {
        log.error("Failed to move module", e);
        return false;
      }

      log.info("Module " + modID + " successfully installed");
      return true;
    }
  }
 private boolean doPullInDependencies(File modRoot, ModuleIdentifier modID) {
   File modDir = new File(modRoot, modID.toString());
   if (!modDir.exists()) {
     log.error("Cannot find module to uninstall");
   }
   JsonObject conf = loadModuleConfig(modID, modDir);
   if (conf == null) {
     log.error("Module " + modID + " does not contain a mod.json");
   }
   ModuleFields fields = new ModuleFields(conf);
   List<String> mods = new ArrayList<>();
   String includes = fields.getIncludes();
   if (includes != null) {
     mods.addAll(Arrays.asList(parseIncludeString(includes)));
   }
   String deploys = fields.getDeploys();
   if (deploys != null) {
     mods.addAll(Arrays.asList(parseIncludeString(deploys)));
   }
   if (!mods.isEmpty()) {
     File internalModsDir = new File(modDir, "mods");
     if (!internalModsDir.exists()) {
       internalModsDir.mkdir();
     }
     for (String modName : mods) {
       File internalModDir = new File(internalModsDir, modName);
       if (!internalModDir.exists()) {
         ModuleIdentifier theModID = new ModuleIdentifier(modName);
         ModuleZipInfo zipInfo = getModule(theModID);
         if (zipInfo.filename != null) {
           internalModDir.mkdir();
           if (!unzipModuleData(internalModDir, zipInfo, true)) {
             return false;
           } else {
             log.info("Module " + modName + " successfully installed in mods dir of " + modName);
             // Now recurse so we bring in all of the deps
             doPullInDependencies(internalModsDir, theModID);
           }
         }
       }
     }
   }
   return true;
 }
  private boolean loadIncludedModules(
      File currentModuleDir, ModuleReference mr, String includesString) {
    checkWorkerContext();
    for (String moduleName : parseIncludeString(includesString)) {
      ModuleIdentifier modID = new ModuleIdentifier(moduleName);
      ModuleReference includedMr = moduleRefs.get(moduleName);
      if (includedMr == null) {
        File modDir = locateModule(currentModuleDir, modID);
        if (modDir == null) {
          if (!doInstallMod(modID)) {
            return false;
          }
        }
        modDir = locateModule(currentModuleDir, modID);
        List<URL> urls = getModuleClasspath(modDir);
        JsonObject conf = loadModuleConfig(modID, modDir);
        ModuleFields fields = new ModuleFields(conf);

        boolean res = fields.isResident();
        includedMr =
            new ModuleReference(
                this,
                moduleName,
                new ModuleClassLoader(platformClassLoader, urls.toArray(new URL[urls.size()])),
                res);
        ModuleReference prev = moduleRefs.putIfAbsent(moduleName, includedMr);
        if (prev != null) {
          includedMr = prev;
        }
        String includes = fields.getIncludes();
        if (includes != null) {
          loadIncludedModules(modDir, includedMr, includes);
        }
      }
      includedMr.incRef();
      mr.mcl.addParent(includedMr);
    }
    return true;
  }
  private void doDeployMod(
      final boolean redeploy,
      final String depName,
      final ModuleIdentifier modID,
      final JsonObject config,
      final int instances,
      final File currentModDir,
      final Handler<String> doneHandler) {
    checkWorkerContext();
    File modDir = locateModule(currentModDir, modID);
    if (modDir != null) {
      JsonObject conf = loadModuleConfig(modID, modDir);
      ModuleFields fields = new ModuleFields(conf);
      String main = fields.getMain();
      if (main == null) {
        log.error("Runnable module " + modID + " mod.json must contain a \"main\" field");
        callDoneHandler(doneHandler, null);
        return;
      }
      boolean worker = fields.isWorker();
      boolean multiThreaded = fields.isMultiThreaded();
      if (multiThreaded && !worker) {
        throw new IllegalArgumentException("Multi-threaded modules must be workers");
      }
      boolean preserveCwd = fields.isPreserveCurrentWorkingDirectory();

      // If preserveCwd then use the current module directory instead, or the cwd if not in a module
      File modDirToUse = preserveCwd ? currentModDir : modDir;

      List<URL> urls = getModuleClasspath(modDir);
      if (urls == null) {
        callDoneHandler(doneHandler, null);
        return;
      }

      ModuleReference mr = moduleRefs.get(modID.toString());
      if (mr == null) {
        boolean res = fields.isResident();
        mr =
            new ModuleReference(
                this,
                modID.toString(),
                new ModuleClassLoader(platformClassLoader, urls.toArray(new URL[urls.size()])),
                res);
        ModuleReference prev = moduleRefs.putIfAbsent(modID.toString(), mr);
        if (prev != null) {
          mr = prev;
        }
      }
      ModuleIdentifier enclosingModID = getEnclosingModID();
      if (enclosingModID != null) {
        // If enclosed in another module then the enclosing module classloader becomes a parent of
        // this one
        ModuleReference parentRef = moduleRefs.get(enclosingModID.toString());
        mr.mcl.addParent(parentRef);
        parentRef.incRef();
      }

      // Now load any included moduleRefs
      String includes = fields.getIncludes();
      if (includes != null) {
        if (!loadIncludedModules(modDir, mr, includes)) {
          callDoneHandler(doneHandler, null);
          return;
        }
      }

      final boolean autoRedeploy = fields.isAutoRedeploy();

      doDeploy(
          depName,
          autoRedeploy,
          worker,
          multiThreaded,
          main,
          modID,
          config,
          urls.toArray(new URL[urls.size()]),
          instances,
          modDirToUse,
          mr,
          new Handler<String>() {
            @Override
            public void handle(String deploymentID) {
              if (deploymentID != null && !redeploy && autoRedeploy) {
                redeployer.moduleDeployed(deployments.get(deploymentID));
              }
              callDoneHandler(doneHandler, deploymentID);
            }
          });
    } else {
      if (doInstallMod(modID)) {
        doDeployMod(redeploy, depName, modID, config, instances, currentModDir, doneHandler);
      } else {
        callDoneHandler(doneHandler, null);
      }
    }
  }