Re[2]: Add posibility to add custom ModuleReaderFactory to ModuleFinder

Alex Sviridov ooo_saturn7 at mail.ru
Fri Sep 28 14:30:27 UTC 2018


Alan, thank you very much for your help. This is what I was looking for. 
Only one moment - as I  understand the ModuleFinder that you implemented can 
work only with .war modules. However, at one JPMS layer I want to place .war 
modules and .jar modules. What should I do in such situation? Should I do
ModuleFinder commonFinder = ModuleFinder.compose(jarFinder, warFinder);
Configuration cf = boot.configuration().resolve(commonFinder,  ModuleFinder.of(), Set.of(jars+wars)); ?

Best regards, Pavel


>Пятница, 28 сентября 2018, 16:52 +03:00 от Alan Bateman <Alan.Bateman at oracle.com>:
>
>On 28/09/2018 13:10, Alex Sviridov wrote:
>> Hi Alan
>>
>> Thank you for your answer. But my main problem is not jars inside .war 
>> - this is a so far from my current problem. Now I need to 1) add .war 
>> file to layer 2). to map file location, for example instead of 
>> "module-info.java" I must find "WEB-INF/classes/module-info.java" etc. 
>> That is all I need. How can I do it without implementing ModuleFinder?
>You'll need a ModuleFinder because the packaging formats that 
>ModuleFinder.of(Path) is required to support doesn't know anything about 
>WAR files. It's not super difficult to develop your own. I attach a 
>simple implementation that may get you started. It's really basic but 
>would need a few iterations to be robust. Invoke 
>WarModuleFinder.of(Path) with the file path to the WAR file and it will 
>create a ModuleFinder that can find the application module in the WAR 
>file. A more complete implementation would be a lot more robust and 
>polished that this sample, it would also find the modules WEB-INF/lib.
>
>Once you have a ModuleFinder then you specify it to Conguration::resolve 
>method when resolving the application as the root module. You'll 
>probably start with something like:
>
>         Path war = Path.of("app.war");
>         ModuleFinder finder = WarModuleFinder.of(war);
>
>         String appModuleName = finder.findAll().stream()
>                 .findFirst()
>                 .map(ModuleReference::descriptor)
>                 .map(ModuleDescriptor::name)
>                 .orElseThrow();
>
>         ModuleLayer boot = ModuleLayer.boot();
>         Configuration cf = boot.configuration().resolve(finder, 
>ModuleFinder.of(), Set.of(appModuleName));
>         ModuleLayer layer = boot.defineModulesWithOneLoader(cf, 
>ClassLoader.getSystemClassLoader());
>
>and now you have a module layer with the application module loaded from 
>the WEB-INF/classes part of the WAR file.
>
>-Alan
>
>
>     static class WarModuleFinder implements ModuleFinder {
>         private final FileSystem warfs;
>         private final Path classes;
>         private final ModuleReference mref;
>
>         private WarModuleFinder(Path warfile) throws IOException {
>             ClassLoader scl = ClassLoader.getSystemClassLoader();
>             FileSystem fs = FileSystems.newFileSystem(warfile, scl);
>             Path classes = fs.getPath("/WEB-INF/classes");
>
>             ModuleDescriptor descriptor;
>             try (InputStream in = 
>Files.newInputStream(classes.resolve("module-info.class"))) {
>                 descriptor = ModuleDescriptor.read(in, () -> 
>packages(classes));
>             }
>
>             this.warfs = fs;
>             this.classes = classes;
>             this.mref = new ModuleReference(descriptor, classes.toUri()) {
>                 @Override
>                 public ModuleReader open() {
>                     return new WarModuleReader();
>                 }
>                 public String toString() {
>                     StringBuilder sb = new StringBuilder();
>                     sb.append("[module ");
>                     sb.append(descriptor().name());
>                     sb.append(", location=");
>                     sb.append(location());
>                     sb.append("]");
>                     return sb.toString();
>                 }
>             };
>         }
>
>         static WarModuleFinder of(Path war) throws IOException {
>             return new WarModuleFinder(war);
>         }
>
>         @Override
>         public Optional<ModuleReference> find(String name) {
>             if (name.equals(mref.descriptor().name())) {
>                 return Optional.of(mref);
>             } else {
>                 return Optional.empty();
>             }
>         }
>
>         @Override
>         public Set<ModuleReference> findAll() {
>             return Set.of(mref);
>         }
>
>         private Set<String> packages(Path classes) {
>             try {
>                 return Files.find(classes, Integer.MAX_VALUE,
>                                   (path, attrs) -> !attrs.isDirectory())
>                         .map(entry -> classes.relativize(entry).toString())
>                         .map(this::toPackageName)
>                         .flatMap(Optional::stream)
>                         .collect(Collectors.toSet());
>             } catch (IOException ioe) {
>                 throw new UncheckedIOException(ioe);
>             }
>         }
>
>         private Optional<String> toPackageName(String name) {
>             int index = name.lastIndexOf("/");
>             if (index > 0) {
>                 return Optional.of(name.substring(0, 
>index).replace('/', '.'));
>             } else {
>                 return Optional.empty();
>             }
>         }
>
>         class WarModuleReader implements ModuleReader {
>             private volatile boolean closed;
>
>             private void ensureOpen() throws IOException {
>                 if (closed) throw new IOException("ModuleReader is 
>closed");
>             }
>
>             public Optional<URI> find(String name) throws IOException {
>                 ensureOpen();
>                 if (!name.startsWith("/")) {
>                     Path entry = classes.resolve(name);
>                     if (Files.exists(entry)) {
>                         return Optional.of(entry.toUri());
>                     }
>                 }
>                 return Optional.empty();
>             }
>
>             public Stream<String> list() throws IOException {
>                 ensureOpen();
>                 return Files.walk(classes)
>                         .map(entry -> classes.relativize(entry).toString())
>                         .filter(name -> name.length() > 0);
>             }
>
>             public void close() {
>                 closed = true;
>             }
>         }
>     }
>


-- 
Alex Sviridov


More information about the jigsaw-dev mailing list