1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  *  Unless required by applicable law or agreed to in writing, software
  16  *  distributed under the License is distributed on an "AS IS" BASIS,
  17  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  *  See the License for the specific language governing permissions and
  19  *  limitations under the License.
  20  *
  21  */
  22 package com.sun.org.apache.bcel.internal.util;
  23 
  24 import java.io.Closeable;
  25 import java.io.File;
  26 import java.io.IOException;
  27 import java.net.URI;
  28 import java.net.URL;
  29 import java.net.URLClassLoader;
  30 import java.nio.file.DirectoryStream;
  31 import java.nio.file.FileSystem;
  32 import java.nio.file.FileSystems;
  33 import java.nio.file.Files;
  34 import java.nio.file.Path;
  35 import java.nio.file.Paths;
  36 import java.util.ArrayList;
  37 import java.util.Collections;
  38 import java.util.Iterator;
  39 import java.util.List;
  40 import java.util.Map;
  41 
  42 /**
  43  * Wraps a Java 9 JEP 220 modular runtime image. Requires the JRT NIO file system.
  44  *
  45  * @since 6.3
  46  */
  47 public class ModularRuntimeImage implements Closeable {
  48 
  49     static final String MODULES_PATH = File.separator + "modules";
  50     static final String PACKAGES_PATH = File.separator + "packages";
  51 
  52     private final URLClassLoader classLoader;
  53     private final FileSystem fileSystem;
  54 
  55     /**
  56      * Constructs a default instance.
  57      *
  58      * @throws IOException
  59      *             an I/O error occurs accessing the file system
  60      */
  61     public ModularRuntimeImage() throws IOException {
  62         this(null, FileSystems.getFileSystem(URI.create("jrt:/")));
  63     }
  64 
  65     /**
  66      * Constructs an instance using the JRT file system implementation from a specific Java Home.
  67      *
  68      * @param javaHome
  69      *            Path to a Java 9 or greater home.
  70      *
  71      * @throws IOException
  72      *             an I/O error occurs accessing the file system
  73      */
  74     public ModularRuntimeImage(final String javaHome) throws IOException {
  75         final Map<String, ?> emptyMap = Collections.emptyMap();
  76         final Path jrePath = Paths.get(javaHome);
  77         final Path jrtFsPath = jrePath.resolve("lib").resolve("jrt-fs.jar");
  78         this.classLoader = new URLClassLoader(new URL[] {jrtFsPath.toUri().toURL() });
  79         this.fileSystem = FileSystems.newFileSystem(URI.create("jrt:/"), emptyMap, classLoader);
  80     }
  81 
  82     private ModularRuntimeImage(final URLClassLoader cl, final FileSystem fs) {
  83         this.classLoader = cl;
  84         this.fileSystem = fs;
  85     }
  86 
  87     @Override
  88     public void close() throws IOException {
  89         if (classLoader != null) {
  90             if (classLoader != null) {
  91                 classLoader.close();
  92             }
  93             if (fileSystem != null) {
  94                 fileSystem.close();
  95             }
  96         }
  97     }
  98 
  99     /**
 100      * Lists all entries in the given directory.
 101      *
 102      * @param dirPath
 103      *            directory path.
 104      * @return a list of dir entries if an I/O error occurs
 105      * @throws IOException
 106      *             an I/O error occurs accessing the file system
 107      */
 108     public List<Path> list(final Path dirPath) throws IOException {
 109         final List<Path> list = new ArrayList<>();
 110         try (DirectoryStream<Path> ds = Files.newDirectoryStream(dirPath)) {
 111             final Iterator<Path> iterator = ds.iterator();
 112             while (iterator.hasNext()) {
 113                 list.add(iterator.next());
 114             }
 115         }
 116         return list;
 117     }
 118 
 119     /**
 120      * Lists all entries in the given directory.
 121      *
 122      * @param dirName
 123      *            directory path.
 124      * @return a list of dir entries if an I/O error occurs
 125      * @throws IOException
 126      *             an I/O error occurs accessing the file system
 127      */
 128     public List<Path> list(final String dirName) throws IOException {
 129         return list(fileSystem.getPath(dirName));
 130     }
 131 
 132     /**
 133      * Lists all modules.
 134      *
 135      * @return a list of modules
 136      * @throws IOException
 137      *             an I/O error occurs accessing the file system
 138      */
 139     public List<Path> modules() throws IOException {
 140         return list(MODULES_PATH);
 141     }
 142 
 143     /**
 144      * Lists all packages.
 145      *
 146      * @return a list of modules
 147      * @throws IOException
 148      *             an I/O error occurs accessing the file system
 149      */
 150     public List<Path> packages() throws IOException {
 151         return list(PACKAGES_PATH);
 152     }
 153 
 154     public FileSystem getFileSystem() {
 155         return fileSystem;
 156     }
 157 
 158 }