001/*
002 * MIT License
003 *
004 * Copyright (c) 2023 IntellectualSites
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024package com.intellectualsites.arkitektonika;
025
026import org.jetbrains.annotations.NotNull;
027
028import java.io.File;
029import java.util.Objects;
030import java.util.concurrent.CompletableFuture;
031import java.util.concurrent.ExecutorService;
032import java.util.concurrent.Executors;
033
034/**
035 * Arkitektonika client class
036 *
037 * @author Alexander Söderberg
038 * @version 1.0
039 * @since 2020-06-21
040 */
041@SuppressWarnings("unused")
042public class Arkitektonika {
043
044    /**
045     * Factory used to construct new {@link ApiClient} instances
046     */
047    private static final ClientFactory clientFactory = new ClientFactory();
048
049    private final ApiClient client;
050    private final ExecutorService executorService;
051
052    private Arkitektonika(@NotNull final String url, @NotNull final ApiVersion apiVersion,
053        @NotNull final ExecutorService executorService) {
054        this.client = clientFactory.getClient(apiVersion, url);
055        this.executorService = executorService;
056    }
057
058    /**
059     * Create a new {@link Arkitektonika} {@link Builder builder}
060     *
061     * @return New builder
062     */
063    @NotNull public static Builder builder() {
064        return new Builder();
065    }
066
067    /**
068     * Get the internal {@link ApiClient} instance. It is not recommended
069     * to interact with this client directly.
070     *
071     * @return Internal client
072     */
073    @NotNull public ApiClient getClient() {
074        return this.client;
075    }
076
077    /**
078     * Check if the specified address is compatible with the
079     * Arkitektonika client
080     *
081     * @return Future that completes with the result
082     */
083    @NotNull public CompletableFuture<Boolean> isCompatible() {
084        return this.client.checkCompatibility(this.executorService);
085    }
086
087    /**
088     * Upload the schematic that is contained in a given file
089     * and return the generated access keys
090     *
091     * @param file Schematic File
092     * @return Future that completes with the generated keys
093     */
094    @NotNull public CompletableFuture<SchematicKeys> upload(@NotNull final File file) {
095        return this.client.upload(file, this.executorService);
096    }
097
098    /**
099     * Check the status of a remote schematic
100     *
101     * @param key Schematic access key
102     * @return Future that completes with the resource status
103     */
104    @NotNull public CompletableFuture<ResourceStatus> checkStatus(@NotNull final String key) {
105        return this.client.checkStatus(key, this.executorService);
106    }
107
108    /**
109     * Attempt to delete a schematic from the remote service
110     *
111     * @param key Deletion key
112     * @return Future that completes with the result
113     */
114    @NotNull public CompletableFuture<Boolean> delete(@NotNull final String key) {
115        return this.client.delete(key, this.executorService);
116    }
117
118    /**
119     * Attempt to download a schematic from the remote service
120     *
121     * @param key Download key
122     * @return Future that completes with the result
123     */
124    @NotNull public CompletableFuture<Schematic> download(@NotNull final String key) {
125        return this.client.download(key, this.executorService);
126    }
127
128
129    /**
130     * Builder class for {@link Arkitektonika} instances.
131     *
132     * @see Arkitektonika#builder() to get a new builder instance
133     */
134    public static final class Builder {
135
136        private String url;
137        private ApiVersion version = ApiVersion.V1_0_0;
138        private ExecutorService executorService = Executors.newCachedThreadPool();
139
140        private Builder() {
141        }
142
143        /**
144         * Specify the base URL that the client will interact with
145         *
146         * @param url Arkitektonika URL
147         * @return The builder instance
148         */
149        @NotNull public Builder withUrl(@NotNull final String url) {
150            this.url = Objects.requireNonNull(url);
151            return this;
152        }
153
154        /**
155         * Specify the API version that the remote Arkitektonika instance
156         * uses
157         *
158         * @param version API version
159         * @return The builder instance
160         */
161        @NotNull public Builder withVersion(@NotNull final ApiVersion version) {
162            this.version = Objects.requireNonNull(version);
163            return this;
164        }
165
166        /**
167         * Specify the executor service that should be used by the client
168         *
169         * @param executorService Executor service
170         * @return The builder instance
171         */
172        @NotNull public Builder withExecutorService(
173            @NotNull final ExecutorService executorService) {
174            this.executorService = Objects.requireNonNull(executorService);
175            return this;
176        }
177
178        /**
179         * Initialize the Arkitektonika instance. This will if no URL
180         * has been specified
181         *
182         * @return Created Arkitektonika instance
183         */
184        @NotNull public Arkitektonika build() {
185            if (this.url == null) {
186                throw new NullPointerException("No URL was provided");
187            }
188            return new Arkitektonika(this.url, this.version, this.executorService);
189        }
190
191    }
192
193}