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}