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.IOException; 021import java.nio.file.Path; 022import java.util.Collection; 023import java.util.List; 024import java.util.Map; 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 * Base interface representing a group of package-oriented paths. 035 * 036 * @author Ashley Scopes 037 * @since 0.0.1 038 */ 039@API(since = "0.0.1", status = Status.STABLE) 040public interface PackageContainerGroup extends ContainerGroup { 041 042 /** 043 * Add a container to this group. 044 * 045 * <p>The provided container will be closed when this group is closed. 046 * 047 * @param container the container to add. 048 */ 049 void addPackage(Container container); 050 051 /** 052 * Add a path to this group. 053 * 054 * <p>Note that this will destroy the {@link #getClassLoader() classloader} if one is already 055 * allocated. 056 * 057 * <p>If the path points to some form of archive (such as a JAR), then this may open that archive 058 * in a new resource internally. If this occurs, then the resource will always be freed by this 059 * class by calling {@link #close()}. 060 * 061 * <p>Any other closable resources passed to this function will not be closed by this 062 * implementation. You must handle the lifecycle of those objects yourself. 063 * 064 * @param path the path to add. 065 */ 066 void addPackage(PathRoot path); 067 068 /** 069 * Get a class loader for this group of containers. 070 * 071 * <p>Note that adding additional containers to this group after accessing this class loader 072 * may result in the class loader being destroyed or re-created. 073 * 074 * @return the class loader. 075 */ 076 ClassLoader getClassLoader(); 077 078 /** 079 * Find the first occurrence of a given path to a file in packages or modules. 080 * 081 * <p>Modules are treated as subdirectories. 082 * 083 * <pre><code> 084 * // Using platform-specific separators. 085 * containerGroup.getFile("foo/bar/baz.txt")...; 086 * 087 * // Letting JCT infer the correct path separators to use (recommended). 088 * containerGroup.getFile("foo", "bar", "baz.txt"); 089 * </code></pre> 090 * 091 * @param fragment the first part of the path. 092 * @param fragments any additional parts of the path. 093 * @return the first occurrence of the path in this group, or null if not found. 094 * @throws IllegalArgumentException if the provided path is absolute. 095 */ 096 Path getFile(String fragment, String... fragments); 097 098 /** 099 * Get a {@link FileObject} that can have content read from it. 100 * 101 * <p>This will return {@code null} if no file is found matching the criteria. 102 * 103 * @param packageName the package name of the file to read. 104 * @param relativeName the relative name of the file to read. 105 * @return the file object, or null if the file is not found. 106 */ 107 PathFileObject getFileForInput(String packageName, String relativeName); 108 109 /** 110 * Get a {@link FileObject} that can have content written to it for the given file. 111 * 112 * <p>This will attempt to write to the first writeable path in this group. {@code null} 113 * will be returned if no writeable paths exist in this group. 114 * 115 * @param packageName the name of the package the file is in. 116 * @param relativeName the relative name of the file within the package. 117 * @return the {@link FileObject} to write to, or null if this group has no paths that can be 118 * written to. 119 */ 120 PathFileObject getFileForOutput(String packageName, String relativeName); 121 122 /** 123 * Get a {@link JavaFileObject} that can have content read from it for the given file. 124 * 125 * <p>This will return {@code null} if no file is found matching the criteria. 126 * 127 * @param className the binary name of the class to read. 128 * @param kind the kind of file to read. 129 * @return the {@link JavaFileObject} to write to, or null if this group has no paths that can be 130 * written to. 131 */ 132 PathFileObject getJavaFileForInput(String className, Kind kind); 133 134 /** 135 * Get a {@link JavaFileObject} that can have content written to it for the given class. 136 * 137 * <p>This will attempt to write to the first writeable path in this group. {@code null} 138 * will be returned if no writeable paths exist in this group. 139 * 140 * @param className the name of the class. 141 * @param kind the kind of the class file. 142 * @return the {@link JavaFileObject} to write to, or null if this group has no paths that can be 143 * written to. 144 */ 145 PathFileObject getJavaFileForOutput(String className, Kind kind); 146 147 /** 148 * Get the package-oriented location that this group of paths is for. 149 * 150 * @return the package-oriented location. 151 */ 152 Location getLocation(); 153 154 /** 155 * Get the package containers in this group. 156 * 157 * <p>Returned packages are presented in the order that they were registered. This is the 158 * resolution order that the compiler will use. 159 * 160 * @return the containers. 161 */ 162 List<Container> getPackages(); 163 164 /** 165 * Try to infer the binary name of a given file object. 166 * 167 * @param fileObject the file object to infer the binary name for. 168 * @return the binary name if known, or null otherwise. 169 */ 170 String inferBinaryName(PathFileObject fileObject); 171 172 /** 173 * Determine if this group has no paths registered. 174 * 175 * @return {@code true} if no paths are registered. {@code false} if paths are registered. 176 */ 177 boolean isEmpty(); 178 179 /** 180 * List all the file objects that match the given criteria in this group. 181 * 182 * @param packageName the package name to look in. 183 * @param kinds the kinds of file to look for. 184 * @param recurse {@code true} to recurse subpackages, {@code false} to only consider the 185 * given package. 186 * @return thr file objects that were found. 187 * @throws IOException if the file lookup fails due to an IO error somewhere. 188 */ 189 Set<JavaFileObject> listFileObjects( 190 String packageName, 191 Set<? extends Kind> kinds, 192 boolean recurse 193 ) throws IOException; 194 195 /** 196 * List all files recursively in this container group, returning a multimap of each container and all files 197 * within that container. 198 * 199 * @return a multimap of containers mapping to collections of all files in that container. 200 * @throws IOException if the file lookup fails due to an IO error somewhere. 201 * @since 0.6.0 202 */ 203 @API(since = "0.6.0", status = Status.STABLE) 204 Map<Container, Collection<Path>> listAllFiles() throws IOException; 205}