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