001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.util; 020 021import java.io.Closeable; 022import java.io.File; 023import java.io.IOException; 024import java.net.URI; 025import java.net.URL; 026import java.net.URLClassLoader; 027import java.nio.file.DirectoryStream; 028import java.nio.file.FileSystem; 029import java.nio.file.FileSystems; 030import java.nio.file.Files; 031import java.nio.file.Path; 032import java.nio.file.Paths; 033import java.util.ArrayList; 034import java.util.Collections; 035import java.util.List; 036import java.util.Map; 037 038import org.apache.commons.io.IOUtils; 039 040/** 041 * Wraps a Java 9 JEP 220 modular runtime image. Requires the JRT NIO file system. 042 * 043 * @since 6.3 044 */ 045public class ModularRuntimeImage implements Closeable { 046 047 static final String MODULES_PATH = File.separator + "modules"; 048 static final String PACKAGES_PATH = File.separator + "packages"; 049 050 private final URLClassLoader classLoader; 051 private final FileSystem fileSystem; 052 053 /** 054 * Constructs a default instance. 055 */ 056 @SuppressWarnings("resource") // See #close() 057 public ModularRuntimeImage() { 058 this(null, FileSystems.getFileSystem(URI.create("jrt:/"))); 059 } 060 061 /** 062 * Constructs an instance using the JRT file system implementation from a specific Java Home. 063 * 064 * @param javaHome Path to a Java 9 or greater home. 065 * @throws IOException an I/O error occurs accessing the file system 066 */ 067 public ModularRuntimeImage(final String javaHome) throws IOException { 068 final Map<String, ?> emptyMap = Collections.emptyMap(); 069 final Path jrePath = Paths.get(javaHome); 070 final Path jrtFsPath = jrePath.resolve("lib").resolve("jrt-fs.jar"); 071 this.classLoader = URLClassLoader.newInstance(new URL[] {jrtFsPath.toUri().toURL()}); 072 this.fileSystem = FileSystems.newFileSystem(URI.create("jrt:/"), emptyMap, classLoader); 073 } 074 075 private ModularRuntimeImage(final URLClassLoader cl, final FileSystem fs) { 076 this.classLoader = cl; 077 this.fileSystem = fs; 078 } 079 080 @Override 081 public void close() throws IOException { 082 IOUtils.close(classLoader); 083 if (fileSystem != null) { 084 try { 085 fileSystem.close(); 086 } catch (final UnsupportedOperationException e) { 087 // do nothing 088 } 089 } 090 } 091 092 public FileSystem getFileSystem() { 093 return fileSystem; 094 } 095 096 /** 097 * Lists all entries in the given directory. 098 * 099 * @param dirPath directory path. 100 * @return a list of dir entries if an I/O error occurs 101 * @throws IOException an I/O error occurs accessing the file system 102 */ 103 public List<Path> list(final Path dirPath) throws IOException { 104 final List<Path> list = new ArrayList<>(); 105 try (DirectoryStream<Path> ds = Files.newDirectoryStream(dirPath)) { 106 ds.forEach(list::add); 107 } 108 return list; 109 } 110 111 /** 112 * Lists all entries in the given directory. 113 * 114 * @param dirName directory path. 115 * @return a list of dir entries if an I/O error occurs 116 * @throws IOException an I/O error occurs accessing the file system 117 */ 118 public List<Path> list(final String dirName) throws IOException { 119 return list(fileSystem.getPath(dirName)); 120 } 121 122 /** 123 * Lists all modules. 124 * 125 * @return a list of modules 126 * @throws IOException an I/O error occurs accessing the file system 127 */ 128 public List<Path> modules() throws IOException { 129 return list(MODULES_PATH); 130 } 131 132 /** 133 * Lists all packages. 134 * 135 * @return a list of modules 136 * @throws IOException an I/O error occurs accessing the file system 137 */ 138 public List<Path> packages() throws IOException { 139 return list(PACKAGES_PATH); 140 } 141 142}