protected void initialiseMetamodel() {
   moduleGraph.visit(
       new ModuleGraph.Visitor() {
         @Override
         public void visit(Module module) {
           registerInMetamodel(module);
         }
       });
 }
 public void cleanup() {
   if (moduleClassLoader != delegateClassLoader && moduleClassLoader instanceof URLClassLoader) {
     try {
       ((URLClassLoader) moduleClassLoader).close();
     } catch (IOException e) {
       // ignore
       e.printStackTrace();
     }
   }
   moduleGraph.clear();
   moduleClassLoader = null;
 }
 void loadModule(
     String name,
     String version,
     boolean optional,
     boolean inCurrentClassLoader,
     ModuleGraph.Module dependent)
     throws IOException {
   ArtifactContext artifactContext =
       new ArtifactContext(name, version, ArtifactContext.CAR, ArtifactContext.JAR);
   Overrides overrides = repositoryManager.getOverrides();
   if (overrides != null) {
     if (overrides.isRemoved(artifactContext)) return;
     ArtifactContext replacement = overrides.replace(artifactContext);
     if (replacement != null) {
       artifactContext = replacement;
       name = replacement.getName();
       version = replacement.getVersion();
     }
     if (overrides.isVersionOverridden(artifactContext)) {
       version = overrides.getVersionOverride(artifactContext);
       artifactContext.setVersion(version);
     }
   }
   // skip JDK modules
   if (JDKUtils.isJDKModule(name) || JDKUtils.isOracleJDKModule(name)) return;
   ModuleGraph.Module loadedModule = moduleGraph.findModule(name);
   if (loadedModule != null) {
     String loadedVersion = loadedModule.version;
     // we loaded the module already, but did we load it with the same version?
     if (!Objects.equals(version, loadedVersion)) {
       if (MavenVersionComparator.compareVersions(version, loadedModule.version) > 0) {
         // we want a newer version, keep going
         if (verbose) log("Replacing " + loadedModule + " with newer version " + version);
       } else {
         // we want an older version, just keep the one we have and ignore that
         addDependency(dependent, loadedModule);
         // already resolved and same version, we're good
         return;
       }
     } else if (loadedModule.artifact == null) {
       // now we're sure the version was the same
       // it was resolved to null so it was optional, but perhaps it's required now?
       if (!optional) {
         throw new ModuleNotFoundException(
             "Could not find module: " + ModuleUtil.makeModuleName(name, version));
       }
       addDependency(dependent, loadedModule);
       // already resolved and same version, we're good
       return;
     } else {
       addDependency(dependent, loadedModule);
       // already resolved and same version, we're good
       return;
     }
   }
   if (verbose) log("Resolving " + name + "/" + version);
   ArtifactResult result = repositoryManager.getArtifactResult(artifactContext);
   if (!optional
       && (result == null || result.artifact() == null || !result.artifact().exists())) {
     throw new ModuleNotFoundException(
         "Could not find module: " + ModuleUtil.makeModuleName(name, version));
   }
   // save even missing optional modules as nulls to not re-resolve them
   ModuleGraph.Module mod;
   if (dependent == null) mod = moduleGraph.addRoot(name, version);
   else mod = dependent.addDependency(name, version);
   if (loadedModule != null) loadedModule.replace(mod);
   mod.artifact = result;
   if (result != null) {
     // everything we know should be in the current class loader
     // plus everything from flat repositories
     if (inCurrentClassLoader || result.repository() instanceof FlatRepository) {
       mod.inCurrentClassLoader = true;
     }
     for (ArtifactResult dep : result.dependencies()) {
       // stop if we get removed at any point
       if (mod.replaced) break;
       loadModule(
           dep.name(),
           dep.version(),
           dep.importType() == ImportType.OPTIONAL,
           inCurrentClassLoader,
           mod);
     }
   }
 }
 private void addDependency(Module from, Module to) {
   if (from != null) from.addDependency(to);
   else moduleGraph.addRoot(to);
 }