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