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