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.workspaces;
017
018import static io.github.ascopes.jct.utils.IoExceptionUtils.uncheckedIo;
019
020import io.github.ascopes.jct.workspaces.impl.JarFactoryImpl;
021import java.io.ByteArrayOutputStream;
022import java.io.UncheckedIOException;
023import java.net.URI;
024import java.net.URL;
025import java.nio.file.Path;
026import org.apiguardian.api.API;
027import org.apiguardian.api.API.Status;
028import org.jspecify.annotations.Nullable;
029
030/**
031 * A path-like object that can provide a {@link Path Java NIO Path}.
032 *
033 * <p>This enables wrapping various implementations and providers of {@link Path} objects
034 * in a translucent façade that enables representing paths in a hierarchical format.
035 *
036 * @author Ashley Scopes
037 * @since 0.0.1
038 */
039@API(since = "0.0.1", status = Status.STABLE)
040public interface PathRoot {
041
042  /**
043   * Convert the given path root into a JAR and return the byte contents of the JAR.
044   *
045   * <p>You can use this to create JAR files from existing path roots, if you want to package
046   * some compiled outputs into a JAR to use them as inputs to another build.
047   *
048   * @return the byte contents of the JAR.
049   * @throws UncheckedIOException if the JAR cannot be created.
050   * @since 0.4.0
051   */
052  @API(since = "0.4.0", status = Status.STABLE)
053  default byte[] asJar() {
054    // TODO(ascopes): move this to impl level before 1.0.0 ideally.
055    return uncheckedIo(() -> {
056      try (var baos = new ByteArrayOutputStream()) {
057        JarFactoryImpl.getInstance().createJarFrom(baos, getPath());
058        return baos.toByteArray();
059      }
060    });
061  }
062
063  /**
064   * Determine if two path roots are equivalent. If the provided object is {@code null} or not an
065   * instance of a {@link PathRoot}, then this will return {@code false} unless otherwise
066   * specified.
067   *
068   * @param other the object to compare with.
069   * @return {@code true} if semantically equal, or {@code false} otherwise.
070   */
071  @Override
072  boolean equals(@Nullable Object other);
073
074  /**
075   * Determine the hash-code for the object.
076   *
077   * @return the hash code.
078   */
079  @Override
080  int hashCode();
081
082  /**
083   * Get the {@link Path Java NIO Path} for this path-like object.
084   *
085   * @return the path.
086   * @see #getUri()
087   * @see #getUrl()
088   */
089  Path getPath();
090
091  /**
092   * Get a URI representation of this path-like object.
093   *
094   * @return the URI.
095   * @see #getUrl()
096   * @see #getPath()
097   */
098  URI getUri();
099
100  /**
101   * Get a URL representation of this path-like object.
102   *
103   * @return the URL.
104   * @see #getUri()
105   * @see #getPath()
106   */
107  URL getUrl();
108
109  /**
110   * Get the parent path root, if there is one.
111   *
112   * @return the parent path root, or {@code null} if no parent root exists.
113   */
114  PathRoot getParent();
115}