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.Closeable;
021import java.io.IOException;
022import java.lang.module.ModuleFinder;
023import java.nio.file.Path;
024import java.util.Collection;
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 * Container that wraps a file path source of some description.
035 *
036 * <p>Closing this resource will close any internally held resources that were opened internally.
037 * Already-opened resources passed to the implementation will not be closed.
038 *
039 * @author Ashley Scopes
040 * @since 0.0.1
041 */
042@API(since = "0.0.1", status = Status.STABLE)
043public interface Container extends Closeable {
044
045  /**
046   * Determine if this container contains the path file object.
047   *
048   * @param fileObject the file object to look up.
049   * @return {@code true} if the object exists in this container, or {@code false} otherwise.
050   */
051  boolean contains(PathFileObject fileObject);
052
053  /**
054   * Find the physical path to a given string file path.
055   *
056   * <p>Examples:
057   *
058   * <pre><code>
059   *   // Using platform-specific separators ('/' for in-memory file systems).
060   *   container.getFile("foo/bar/baz.txt");
061   *
062   *   // Letting JCT infer the correct path separators to use.
063   *   container.getFile("foo", "bar", "baz.txt");
064   * </code></pre>
065   *
066   * @param fragment  the first part of the file name.
067   * @param fragments any additional parts of the file name to find.
068   * @return the path if the file exists, or null if it does not exist.
069   */
070  Path getFile(String fragment, String... fragments);
071
072  /**
073   * Get a {@link FileObject} for reading, if it exists.
074   *
075   * <p>If the file does not exist, {@code null} is returned.
076   *
077   * @param packageName  the package name of the file.
078   * @param relativeName the relative name of the file in the package.
079   * @return the file object, or null if it does not exist.
080   */
081  PathFileObject getFileForInput(String packageName, String relativeName);
082
083  /**
084   * Get a {@link FileObject} for writing.
085   *
086   * <p>If the container is read-only, {@code null} is returned.
087   *
088   * @param packageName  the package name of the file.
089   * @param relativeName the relative name of the file in the package.
090   * @return the file object, or null if this container is read-only.
091   */
092  PathFileObject getFileForOutput(String packageName, String relativeName);
093
094  /**
095   * Get a {@link JavaFileObject} for reading, if it exists.
096   *
097   * <p>If the file does not exist, {@code null} is returned.
098   *
099   * @param className the binary name of the class to open.
100   * @param kind      the kind of file to open.
101   * @return the file object, or null if it does not exist.
102   */
103  PathFileObject getJavaFileForInput(String className, Kind kind);
104
105  /**
106   * Get a {@link JavaFileObject} for writing.
107   *
108   * <p>If the container is read-only, {@code null} is returned.
109   *
110   * @param className the binary name of the class to open.
111   * @param kind      the kind of file to open.
112   * @return the file object, or null if this container is read-only.
113   */
114  PathFileObject getJavaFileForOutput(String className, Kind kind);
115
116  /**
117   * Get the location of this container.
118   *
119   * @return the location.
120   */
121  Location getLocation();
122
123  /**
124   * Get a module finder for this container.
125   *
126   * <p>Note that this will not detect modules that are not yet compiled.
127   *
128   * @return the module finder for this container, or {@code null} if not relevant to the
129   *     implementation.
130   */
131  ModuleFinder getModuleFinder();
132
133  /**
134   * Get the name of this container for human consumption.
135   *
136   * @return the container name.
137   */
138  String getName();
139
140  /**
141   * Get the path root of the container.
142   *
143   * @return the path root.
144   */
145  PathRoot getPathRoot();
146
147  /**
148   * Infer the binary name of a given Java file object.
149   *
150   * @param javaFileObject the Java file object to infer the binary name of.
151   * @return the name, or null if the file does not exist in this container.
152   */
153  String inferBinaryName(PathFileObject javaFileObject);
154
155  /**
156   * List all files within this container.
157   *
158   * @return all files within the container, relative to the container base path.
159   * @throws IOException if the file system failed to be read.
160   */
161  Collection<Path> listAllFiles() throws IOException;
162
163  /**
164   * List all the file objects that match the given criteria in this group.
165   *
166   * <p>The results are filled into a given collection, since this call may be made many times
167   * per compliation, and this reduces the memory overhead needed in such cases.
168   *
169   * @param packageName the package name to look in.
170   * @param kinds       the kinds of file to look for. Set to {@code Set.of(Kind.OTHER)} to find all
171   *                    types of file.
172   * @param recurse     {@code true} to recurse subpackages, {@code false} to only consider the
173   *                    given package.
174   * @param collection  the collection to fill.
175   * @throws IOException if the file system failed to be read.
176   */
177  void listFileObjects(
178      String packageName,
179      Set<? extends Kind> kinds,
180      boolean recurse,
181      Collection<JavaFileObject> collection
182  ) throws IOException;
183}