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.filemanagers;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.io.OutputStream;
021import java.io.Reader;
022import java.io.Writer;
023import java.net.URI;
024import java.nio.file.NoSuchFileException;
025import java.nio.file.Path;
026import javax.lang.model.element.Modifier;
027import javax.lang.model.element.NestingKind;
028import javax.tools.FileObject;
029import javax.tools.JavaFileManager.Location;
030import javax.tools.JavaFileObject;
031import org.apiguardian.api.API;
032import org.apiguardian.api.API.Status;
033import org.jspecify.annotations.Nullable;
034
035/**
036 * Interface for a path-based {@link JavaFileObject} that points to a path on a file system
037 * somewhere.
038 *
039 * <p>This object will always use UTF-8 encoding when obtaining readers or writers.
040 *
041 * <p>No access level or nesting kind information is provided by this implementation.
042 *
043 * @author Ashley Scopes
044 * @since 1.0.0
045 */
046@API(since = "1.0.0", status = Status.STABLE)
047public interface PathFileObject extends JavaFileObject {
048
049  /**
050   * Timestamp that is returned if the file object has never been modified.
051   */
052  long NOT_MODIFIED = 0L;
053
054  /**
055   * Attempt to delete the file.
056   *
057   * @return {@code true} if the file was deleted, or {@code false} if it was not deleted.
058   */
059  @Override
060  boolean delete();
061
062  /**
063   * Determine if this object equals another.
064   *
065   * @param other the other object to compare with.
066   * @return {@code true} if the other object is also a {@link FileObject} and has the same
067   *     {@link #toUri() URI} as this object, or {@code false} otherwise.
068   */
069  @Override
070  boolean equals(@Nullable Object other);
071
072  /**
073   * Get the absolute path of this file object.
074   *
075   * @return the full path.
076   */
077  Path getAbsolutePath();
078
079  /**
080   * Get the class access level, where appropriate.
081   *
082   * <p>In most implementations, this class will always return {@code null}, since this
083   * information is not readily available without preloading the file in question and parsing it
084   * first.
085   *
086   * <p>At the time of writing, the OpenJDK implementations of the JavaFileObject class
087   * do not provide an implementation for this method either.
088   *
089   * @return the modifier for the access level, or {@code null} if the information is not available.
090   */
091  @Nullable
092  @Override
093  Modifier getAccessLevel();
094
095  /**
096   * Get the inferred binary name of the file object.
097   *
098   * @return the inferred binary name.
099   */
100  String getBinaryName();
101
102  /**
103   * Read the character content of the file into memory and decode it using the default character
104   * set.
105   *
106   * @param ignoreEncodingErrors ignore encoding errors if {@code true}, or throw them otherwise.
107   * @return the character content, encoded as UTF-8.
108   * @throws IOException if an IO error occurs.
109   */
110  @Override
111  String getCharContent(boolean ignoreEncodingErrors) throws IOException;
112
113  /**
114   * Get the kind of the file.
115   *
116   * @return the inferred file kind.
117   */
118  @Override
119  Kind getKind();
120
121  /**
122   * Determine when the file was last modified.
123   *
124   * @return the timestamp in milliseconds since UNIX epoch that the file was last modified at, or
125   *     {@link #NOT_MODIFIED} if unmodified or if the information is not available.
126   */
127  @Override
128  long getLastModified();
129
130  /**
131   * Get the location of this path file object.
132   *
133   * @return the location.
134   */
135  Location getLocation();
136
137  /**
138   * Get the file name as a string.
139   *
140   * @return the name of the file.
141   */
142  @Override
143  String getName();
144
145  /**
146   * Determine the class nesting kind, where appropriate.
147   *
148   * <p>In most implementations, this method will always return {@code null}, since this
149   * information is not readily available without preloading the file in question and parsing it
150   * first.
151   *
152   * <p>At the time of writing, the OpenJDK implementations of the JavaFileObject class
153   * do not provide an implementation for this method either.
154   *
155   * @return the nesting kind, or {@code null} if the information is not available.
156   */
157  @Nullable
158  @Override
159  NestingKind getNestingKind();
160
161  /**
162   * Get the relative path of this file object.
163   *
164   * @return the path of this file object.
165   */
166  Path getRelativePath();
167
168  /**
169   * Get the root path that the package containing this file is nested within.
170   *
171   * @return the root path.
172   */
173  Path getRootPath();
174
175  /**
176   * Determine the hash code for this object.
177   *
178   * @return the hash code for the object.
179   */
180  @Override
181  int hashCode();
182
183  /**
184   * Determine if a given simple name and file kind are compatible with this file object.
185   *
186   * <p>This will perform a case-sensitive check, regardless of the platform that it runs on.
187   *
188   * @param simpleName the simple name of the class to compare to this file.
189   * @param kind       the kind of the class to compare to this file.
190   * @return {@code true} if the simple name and kind are compatible with the current file object
191   *     name, or {@code false} if not.
192   */
193  @Override
194  boolean isNameCompatible(String simpleName, Kind kind);
195
196  /**
197   * Open an input stream into this file.
198   *
199   * <p>This input stream must be closed once finished with, otherwise resources will be leaked.
200   *
201   * <p>The returned implementation will always be buffered when appropriate.
202   *
203   * @return an input stream.
204   * @throws NoSuchFileException if the file does not exist.
205   * @throws IOException         if an IO error occurs.
206   */
207  @Override
208  InputStream openInputStream() throws IOException;
209
210  /**
211   * Open an output stream to this file.
212   *
213   * <p>This will create the file first if it does not already exist. If it does exist, then this
214   * will overwrite the file and truncate it. The parent directories will also be created if they do
215   * not exist.
216   *
217   * <p>This output stream must be closed once finished with, otherwise resources will be leaked.
218   *
219   * <p>The returned implementation will always be buffered when appropriate.
220   *
221   * @return an output stream.
222   * @throws IOException if an IO error occurs.
223   */
224  @Override
225  OutputStream openOutputStream() throws IOException;
226
227  /**
228   * Open a reader to this file using the default charset (UTF-8).
229   *
230   * <p>This reader must be closed once finished with, otherwise resources will be leaked.
231   *
232   * <p>The returned implementation will always be buffered when appropriate.
233   *
234   * @param ignoreEncodingErrors {@code true} to suppress encoding errors, or {@code false} to throw
235   *                             them to the caller.
236   * @return a reader.
237   * @throws NoSuchFileException if the file does not exist.
238   * @throws IOException         if an IO error occurs.
239   */
240  @Override
241  Reader openReader(boolean ignoreEncodingErrors) throws IOException;
242
243  /**
244   * Open a writer to this file using the default charset (UTF-8).
245   *
246   * <p>This will create the file first if it does not already exist. If it does exist, this will
247   * first overwrite the file and truncate it. The parent directories will also be created if they
248   * do not exist.
249   *
250   * <p>This input stream must be closed once finished with, otherwise resources will be leaked.
251   *
252   * <p>The returned implementation will always be buffered when appropriate.
253   *
254   * @return a writer.
255   * @throws IOException if an IO error occurs.
256   */
257  @Override
258  Writer openWriter() throws IOException;
259
260  /**
261   * Get a string representation of this object.
262   *
263   * @return a string representation of this object.
264   */
265  @Override
266  String toString();
267
268  /**
269   * Determine the URI for this file.
270   *
271   * @return the URI for this file object.
272   */
273  @Override
274  URI toUri();
275}