95 * 96 * @since 9 97 * @spec JPMS 98 * @see java.lang.reflect.Layer 99 */ 100 public final class Configuration { 101 102 // @see Configuration#empty() 103 private static final Configuration EMPTY_CONFIGURATION = new Configuration(); 104 105 // parent configurations, in search order 106 private final List<Configuration> parents; 107 108 private final Map<ResolvedModule, Set<ResolvedModule>> graph; 109 private final Set<ResolvedModule> modules; 110 private final Map<String, ResolvedModule> nameToModule; 111 112 // module constraints on target 113 private final String osName; 114 private final String osArch; 115 private final String osVersion; 116 117 String osName() { return osName; } 118 String osArch() { return osArch; } 119 String osVersion() { return osVersion; } 120 121 private Configuration() { 122 this.parents = Collections.emptyList(); 123 this.graph = Collections.emptyMap(); 124 this.modules = Collections.emptySet(); 125 this.nameToModule = Collections.emptyMap(); 126 this.osName = null; 127 this.osArch = null; 128 this.osVersion = null; 129 } 130 131 private Configuration(List<Configuration> parents, 132 Resolver resolver, 133 boolean check) 134 { 135 Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check); 136 137 @SuppressWarnings(value = {"rawtypes", "unchecked"}) 138 Entry<String, ResolvedModule>[] nameEntries 139 = (Entry<String, ResolvedModule>[])new Entry[g.size()]; 140 ResolvedModule[] moduleArray = new ResolvedModule[g.size()]; 141 int i = 0; 142 for (ResolvedModule resolvedModule : g.keySet()) { 143 moduleArray[i] = resolvedModule; 144 nameEntries[i] = Map.entry(resolvedModule.name(), resolvedModule); 145 i++; 146 } 147 148 this.parents = Collections.unmodifiableList(parents); 149 this.graph = g; 150 this.modules = Set.of(moduleArray); 151 this.nameToModule = Map.ofEntries(nameEntries); 152 153 this.osName = resolver.osName(); 154 this.osArch = resolver.osArch(); 155 this.osVersion = resolver.osVersion(); 156 } 157 158 /** 159 * Resolves a collection of root modules, with this configuration as its 160 * parent, to create a new configuration. This method works exactly as 161 * specified by the static {@link 162 * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve} 163 * method when invoked with this configuration as the parent. In other words, 164 * if this configuration is {@code cf} then this method is equivalent to 165 * invoking: 166 * <pre> {@code 167 * Configuration.resolve(before, List.of(cf), after, roots); 168 * }</pre> 169 * 170 * @param before 171 * The <em>before</em> module finder to find modules 172 * @param after 173 * The <em>after</em> module finder to locate modules when not 174 * located by the {@code before} module finder or in parent 175 * configurations 264 * Resolves a collection of root modules to create a configuration. 265 * 266 * <p> Each root module is located using the given {@code before} module 267 * finder. If a module is not found then it is located in the parent 268 * configuration as if by invoking the {@link #findModule(String) 269 * findModule} method on each parent in iteration order. If not found then 270 * the module is located using the given {@code after} module finder. The 271 * same search order is used to locate transitive dependences. Root modules 272 * or dependences that are located in a parent configuration are resolved 273 * no further and are not included in the resulting configuration. </p> 274 * 275 * <p> When all modules have been resolved then the resulting dependency 276 * graph is checked to ensure that it does not contain cycles. A 277 * readability graph is constructed, and in conjunction with the module 278 * exports and service use, checked for consistency. </p> 279 * 280 * <p> Resolution may fail with {@code FindException} for the following 281 * <em>observability-related</em> reasons: </p> 282 * 283 * <ul> 284 * <li><p> A root module, or a direct or transitive dependency, is not 285 * found. </p></li> 286 * 287 * <li><p> An error occurs when attempting to find a module. 288 * Possible errors include I/O errors, errors detected parsing a module 289 * descriptor ({@code module-info.class}) or two versions of the same 290 * module are found in the same directory. </p></li> 291 * 292 * <li><p> A module with the required name is found but the module 293 * requires a different {@link ModuleDescriptor#osName() operating 294 * system}, {@link ModuleDescriptor#osArch() architecture}, or {@link 295 * ModuleDescriptor#osVersion() version} to other modules that have 296 * been resolved for the new configuration or modules in the parent 297 * configurations. </p></li> 298 * 299 * </ul> 300 * 301 * <p> Post-resolution consistency checks may fail with {@code 302 * ResolutionException} for the following reasons: </p> 303 * 304 * <ul> 305 * 306 * <li><p> A cycle is detected, say where module {@code m1} requires 307 * module {@code m2} and {@code m2} requires {@code m1}. </p></li> 308 * 309 * <li><p> Two or more modules in the configuration export the same 310 * package to a module that reads both. This includes the case where a 311 * module {@code M} containing package {@code p} reads another module 312 * that exports {@code p} to {@code M}. </p></li> 313 * 314 * <li><p> A module {@code M} declares that it "{@code uses p.S}" or 315 * "{@code provides p.S with ...}" but package {@code p} is neither in 316 * module {@code M} nor exported to {@code M} by any module that 317 * {@code M} reads. </p></li> 318 * 319 * </ul> 320 * 321 * @implNote In the implementation then observability of modules may depend 322 * on referential integrity checks that ensure different builds of tightly 323 * coupled modules are not combined in the same configuration. 324 * 325 * @param before 326 * The <em>before</em> module finder to find modules 327 * @param parents 328 * The list parent configurations in search order 329 * @param after 330 * The <em>after</em> module finder to locate modules when not 331 * located by the {@code before} module finder or in parent 332 * configurations 333 * @param roots 334 * The possibly-empty collection of module names of the modules 335 * to resolve 336 * 337 * @return The configuration that is the result of resolving the given 338 * root modules 339 * 340 * @throws FindException 341 * If resolution fails for an observability-related reason 342 * @throws ResolutionException 343 * If a post-resolution consistency checks fails | 95 * 96 * @since 9 97 * @spec JPMS 98 * @see java.lang.reflect.Layer 99 */ 100 public final class Configuration { 101 102 // @see Configuration#empty() 103 private static final Configuration EMPTY_CONFIGURATION = new Configuration(); 104 105 // parent configurations, in search order 106 private final List<Configuration> parents; 107 108 private final Map<ResolvedModule, Set<ResolvedModule>> graph; 109 private final Set<ResolvedModule> modules; 110 private final Map<String, ResolvedModule> nameToModule; 111 112 // module constraints on target 113 private final String osName; 114 private final String osArch; 115 116 String osName() { return osName; } 117 String osArch() { return osArch; } 118 119 private Configuration() { 120 this.parents = Collections.emptyList(); 121 this.graph = Collections.emptyMap(); 122 this.modules = Collections.emptySet(); 123 this.nameToModule = Collections.emptyMap(); 124 this.osName = null; 125 this.osArch = null; 126 } 127 128 private Configuration(List<Configuration> parents, 129 Resolver resolver, 130 boolean check) 131 { 132 Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check); 133 134 @SuppressWarnings(value = {"rawtypes", "unchecked"}) 135 Entry<String, ResolvedModule>[] nameEntries 136 = (Entry<String, ResolvedModule>[])new Entry[g.size()]; 137 ResolvedModule[] moduleArray = new ResolvedModule[g.size()]; 138 int i = 0; 139 for (ResolvedModule resolvedModule : g.keySet()) { 140 moduleArray[i] = resolvedModule; 141 nameEntries[i] = Map.entry(resolvedModule.name(), resolvedModule); 142 i++; 143 } 144 145 this.parents = Collections.unmodifiableList(parents); 146 this.graph = g; 147 this.modules = Set.of(moduleArray); 148 this.nameToModule = Map.ofEntries(nameEntries); 149 150 this.osName = resolver.osName(); 151 this.osArch = resolver.osArch(); 152 } 153 154 /** 155 * Resolves a collection of root modules, with this configuration as its 156 * parent, to create a new configuration. This method works exactly as 157 * specified by the static {@link 158 * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve} 159 * method when invoked with this configuration as the parent. In other words, 160 * if this configuration is {@code cf} then this method is equivalent to 161 * invoking: 162 * <pre> {@code 163 * Configuration.resolve(before, List.of(cf), after, roots); 164 * }</pre> 165 * 166 * @param before 167 * The <em>before</em> module finder to find modules 168 * @param after 169 * The <em>after</em> module finder to locate modules when not 170 * located by the {@code before} module finder or in parent 171 * configurations 260 * Resolves a collection of root modules to create a configuration. 261 * 262 * <p> Each root module is located using the given {@code before} module 263 * finder. If a module is not found then it is located in the parent 264 * configuration as if by invoking the {@link #findModule(String) 265 * findModule} method on each parent in iteration order. If not found then 266 * the module is located using the given {@code after} module finder. The 267 * same search order is used to locate transitive dependences. Root modules 268 * or dependences that are located in a parent configuration are resolved 269 * no further and are not included in the resulting configuration. </p> 270 * 271 * <p> When all modules have been resolved then the resulting dependency 272 * graph is checked to ensure that it does not contain cycles. A 273 * readability graph is constructed, and in conjunction with the module 274 * exports and service use, checked for consistency. </p> 275 * 276 * <p> Resolution may fail with {@code FindException} for the following 277 * <em>observability-related</em> reasons: </p> 278 * 279 * <ul> 280 * 281 * <li><p> A root module, or a direct or transitive dependency, is not 282 * found. </p></li> 283 * 284 * <li><p> An error occurs when attempting to find a module. 285 * Possible errors include I/O errors, errors detected parsing a module 286 * descriptor ({@code module-info.class}) or two versions of the same 287 * module are found in the same directory. </p></li> 288 * 289 * </ul> 290 * 291 * <p> Post-resolution consistency checks may fail with {@code 292 * ResolutionException} for the following reasons: </p> 293 * 294 * <ul> 295 * 296 * <li><p> A cycle is detected, say where module {@code m1} requires 297 * module {@code m2} and {@code m2} requires {@code m1}. </p></li> 298 * 299 * <li><p> A module reads two or more modules with the same name. This 300 * includes the case where a module reads another with the same name as 301 * itself. </p></li> 302 * 303 * <li><p> Two or more modules in the configuration export the same 304 * package to a module that reads both. This includes the case where a 305 * module {@code M} containing package {@code p} reads another module 306 * that exports {@code p} to {@code M}. </p></li> 307 * 308 * <li><p> A module {@code M} declares that it "{@code uses p.S}" or 309 * "{@code provides p.S with ...}" but package {@code p} is neither in 310 * module {@code M} nor exported to {@code M} by any module that 311 * {@code M} reads. </p></li> 312 * 313 * </ul> 314 * 315 * @implNote In the implementation then observability of modules may depend 316 * on referential integrity or other checks that ensure different builds of 317 * tightly coupled modules or modules for specific operating systems or 318 * architectures are not combined in the same configuration. 319 * 320 * @param before 321 * The <em>before</em> module finder to find modules 322 * @param parents 323 * The list parent configurations in search order 324 * @param after 325 * The <em>after</em> module finder to locate modules when not 326 * located by the {@code before} module finder or in parent 327 * configurations 328 * @param roots 329 * The possibly-empty collection of module names of the modules 330 * to resolve 331 * 332 * @return The configuration that is the result of resolving the given 333 * root modules 334 * 335 * @throws FindException 336 * If resolution fails for an observability-related reason 337 * @throws ResolutionException 338 * If a post-resolution consistency checks fails |