private ModuleSpec parseModuleInfoFile(
     final ModuleIdentifier moduleIdentifier, final File moduleRoot, final File moduleInfoFile)
     throws ModuleLoadException {
   return ModuleXmlParser.parse(moduleIdentifier, moduleRoot, moduleInfoFile);
 }
 public ModuleSpec findModule(final ModuleIdentifier identifier, final ModuleLoader delegateLoader)
     throws ModuleLoadException {
   if (identifier.equals(myIdentifier)) {
     // special root JAR module
     Manifest manifest;
     try {
       manifest = jarFile.getManifest();
     } catch (IOException e) {
       throw new ModuleLoadException("Failed to load MANIFEST from JAR", e);
     }
     ModuleSpec.Builder builder = ModuleSpec.build(identifier);
     Attributes mainAttributes = manifest.getMainAttributes();
     String mainClass = mainAttributes.getValue(Attributes.Name.MAIN_CLASS);
     if (mainClass != null) {
       builder.setMainClass(mainClass);
     }
     String classPath = mainAttributes.getValue(Attributes.Name.CLASS_PATH);
     String dependencies = mainAttributes.getValue("Dependencies");
     MultiplePathFilterBuilder pathFilterBuilder = PathFilters.multiplePathFilterBuilder(true);
     pathFilterBuilder.addFilter(PathFilters.is("modules"), false);
     pathFilterBuilder.addFilter(PathFilters.isChildOf("modules"), false);
     builder.addResourceRoot(
         ResourceLoaderSpec.createResourceLoaderSpec(
             new JarFileResourceLoader("", jarFile), pathFilterBuilder.create()));
     String[] classPathEntries =
         classPath == null ? JarModuleLoader.NO_STRINGS : classPath.split("\\s+");
     for (String entry : classPathEntries) {
       if (!entry.isEmpty()) {
         if (entry.startsWith("../")
             || entry.startsWith("./")
             || entry.startsWith("/")
             || entry.contains("/../")) {
           // invalid
           continue;
         }
         if (entry.endsWith("/")) {
           // directory reference
           File root = new File(jarFile.getName(), entry);
           FileResourceLoader resourceLoader = new FileResourceLoader(entry, root);
           builder.addResourceRoot(ResourceLoaderSpec.createResourceLoaderSpec(resourceLoader));
         } else {
           // assume a JAR
           File root = new File(jarFile.getName(), entry);
           JarFile childJarFile;
           try {
             childJarFile = new JarFile(root, true);
           } catch (IOException e) {
             // ignore and continue
             continue;
           }
           builder.addResourceRoot(
               ResourceLoaderSpec.createResourceLoaderSpec(
                   new JarFileResourceLoader(entry, childJarFile)));
         }
       }
     }
     String[] dependencyEntries =
         dependencies == null ? JarModuleLoader.NO_STRINGS : dependencies.split("\\s*,\\s*");
     for (String dependencyEntry : dependencyEntries) {
       boolean optional = false;
       boolean export = false;
       dependencyEntry = dependencyEntry.trim();
       if (!dependencyEntry.isEmpty()) {
         String[] fields = dependencyEntry.split("\\s+");
         if (fields.length < 1) {
           continue;
         }
         String moduleName = fields[0];
         for (int i = 1; i < fields.length; i++) {
           String field = fields[i];
           if (field.equals("optional")) {
             optional = true;
           } else if (field.equals("export")) {
             export = true;
           }
           // else ignored
         }
         builder.addDependency(
             DependencySpec.createModuleDependencySpec(
                 ModuleIdentifier.fromString(moduleName), export, optional));
       }
     }
     builder.addDependency(DependencySpec.createSystemDependencySpec(JDKPaths.JDK));
     builder.addDependency(DependencySpec.createLocalDependencySpec());
     return builder.create();
   } else {
     String namePath = identifier.getName().replace('.', '/');
     String basePath = "modules/" + namePath + "/" + identifier.getSlot();
     JarEntry moduleXmlEntry = jarFile.getJarEntry(basePath + "/module.xml");
     if (moduleXmlEntry == null) {
       return null;
     }
     ModuleSpec moduleSpec;
     try {
       InputStream inputStream = jarFile.getInputStream(moduleXmlEntry);
       try {
         moduleSpec =
             ModuleXmlParser.parseModuleXml(
                 new ModuleXmlParser.ResourceRootFactory() {
                   public ResourceLoader createResourceLoader(
                       final String rootPath, final String loaderPath, final String loaderName)
                       throws IOException {
                     return new JarFileResourceLoader(loaderName, jarFile, loaderPath);
                   }
                 },
                 basePath,
                 inputStream,
                 moduleXmlEntry.getName(),
                 delegateLoader,
                 identifier);
       } finally {
         JarModuleLoader.safeClose(inputStream);
       }
     } catch (IOException e) {
       throw new ModuleLoadException("Failed to read module.xml file", e);
     }
     return moduleSpec;
   }
 }