001/* 002 * Copyright (C) 2022 - 2023, 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; 032 033/** 034 * Container that wraps a file path source of some description. 035 * 036 * <p>Closing this resource will close any internally held resources that were opened internally. 037 * Already-opened resources passed to the implementation will not be closed. 038 * 039 * @author Ashley Scopes 040 * @since 0.0.1 041 */ 042@API(since = "0.0.1", status = Status.STABLE) 043public interface Container extends Closeable { 044 045 /** 046 * Determine if this container contains the path file object. 047 * 048 * @param fileObject the file object to look up. 049 * @return {@code true} if the object exists in this container, or {@code false} otherwise. 050 */ 051 boolean contains(PathFileObject fileObject); 052 053 /** 054 * Find the physical path to a given string file path. 055 * 056 * <p>Examples: 057 * 058 * <pre><code> 059 * // Using platform-specific separators ('/' for in-memory file systems). 060 * container.getFile("foo/bar/baz.txt"); 061 * 062 * // Letting JCT infer the correct path separators to use. 063 * container.getFile("foo", "bar", "baz.txt"); 064 * </code></pre> 065 * 066 * @param fragment the first part of the file name. 067 * @param fragments any additional parts of the file name to find. 068 * @return the path if the file exists, or null if it does not exist. 069 */ 070 Path getFile(String fragment, String... fragments); 071 072 /** 073 * Get a {@link FileObject} for reading, if it exists. 074 * 075 * <p>If the file does not exist, {@code null} is returned. 076 * 077 * @param packageName the package name of the file. 078 * @param relativeName the relative name of the file in the package. 079 * @return the file object, or null if it does not exist. 080 */ 081 PathFileObject getFileForInput(String packageName, String relativeName); 082 083 /** 084 * Get a {@link FileObject} for writing. 085 * 086 * <p>If the container is read-only, {@code null} is returned. 087 * 088 * @param packageName the package name of the file. 089 * @param relativeName the relative name of the file in the package. 090 * @return the file object, or null if this container is read-only. 091 */ 092 PathFileObject getFileForOutput(String packageName, String relativeName); 093 094 /** 095 * Get the inner path root of the container. 096 * 097 * <p>This will usually be the same as the {@link #getPathRoot() path root}, but for archives, 098 * this will point to the root directory of the archive for the virtual file system it is loaded 099 * in, rather than the location of the archive on the original file system. 100 * 101 * <p>It is worth noting that this operation may result in the archive being loaded into memory 102 * eagerly if it uses lazy loading, due to the need to load the archive to be able to determine 103 * an accurate handle to the inner root directory. 104 * 105 * @return the path root. 106 * @since 0.0.6 107 */ 108 @API(since = "0.0.6", status = Status.STABLE) 109 PathRoot getInnerPathRoot(); 110 111 /** 112 * Get a {@link JavaFileObject} for reading, if it exists. 113 * 114 * <p>If the file does not exist, {@code null} is returned. 115 * 116 * @param className the binary name of the class to open. 117 * @param kind the kind of file to open. 118 * @return the file object, or null if it does not exist. 119 */ 120 PathFileObject getJavaFileForInput(String className, Kind kind); 121 122 /** 123 * Get a {@link JavaFileObject} for writing. 124 * 125 * <p>If the container is read-only, {@code null} is returned. 126 * 127 * @param className the binary name of the class to open. 128 * @param kind the kind of file to open. 129 * @return the file object, or null if this container is read-only. 130 */ 131 PathFileObject getJavaFileForOutput(String className, Kind kind); 132 133 /** 134 * Get the location of this container. 135 * 136 * @return the location. 137 */ 138 Location getLocation(); 139 140 /** 141 * Get a module finder for this container. 142 * 143 * <p>Note that this will not detect modules that are not yet compiled. 144 * 145 * @return the module finder for this container, or {@code null} if not relevant to the 146 * implementation. 147 */ 148 ModuleFinder getModuleFinder(); 149 150 /** 151 * Get the name of this container for human consumption. 152 * 153 * @return the container name. 154 */ 155 String getName(); 156 157 /** 158 * Get the path root of the container. 159 * 160 * @return the path root. 161 */ 162 PathRoot getPathRoot(); 163 164 /** 165 * Infer the binary name of a given Java file object. 166 * 167 * @param javaFileObject the Java file object to infer the binary name of. 168 * @return the name, or null if the file does not exist in this container. 169 */ 170 String inferBinaryName(PathFileObject javaFileObject); 171 172 /** 173 * List all files within this container. 174 * 175 * @return all files within the container, relative to the container base path. 176 * @throws IOException if the file system failed to be read. 177 */ 178 Collection<Path> listAllFiles() throws IOException; 179 180 /** 181 * List all the file objects that match the given criteria in this group. 182 * 183 * <p>The results are filled into a given collection, since this call may be made many times 184 * per compliation, and this reduces the memory overhead needed in such cases. 185 * 186 * @param packageName the package name to look in. 187 * @param kinds the kinds of file to look for. Set to {@code Set.of(Kind.OTHER)} to find all 188 * types of file. 189 * @param recurse {@code true} to recurse subpackages, {@code false} to only consider the 190 * given package. 191 * @param collection the collection to fill. 192 * @throws IOException if the file system failed to be read. 193 */ 194 void listFileObjects( 195 String packageName, 196 Set<? extends Kind> kinds, 197 boolean recurse, 198 Collection<JavaFileObject> collection 199 ) throws IOException; 200}