/** * Try to load a module from this module loader. Returns {@code null} if the module is not found. * The returned module may not yet be resolved. The returned module may have a different name than * the given identifier if the identifier is an alias for another module. * * @param identifier the module identifier * @return the module * @throws ModuleLoadException if an error occurs while loading the module */ protected final Module loadModuleLocal(ModuleIdentifier identifier) throws ModuleLoadException { FutureModule futureModule = moduleMap.get(identifier); if (futureModule != null) { return futureModule.getModule(); } FutureModule newFuture = new FutureModule(identifier); futureModule = moduleMap.putIfAbsent(identifier, newFuture); if (futureModule != null) { return futureModule.getModule(); } boolean ok = false; try { final ModuleLogger log = Module.log; log.trace("Locally loading module %s from %s", identifier, this); final long startTime = Metrics.getCurrentCPUTime(); final ModuleSpec moduleSpec = findModule(identifier); loadTimeUpdater.addAndGet(this, Metrics.getCurrentCPUTime() - startTime); if (moduleSpec == null) { log.trace("Module %s not found from %s", identifier, this); return null; } if (!moduleSpec.getModuleIdentifier().equals(identifier)) { throw new ModuleLoadException("Module loader found a module with the wrong name"); } final Module module; if (moduleSpec instanceof AliasModuleSpec) { final ModuleIdentifier aliasTarget = ((AliasModuleSpec) moduleSpec).getAliasTarget(); try { newFuture.setModule(module = loadModuleLocal(aliasTarget)); } catch (RuntimeException e) { log.trace(e, "Failed to load module %s (alias for %s)", identifier, aliasTarget); throw e; } catch (Error e) { log.trace(e, "Failed to load module %s (alias for %s)", identifier, aliasTarget); throw e; } } else { module = defineModule((ConcreteModuleSpec) moduleSpec, newFuture); } log.trace("Loaded module %s from %s", identifier, this); ok = true; return module; } finally { if (!ok) { newFuture.setModule(null); moduleMap.remove(identifier, newFuture); } } }
/** * Defines a Module based on a specification. Use of this method is required by any ModuleLoader * implementations in order to fully define a Module. * * @param moduleSpec The module specification to create the Module from * @return The defined Module * @throws ModuleLoadException If any dependent modules can not be loaded */ protected final Module defineModule(ModuleSpec moduleSpec) throws ModuleLoadException { final ModuleIdentifier moduleIdentifier = moduleSpec.getIdentifier(); FutureModule futureModule = moduleMap.get(moduleIdentifier); if (futureModule == null) { FutureModule newFuture = new FutureModule(moduleIdentifier); futureModule = moduleMap.putIfAbsent(moduleIdentifier, newFuture); if (futureModule == null) futureModule = newFuture; } // early detect if (futureModule.module != null) { throw new ModuleAlreadyExistsException(moduleIdentifier.toString()); } try { final List<Dependency> dependencies = new ArrayList<Dependency>(moduleSpec.getDependencies().size()); for (DependencySpec dependencySpec : moduleSpec.getDependencies()) { final Module dependencyModule; try { dependencyModule = loadModule(dependencySpec.getModuleIdentifier()); } catch (ModuleLoadException e) { if (dependencySpec.isOptional()) { continue; } else { throw e; } } final Dependency dependency = new Dependency(dependencyModule, dependencySpec.isExport()); dependencies.add(dependency); } final Module module = new Module(moduleSpec, dependencies, moduleSpec.getModuleFlags(), this); synchronized (futureModule) { futureModule.setModule(module); } return module; } catch (ModuleLoadException e) { futureModule.setModule(null); throw e; } catch (RuntimeException e) { futureModule.setModule(null); throw e; } catch (Error e) { futureModule.setModule(null); throw e; } }
/** * Defines a Module based on a specification. May only be called from {@link * #loadModuleLocal(ModuleIdentifier)}. * * @param moduleSpec The module specification to create the Module from * @param futureModule the future module to populate * @return The defined Module * @throws ModuleLoadException If any dependent modules can not be loaded */ private Module defineModule(final ConcreteModuleSpec moduleSpec, final FutureModule futureModule) throws ModuleLoadException { final ModuleLogger log = Module.log; final ModuleIdentifier moduleIdentifier = moduleSpec.getModuleIdentifier(); final Module module = new Module(moduleSpec, this, futureModule); module.getClassLoaderPrivate().recalculate(); module.setDependencies(Arrays.asList(moduleSpec.getDependencies())); log.moduleDefined(moduleIdentifier, this); try { futureModule.setModule(module); return module; } catch (RuntimeException e) { log.trace(e, "Failed to load module %s", moduleIdentifier); throw e; } catch (Error e) { log.trace(e, "Failed to load module %s", moduleIdentifier); throw e; } }