001/* 002 * Copyright (C) 2022 - 2024, the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.github.ascopes.jct.containers; 017 018import io.github.ascopes.jct.filemanagers.PathFileObject; 019import io.github.ascopes.jct.workspaces.PathRoot; 020import java.io.Closeable; 021import java.io.IOException; 022import java.lang.module.ModuleFinder; 023import java.nio.file.Path; 024import java.util.Collection; 025import java.util.Set; 026import javax.tools.FileObject; 027import javax.tools.JavaFileManager.Location; 028import javax.tools.JavaFileObject; 029import javax.tools.JavaFileObject.Kind; 030import org.apiguardian.api.API; 031import org.apiguardian.api.API.Status; 032import org.jspecify.annotations.Nullable; 033 034/** 035 * Container that wraps a file path source of some description. 036 * 037 * <p>Closing this resource will close any internally held resources that were opened internally. 038 * Already-opened resources passed to the implementation will not be closed. 039 * 040 * @author Ashley Scopes 041 * @since 0.0.1 042 */ 043@API(since = "0.0.1", status = Status.STABLE) 044public interface Container extends Closeable { 045 046 /** 047 * Determine if this container contains the path file object. 048 * 049 * @param fileObject the file object to look up. 050 * @return {@code true} if the object exists in this container, or {@code false} otherwise. 051 */ 052 boolean contains(PathFileObject fileObject); 053 054 /** 055 * Find the physical path to a given string file path. 056 * 057 * <p>Examples: 058 * 059 * <pre><code> 060 * // Using platform-specific separators ('/' for in-memory file systems). 061 * container.getFile("foo/bar/baz.txt"); 062 * 063 * // Letting JCT infer the correct path separators to use. 064 * container.getFile("foo", "bar", "baz.txt"); 065 * </code></pre> 066 * 067 * @param fragment the first part of the file name. 068 * @param fragments any additional parts of the file name to find. 069 * @return the path if the file exists, or null if it does not exist. 070 */ 071 @Nullable 072 Path getFile(String fragment, String... fragments); 073 074 /** 075 * Get a {@link FileObject} for reading, if it exists. 076 * 077 * <p>If the file does not exist, {@code null} is returned. 078 * 079 * @param packageName the package name of the file. 080 * @param relativeName the relative name of the file in the package. 081 * @return the file object, or null if it does not exist. 082 */ 083 @Nullable 084 PathFileObject getFileForInput(String packageName, String relativeName); 085 086 /** 087 * Get a {@link FileObject} for writing. 088 * 089 * <p>If the container is read-only, {@code null} is returned. 090 * 091 * @param packageName the package name of the file. 092 * @param relativeName the relative name of the file in the package. 093 * @return the file object, or null if this container is read-only. 094 */ 095 @Nullable 096 PathFileObject getFileForOutput(String packageName, String relativeName); 097 098 /** 099 * Get the inner path root of the container. 100 * 101 * <p>This will usually be the same as the {@link #getPathRoot() path root}, but for archives, 102 * this will point to the root directory of the archive for the virtual file system it is loaded 103 * in, rather than the location of the archive on the original file system. 104 * 105 * <p>It is worth noting that this operation may result in the archive being loaded into memory 106 * eagerly if it uses lazy loading, due to the need to load the archive to be able to determine an 107 * accurate handle to the inner root directory. 108 * 109 * @return the path root. 110 * @since 0.0.6 111 */ 112 @API(since = "0.0.6", status = Status.STABLE) 113 PathRoot getInnerPathRoot(); 114 115 /** 116 * Get a {@link JavaFileObject} for reading, if it exists. 117 * 118 * <p>If the file does not exist, {@code null} is returned. 119 * 120 * @param className the binary name of the class to open. 121 * @param kind the kind of file to open. 122 * @return the file object, or null if it does not exist. 123 */ 124 @Nullable 125 PathFileObject getJavaFileForInput(String className, Kind kind); 126 127 /** 128 * Get a {@link JavaFileObject} for writing. 129 * 130 * <p>If the container is read-only, {@code null} is returned. 131 * 132 * @param className the binary name of the class to open. 133 * @param kind the kind of file to open. 134 * @return the file object, or null if this container is read-only. 135 */ 136 @Nullable 137 PathFileObject getJavaFileForOutput(String className, Kind kind); 138 139 /** 140 * Get the location of this container. 141 * 142 * @return the location. 143 */ 144 Location getLocation(); 145 146 /** 147 * Get a module finder for this container. 148 * 149 * <p>Note that this will not detect modules that are not yet compiled. 150 * 151 * @return the module finder for this container, or {@code null} if not relevant to the 152 * implementation. 153 */ 154 @Nullable 155 ModuleFinder getModuleFinder(); 156 157 /** 158 * Get the name of this container for human consumption. 159 * 160 * @return the container name. 161 */ 162 String getName(); 163 164 /** 165 * Get the path root of the container. 166 * 167 * @return the path root. 168 */ 169 PathRoot getPathRoot(); 170 171 /** 172 * Infer the binary name of a given Java file object. 173 * 174 * @param javaFileObject the Java file object to infer the binary name of. 175 * @return the name, or null if the file does not exist in this container. 176 */ 177 @Nullable 178 String inferBinaryName(PathFileObject javaFileObject); 179 180 /** 181 * List all files within this container. 182 * 183 * @return all files within the container, relative to the container base path. 184 * @throws IOException if the file system failed to be read. 185 */ 186 Collection<Path> listAllFiles() throws IOException; 187 188 /** 189 * List all the file objects that match the given criteria in this group. 190 * 191 * <p>The results are filled into a given collection, since this call may be made many times 192 * per compilation, and this reduces the memory overhead needed in such cases. 193 * 194 * @param packageName the package name to look in. 195 * @param kinds the kinds of file to look for. Set to {@code Set.of(Kind.OTHER)} to find all 196 * types of file. 197 * @param recurse {@code true} to recurse subpackages, {@code false} to only consider the 198 * given package. 199 * @param collection the collection to fill. 200 * @throws IOException if the file system failed to be read. 201 */ 202 void listFileObjects( 203 String packageName, 204 Set<? extends Kind> kinds, 205 boolean recurse, 206 Collection<JavaFileObject> collection 207 ) throws IOException; 208}