From ed020bfd6ad95f9cc850c6a3ad17f58872d97060 Mon Sep 17 00:00:00 2001 From: SashAwl <98090080+SashAwl@users.noreply.github.com> Date: Thu, 15 Dec 2022 21:42:52 +0300 Subject: [PATCH 1/4] hw_9: created ERD for ordering cloud resourses --- ERD_ordering_cloud_resources.jpg | Bin 0 -> 148369 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ERD_ordering_cloud_resources.jpg diff --git a/ERD_ordering_cloud_resources.jpg b/ERD_ordering_cloud_resources.jpg new file mode 100644 index 0000000000000000000000000000000000000000..daca953846b89342ab0621df020802cd9018197f GIT binary patch literal 148369 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 literal 0 HcmV?d00001 From 682713494b3f08cbdf410b1bd510f5148138e0c9 Mon Sep 17 00:00:00 2001 From: SashAwl <98090080+SashAwl@users.noreply.github.com> Date: Thu, 15 Dec 2022 21:45:36 +0300 Subject: [PATCH 2/4] hw_9: API specification for ordering cloud resources --- openapi.yaml | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 openapi.yaml diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..52a4948 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,153 @@ +openapi: 3.0.0 +info: + title: Заказ облачных ресурсов + version: 0.0.1 +servers: + - url: http://localhost:8080/api/v1/ + description: Dev server +paths: + /clouds: + get: + summary: Метод получения списка заказов на облако + tags: + - Clouds + operationId: getAllClouds + responses: + "200": + description: "Успешный ответ со списком заказов в облаке" + content: + application/json: + schema: + $ref: "#/components/schemas/Clouds" + "default": + description: "Ответ в остальных случаях" + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Метод создания заказа на облако + tags: + - Cloud + operationId: createCloud + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/Cloud" + responses: + "200": + description: "Успешный ответ с одним заказом" + content: + application/json: + schema: + $ref: "#/components/schemas/Cloud" + "default": + description: "Ответ в остальных случаях" + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /clouds{cloud_number}: + get: + summary: Метод получения одного заказа на облако по номеру + tags: + - Clouds + operationId: getCloudByNumber + parameters: + - name: cloud_number + in: path + required: true + description: Номер заказа + schema: + type: string + responses: + "200": + description: "Успешный ответ с одним заказом" + content: + application/json: + schema: + $ref: "#/components/schemas/Cloud" + "default": + description: "Ответ в остальных случаях" + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + delete: + summary: Метод удаления заказа на облако по номеру + tags: + - Clouds + operationId: deleteCloudByNumber + parameters: + - name: cloud_number + in: path + required: true + description: Номер заказа + schema: + type: string + responses: + "200": + description: Успешно удалено + content: + application/json: {} + "default": + description: "Ответ в остальных случаях" + content: + application/json: + schema: + $ref: "#/components/schemas/Error" +components: + schemas: + Cloud: + type: object + required: + - ID_cloud + - ID_client + - OS + - RAM + - ROM + properties: + ID_cloud: + type: string + example: r382m292 + ID_client: + type: string + example: j234l234 + OS: + type: string + enum: + - Windows + - Linux + description: Операционная система сервера + RAM: + type: integer + example: 64 + description: Оперативная память сервера в Гб + ROM: + type: integer + example: 1024 + description: Внутренняя память сервера в Гб + CPU: + type: integer + example: 12497 + description: Процессор сервера (производительность) + Clouds: + type: array + items: + $ref: "#/components/schemas/Cloud" + Error: + type: object + required: + - code_error + - message_error + properties: + code_error: + type: integer + message_error: + type: string + + + + From 0c713001287a572376615f71bf6114957b3430f8 Mon Sep 17 00:00:00 2001 From: SashAwl <98090080+SashAwl@users.noreply.github.com> Date: Thu, 15 Dec 2022 21:49:43 +0300 Subject: [PATCH 3/4] Code for client --- code for client/ApiCallback.java | 61 + code for client/ApiClient.java | 1205 +++++++++++++++++++ code for client/ApiException.java | 89 ++ code for client/ApiResponse.java | 58 + code for client/Configuration.java | 37 + code for client/GzipRequestInterceptor.java | 80 ++ code for client/JSON.java | 363 ++++++ code for client/Pair.java | 50 + code for client/ProgressRequestBody.java | 76 ++ code for client/ProgressResponseBody.java | 75 ++ code for client/StringUtil.java | 53 + code for client/api/CloudApi.java | 181 +++ code for client/api/CloudsApi.java | 420 +++++++ code for client/auth/ApiKeyAuth.java | 73 ++ code for client/auth/Authentication.java | 28 + code for client/auth/HttpBasicAuth.java | 53 + code for client/auth/OAuth.java | 37 + code for client/auth/OAuthFlow.java | 17 + code for client/model/Cloud.java | 247 ++++ code for client/model/Clouds.java | 64 + code for client/model/Error.java | 114 ++ 21 files changed, 3381 insertions(+) create mode 100644 code for client/ApiCallback.java create mode 100644 code for client/ApiClient.java create mode 100644 code for client/ApiException.java create mode 100644 code for client/ApiResponse.java create mode 100644 code for client/Configuration.java create mode 100644 code for client/GzipRequestInterceptor.java create mode 100644 code for client/JSON.java create mode 100644 code for client/Pair.java create mode 100644 code for client/ProgressRequestBody.java create mode 100644 code for client/ProgressResponseBody.java create mode 100644 code for client/StringUtil.java create mode 100644 code for client/api/CloudApi.java create mode 100644 code for client/api/CloudsApi.java create mode 100644 code for client/auth/ApiKeyAuth.java create mode 100644 code for client/auth/Authentication.java create mode 100644 code for client/auth/HttpBasicAuth.java create mode 100644 code for client/auth/OAuth.java create mode 100644 code for client/auth/OAuthFlow.java create mode 100644 code for client/model/Cloud.java create mode 100644 code for client/model/Clouds.java create mode 100644 code for client/model/Error.java diff --git a/code for client/ApiCallback.java b/code for client/ApiCallback.java new file mode 100644 index 0000000..717f764 --- /dev/null +++ b/code for client/ApiCallback.java @@ -0,0 +1,61 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +import java.io.IOException; + +import java.util.Map; +import java.util.List; + +/** + * Callback for asynchronous API call. + * + * @param The return type + */ +public interface ApiCallback { + /** + * This is called when the API call fails. + * + * @param e The exception causing the failure + * @param statusCode Status code of the response if available, otherwise it would be 0 + * @param responseHeaders Headers of the response if available, otherwise it would be null + */ + void onFailure(ApiException e, int statusCode, Map> responseHeaders); + + /** + * This is called when the API call succeeded. + * + * @param result The result deserialized from response + * @param statusCode Status code of the response + * @param responseHeaders Headers of the response + */ + void onSuccess(T result, int statusCode, Map> responseHeaders); + + /** + * This is called when the API upload processing. + * + * @param bytesWritten bytes Written + * @param contentLength content length of request body + * @param done write end + */ + void onUploadProgress(long bytesWritten, long contentLength, boolean done); + + /** + * This is called when the API downlond processing. + * + * @param bytesRead bytes Read + * @param contentLength content lenngth of the response + * @param done Read end + */ + void onDownloadProgress(long bytesRead, long contentLength, boolean done); +} diff --git a/code for client/ApiClient.java b/code for client/ApiClient.java new file mode 100644 index 0000000..aeaeab4 --- /dev/null +++ b/code for client/ApiClient.java @@ -0,0 +1,1205 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +import com.squareup.okhttp.*; +import com.squareup.okhttp.internal.http.HttpMethod; +import com.squareup.okhttp.logging.HttpLoggingInterceptor; +import com.squareup.okhttp.logging.HttpLoggingInterceptor.Level; +import okio.BufferedSink; +import okio.Okio; +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.format.DateTimeFormatter; + +import javax.net.ssl.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.lang.reflect.Type; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.swagger.client.auth.Authentication; +import io.swagger.client.auth.HttpBasicAuth; +import io.swagger.client.auth.ApiKeyAuth; +import io.swagger.client.auth.OAuth; + +public class ApiClient { + + private String basePath = "http://localhost:8080/api/v1/"; + private boolean debugging = false; + private Map defaultHeaderMap = new HashMap(); + private String tempFolderPath = null; + + private Map authentications; + + private DateFormat dateFormat; + private DateFormat datetimeFormat; + private boolean lenientDatetimeFormat; + private int dateLength; + + private InputStream sslCaCert; + private boolean verifyingSsl; + private KeyManager[] keyManagers; + + private OkHttpClient httpClient; + private JSON json; + + private HttpLoggingInterceptor loggingInterceptor; + + /* + * Constructor for ApiClient + */ + public ApiClient() { + httpClient = new OkHttpClient(); + + + verifyingSsl = true; + + json = new JSON(); + + // Set default User-Agent. + setUserAgent("Swagger-Codegen/1.0.0/java"); + + // Setup authentications (key: authentication name, value: authentication). + authentications = new HashMap(); + // Prevent the authentications from being modified. + authentications = Collections.unmodifiableMap(authentications); + } + + /** + * Get base path + * + * @return Baes path + */ + public String getBasePath() { + return basePath; + } + + /** + * Set base path + * + * @param basePath Base path of the URL (e.g http://localhost:8080/api/v1/ + * @return An instance of OkHttpClient + */ + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + /** + * Get HTTP client + * + * @return An instance of OkHttpClient + */ + public OkHttpClient getHttpClient() { + return httpClient; + } + + /** + * Set HTTP client + * + * @param httpClient An instance of OkHttpClient + * @return Api Client + */ + public ApiClient setHttpClient(OkHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Get JSON + * + * @return JSON object + */ + public JSON getJSON() { + return json; + } + + /** + * Set JSON + * + * @param json JSON object + * @return Api client + */ + public ApiClient setJSON(JSON json) { + this.json = json; + return this; + } + + /** + * True if isVerifyingSsl flag is on + * + * @return True if isVerifySsl flag is on + */ + public boolean isVerifyingSsl() { + return verifyingSsl; + } + + /** + * Configure whether to verify certificate and hostname when making https requests. + * Default to true. + * NOTE: Do NOT set to false in production code, otherwise you would face multiple types of cryptographic attacks. + * + * @param verifyingSsl True to verify TLS/SSL connection + * @return ApiClient + */ + public ApiClient setVerifyingSsl(boolean verifyingSsl) { + this.verifyingSsl = verifyingSsl; + applySslSettings(); + return this; + } + + /** + * Get SSL CA cert. + * + * @return Input stream to the SSL CA cert + */ + public InputStream getSslCaCert() { + return sslCaCert; + } + + /** + * Configure the CA certificate to be trusted when making https requests. + * Use null to reset to default. + * + * @param sslCaCert input stream for SSL CA cert + * @return ApiClient + */ + public ApiClient setSslCaCert(InputStream sslCaCert) { + this.sslCaCert = sslCaCert; + applySslSettings(); + return this; + } + + public KeyManager[] getKeyManagers() { + return keyManagers; + } + + /** + * Configure client keys to use for authorization in an SSL session. + * Use null to reset to default. + * + * @param managers The KeyManagers to use + * @return ApiClient + */ + public ApiClient setKeyManagers(KeyManager[] managers) { + this.keyManagers = managers; + applySslSettings(); + return this; + } + + public DateFormat getDateFormat() { + return dateFormat; + } + + public ApiClient setDateFormat(DateFormat dateFormat) { + this.json.setDateFormat(dateFormat); + return this; + } + + public ApiClient setSqlDateFormat(DateFormat dateFormat) { + this.json.setSqlDateFormat(dateFormat); + return this; + } + + public ApiClient setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { + this.json.setOffsetDateTimeFormat(dateFormat); + return this; + } + + public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) { + this.json.setLocalDateFormat(dateFormat); + return this; + } + + public ApiClient setLenientOnJson(boolean lenientOnJson) { + this.json.setLenientOnJson(lenientOnJson); + return this; + } + + /** + * Get authentications (key: authentication name, value: authentication). + * + * @return Map of authentication objects + */ + public Map getAuthentications() { + return authentications; + } + + /** + * Get authentication for the given name. + * + * @param authName The authentication name + * @return The authentication, null if not found + */ + public Authentication getAuthentication(String authName) { + return authentications.get(authName); + } + + /** + * Helper method to set username for the first HTTP basic authentication. + * + * @param username Username + */ + public void setUsername(String username) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setUsername(username); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set password for the first HTTP basic authentication. + * + * @param password Password + */ + public void setPassword(String password) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setPassword(password); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set API key value for the first API key authentication. + * + * @param apiKey API key + */ + public void setApiKey(String apiKey) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKey(apiKey); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set API key prefix for the first API key authentication. + * + * @param apiKeyPrefix API key prefix + */ + public void setApiKeyPrefix(String apiKeyPrefix) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set access token for the first OAuth2 authentication. + * + * @param accessToken Access token + */ + public void setAccessToken(String accessToken) { + for (Authentication auth : authentications.values()) { + if (auth instanceof OAuth) { + ((OAuth) auth).setAccessToken(accessToken); + return; + } + } + throw new RuntimeException("No OAuth2 authentication configured!"); + } + + /** + * Set the User-Agent header's value (by adding to the default header map). + * + * @param userAgent HTTP request's user agent + * @return ApiClient + */ + public ApiClient setUserAgent(String userAgent) { + addDefaultHeader("User-Agent", userAgent); + return this; + } + + /** + * Add a default header. + * + * @param key The header's key + * @param value The header's value + * @return ApiClient + */ + public ApiClient addDefaultHeader(String key, String value) { + defaultHeaderMap.put(key, value); + return this; + } + + /** + * Check that whether debugging is enabled for this API client. + * + * @return True if debugging is enabled, false otherwise. + */ + public boolean isDebugging() { + return debugging; + } + + /** + * Enable/disable debugging for this API client. + * + * @param debugging To enable (true) or disable (false) debugging + * @return ApiClient + */ + public ApiClient setDebugging(boolean debugging) { + if (debugging != this.debugging) { + if (debugging) { + loggingInterceptor = new HttpLoggingInterceptor(); + loggingInterceptor.setLevel(Level.BODY); + httpClient.interceptors().add(loggingInterceptor); + } else { + httpClient.interceptors().remove(loggingInterceptor); + loggingInterceptor = null; + } + } + this.debugging = debugging; + return this; + } + + /** + * The path of temporary folder used to store downloaded files from endpoints + * with file response. The default value is null, i.e. using + * the system's default tempopary folder. + * + * @see createTempFile + * @return Temporary folder path + */ + public String getTempFolderPath() { + return tempFolderPath; + } + + /** + * Set the temporary folder path (for downloading files) + * + * @param tempFolderPath Temporary folder path + * @return ApiClient + */ + public ApiClient setTempFolderPath(String tempFolderPath) { + this.tempFolderPath = tempFolderPath; + return this; + } + + /** + * Get connection timeout (in milliseconds). + * + * @return Timeout in milliseconds + */ + public int getConnectTimeout() { + return httpClient.getConnectTimeout(); + } + + /** + * Sets the connect timeout (in milliseconds). + * A value of 0 means no timeout, otherwise values must be between 1 and + * + * @param connectionTimeout connection timeout in milliseconds + * @return Api client + */ + public ApiClient setConnectTimeout(int connectionTimeout) { + httpClient.setConnectTimeout(connectionTimeout, TimeUnit.MILLISECONDS); + return this; + } + + /** + * Get read timeout (in milliseconds). + * + * @return Timeout in milliseconds + */ + public int getReadTimeout() { + return httpClient.getReadTimeout(); + } + + /** + * Sets the read timeout (in milliseconds). + * A value of 0 means no timeout, otherwise values must be between 1 and + * {@link Integer#MAX_VALUE}. + * + * @param readTimeout read timeout in milliseconds + * @return Api client + */ + public ApiClient setReadTimeout(int readTimeout) { + httpClient.setReadTimeout(readTimeout, TimeUnit.MILLISECONDS); + return this; + } + + /** + * Get write timeout (in milliseconds). + * + * @return Timeout in milliseconds + */ + public int getWriteTimeout() { + return httpClient.getWriteTimeout(); + } + + /** + * Sets the write timeout (in milliseconds). + * A value of 0 means no timeout, otherwise values must be between 1 and + * {@link Integer#MAX_VALUE}. + * + * @param writeTimeout connection timeout in milliseconds + * @return Api client + */ + public ApiClient setWriteTimeout(int writeTimeout) { + httpClient.setWriteTimeout(writeTimeout, TimeUnit.MILLISECONDS); + return this; + } + + /** + * Format the given parameter object into string. + * + * @param param Parameter + * @return String representation of the parameter + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date || param instanceof OffsetDateTime || param instanceof LocalDate) { + //Serialize to json string and remove the " enclosing characters + String jsonStr = json.serialize(param); + return jsonStr.substring(1, jsonStr.length() - 1); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for (Object o : (Collection)param) { + if (b.length() > 0) { + b.append(","); + } + b.append(String.valueOf(o)); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /** + * Formats the specified query parameter to a list containing a single {@code Pair} object. + * + * Note that {@code value} must not be a collection. + * + * @param name The name of the parameter. + * @param value The value of the parameter. + * @return A list containing a single {@code Pair} object. + */ + public List parameterToPair(String name, Object value) { + List params = new ArrayList(); + + // preconditions + if (name == null || name.isEmpty() || value == null || value instanceof Collection) return params; + + params.add(new Pair(name, parameterToString(value))); + return params; + } + + /** + * Formats the specified collection query parameters to a list of {@code Pair} objects. + * + * Note that the values of each of the returned Pair objects are percent-encoded. + * + * @param collectionFormat The collection format of the parameter. + * @param name The name of the parameter. + * @param value The value of the parameter. + * @return A list of {@code Pair} objects. + */ + public List parameterToPairs(String collectionFormat, String name, Collection value) { + List params = new ArrayList(); + + // preconditions + if (name == null || name.isEmpty() || value == null || value.isEmpty()) { + return params; + } + + // create the params based on the collection format + if ("multi".equals(collectionFormat)) { + for (Object item : value) { + params.add(new Pair(name, escapeString(parameterToString(item)))); + } + return params; + } + + // collectionFormat is assumed to be "csv" by default + String delimiter = ","; + + // escape all delimiters except commas, which are URI reserved + // characters + if ("ssv".equals(collectionFormat)) { + delimiter = escapeString(" "); + } else if ("tsv".equals(collectionFormat)) { + delimiter = escapeString("\t"); + } else if ("pipes".equals(collectionFormat)) { + delimiter = escapeString("|"); + } + + StringBuilder sb = new StringBuilder() ; + for (Object item : value) { + sb.append(delimiter); + sb.append(escapeString(parameterToString(item))); + } + + params.add(new Pair(name, sb.substring(delimiter.length()))); + + return params; + } + + /** + * Sanitize filename by removing path. + * e.g. ../../sun.gif becomes sun.gif + * + * @param filename The filename to be sanitized + * @return The sanitized filename + */ + public String sanitizeFilename(String filename) { + return filename.replaceAll(".*[/\\\\]", ""); + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * "* / *" is also default to JSON + * @param mime MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public boolean isJsonMime(String mime) { + String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"; + return mime != null && (mime.matches(jsonMime) || mime.equals("*/*")); + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return The Accept header to use. If the given array is empty, + * null will be returned (not to set the Accept header explicitly). + */ + public String selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } + return StringUtil.join(accepts, ","); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return The Content-Type header to use. If the given array is empty, + * or matches "any", JSON will be used. + */ + public String selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0 || contentTypes[0].equals("*/*")) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } + return contentTypes[0]; + } + + /** + * Escape the given string to be used as URL query value. + * + * @param str String to be escaped + * @return Escaped string + */ + public String escapeString(String str) { + try { + return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20"); + } catch (UnsupportedEncodingException e) { + return str; + } + } + + /** + * Deserialize response body to Java object, according to the return type and + * the Content-Type response header. + * + * @param Type + * @param response HTTP response + * @param returnType The type of the Java object + * @return The deserialized Java object + * @throws ApiException If fail to deserialize response body, i.e. cannot read response body + * or the Content-Type of the response is not supported. + */ + @SuppressWarnings("unchecked") + public T deserialize(Response response, Type returnType) throws ApiException { + if (response == null || returnType == null) { + return null; + } + + if ("byte[]".equals(returnType.toString())) { + // Handle binary response (byte array). + try { + return (T) response.body().bytes(); + } catch (IOException e) { + throw new ApiException(e); + } + } else if (returnType.equals(File.class)) { + // Handle file downloading. + return (T) downloadFileFromResponse(response); + } + + String respBody; + try { + if (response.body() != null) + respBody = response.body().string(); + else + respBody = null; + } catch (IOException e) { + throw new ApiException(e); + } + + if (respBody == null || "".equals(respBody)) { + return null; + } + + String contentType = response.headers().get("Content-Type"); + if (contentType == null) { + // ensuring a default content type + contentType = "application/json"; + } + if (isJsonMime(contentType)) { + return json.deserialize(respBody, returnType); + } else if (returnType.equals(String.class)) { + // Expecting string, return the raw response body. + return (T) respBody; + } else { + throw new ApiException( + "Content type \"" + contentType + "\" is not supported for type: " + returnType, + response.code(), + response.headers().toMultimap(), + respBody); + } + } + + /** + * Serialize the given Java object into request body according to the object's + * class and the request Content-Type. + * + * @param obj The Java object + * @param contentType The request Content-Type + * @return The serialized request body + * @throws ApiException If fail to serialize the given object + */ + public RequestBody serialize(Object obj, String contentType) throws ApiException { + if (obj instanceof byte[]) { + // Binary (byte array) body parameter support. + return RequestBody.create(MediaType.parse(contentType), (byte[]) obj); + } else if (obj instanceof File) { + // File body parameter support. + return RequestBody.create(MediaType.parse(contentType), (File) obj); + } else if (isJsonMime(contentType)) { + String content; + if (obj != null) { + content = json.serialize(obj); + } else { + content = null; + } + return RequestBody.create(MediaType.parse(contentType), content); + } else { + throw new ApiException("Content type \"" + contentType + "\" is not supported"); + } + } + + /** + * Download file from the given response. + * + * @param response An instance of the Response object + * @throws ApiException If fail to read file content from response and write to disk + * @return Downloaded file + */ + public File downloadFileFromResponse(Response response) throws ApiException { + try { + File file = prepareDownloadFile(response); + BufferedSink sink = Okio.buffer(Okio.sink(file)); + sink.writeAll(response.body().source()); + sink.close(); + return file; + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + * Prepare file for download + * + * @param response An instance of the Response object + * @throws IOException If fail to prepare file for download + * @return Prepared file for the download + */ + public File prepareDownloadFile(Response response) throws IOException { + String filename = null; + String contentDisposition = response.header("Content-Disposition"); + if (contentDisposition != null && !"".equals(contentDisposition)) { + // Get filename from the Content-Disposition header. + Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); + Matcher matcher = pattern.matcher(contentDisposition); + if (matcher.find()) { + filename = sanitizeFilename(matcher.group(1)); + } + } + + String prefix = null; + String suffix = null; + if (filename == null) { + prefix = "download-"; + suffix = ""; + } else { + int pos = filename.lastIndexOf("."); + if (pos == -1) { + prefix = filename + "-"; + } else { + prefix = filename.substring(0, pos) + "-"; + suffix = filename.substring(pos); + } + // File.createTempFile requires the prefix to be at least three characters long + if (prefix.length() < 3) + prefix = "download-"; + } + + if (tempFolderPath == null) + return Files.createTempFile(prefix, suffix).toFile(); + else + return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile(); + } + + /** + * {@link #execute(Call, Type)} + * + * @param Type + * @param call An instance of the Call object + * @throws ApiException If fail to execute the call + * @return ApiResponse<T> + */ + public ApiResponse execute(Call call) throws ApiException { + return execute(call, null); + } + + /** + * Execute HTTP call and deserialize the HTTP response body into the given return type. + * + * @param returnType The return type used to deserialize HTTP response body + * @param The return type corresponding to (same with) returnType + * @param call Call + * @return ApiResponse object containing response status, headers and + * data, which is a Java object deserialized from response body and would be null + * when returnType is null. + * @throws ApiException If fail to execute the call + */ + public ApiResponse execute(Call call, Type returnType) throws ApiException { + try { + Response response = call.execute(); + T data = handleResponse(response, returnType); + return new ApiResponse(response.code(), response.headers().toMultimap(), data); + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + * {@link #executeAsync(Call, Type, ApiCallback)} + * + * @param Type + * @param call An instance of the Call object + * @param callback ApiCallback<T> + */ + public void executeAsync(Call call, ApiCallback callback) { + executeAsync(call, null, callback); + } + + /** + * Execute HTTP call asynchronously. + * + * @see #execute(Call, Type) + * @param Type + * @param call The callback to be executed when the API call finishes + * @param returnType Return type + * @param callback ApiCallback + */ + @SuppressWarnings("unchecked") + public void executeAsync(Call call, final Type returnType, final ApiCallback callback) { + call.enqueue(new Callback() { + @Override + public void onFailure(Request request, IOException e) { + callback.onFailure(new ApiException(e), 0, null); + } + + @Override + public void onResponse(Response response) throws IOException { + T result; + try { + result = (T) handleResponse(response, returnType); + } catch (ApiException e) { + callback.onFailure(e, response.code(), response.headers().toMultimap()); + return; + } + callback.onSuccess(result, response.code(), response.headers().toMultimap()); + } + }); + } + + /** + * Handle the given response, return the deserialized object when the response is successful. + * + * @param Type + * @param response Response + * @param returnType Return type + * @throws ApiException If the response has a unsuccessful status code or + * fail to deserialize the response body + * @return Type + */ + public T handleResponse(Response response, Type returnType) throws ApiException { + if (response.isSuccessful()) { + if (returnType == null || response.code() == 204) { + // returning null if the returnType is not defined, + // or the status code is 204 (No Content) + if (response.body() != null) { + try { + response.body().close(); + } catch (IOException e) { + throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap()); + } + } + return null; + } else { + return deserialize(response, returnType); + } + } else { + String respBody = null; + if (response.body() != null) { + try { + respBody = response.body().string(); + } catch (IOException e) { + throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap()); + } + } + throw new ApiException(response.message(), response.code(), response.headers().toMultimap(), respBody); + } + } + + /** + * Build HTTP call with the given options. + * + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE" + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @param body The request body object + * @param headerParams The header parameters + * @param formParams The form parameters + * @param authNames The authentications to apply + * @param progressRequestListener Progress request listener + * @return The HTTP call + * @throws ApiException If fail to serialize the request body object + */ + public Call buildCall(String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + Request request = buildRequest(path, method, queryParams, collectionQueryParams, body, headerParams, formParams, authNames, progressRequestListener); + + return httpClient.newCall(request); + } + + /** + * Build an HTTP request with the given options. + * + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE" + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @param body The request body object + * @param headerParams The header parameters + * @param formParams The form parameters + * @param authNames The authentications to apply + * @param progressRequestListener Progress request listener + * @return The HTTP request + * @throws ApiException If fail to serialize the request body object + */ + public Request buildRequest(String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + updateParamsForAuth(authNames, queryParams, headerParams); + + final String url = buildUrl(path, queryParams, collectionQueryParams); + final Request.Builder reqBuilder = new Request.Builder().url(url); + processHeaderParams(headerParams, reqBuilder); + + String contentType = (String) headerParams.get("Content-Type"); + // ensuring a default content type + if (contentType == null) { + contentType = "application/json"; + } + + RequestBody reqBody; + if (!HttpMethod.permitsRequestBody(method)) { + reqBody = null; + } else if ("application/x-www-form-urlencoded".equals(contentType)) { + reqBody = buildRequestBodyFormEncoding(formParams); + } else if ("multipart/form-data".equals(contentType)) { + reqBody = buildRequestBodyMultipart(formParams); + } else if (body == null) { + if ("DELETE".equals(method)) { + // allow calling DELETE without sending a request body + reqBody = null; + } else { + // use an empty request body (for POST, PUT and PATCH) + reqBody = RequestBody.create(MediaType.parse(contentType), ""); + } + } else { + reqBody = serialize(body, contentType); + } + + Request request = null; + + if(progressRequestListener != null && reqBody != null) { + ProgressRequestBody progressRequestBody = new ProgressRequestBody(reqBody, progressRequestListener); + request = reqBuilder.method(method, progressRequestBody).build(); + } else { + request = reqBuilder.method(method, reqBody).build(); + } + + return request; + } + + /** + * Build full URL by concatenating base path, the given sub path and query parameters. + * + * @param path The sub path + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @return The full URL + */ + public String buildUrl(String path, List queryParams, List collectionQueryParams) { + final StringBuilder url = new StringBuilder(); + url.append(basePath).append(path); + + if (queryParams != null && !queryParams.isEmpty()) { + // support (constant) query string in `path`, e.g. "/posts?draft=1" + String prefix = path.contains("?") ? "&" : "?"; + for (Pair param : queryParams) { + if (param.getValue() != null) { + if (prefix != null) { + url.append(prefix); + prefix = null; + } else { + url.append("&"); + } + String value = parameterToString(param.getValue()); + url.append(escapeString(param.getName())).append("=").append(escapeString(value)); + } + } + } + + if (collectionQueryParams != null && !collectionQueryParams.isEmpty()) { + String prefix = url.toString().contains("?") ? "&" : "?"; + for (Pair param : collectionQueryParams) { + if (param.getValue() != null) { + if (prefix != null) { + url.append(prefix); + prefix = null; + } else { + url.append("&"); + } + String value = parameterToString(param.getValue()); + // collection query parameter value already escaped as part of parameterToPairs + url.append(escapeString(param.getName())).append("=").append(value); + } + } + } + + return url.toString(); + } + + /** + * Set header parameters to the request builder, including default headers. + * + * @param headerParams Header parameters in the ofrm of Map + * @param reqBuilder Reqeust.Builder + */ + public void processHeaderParams(Map headerParams, Request.Builder reqBuilder) { + for (Entry param : headerParams.entrySet()) { + reqBuilder.header(param.getKey(), parameterToString(param.getValue())); + } + for (Entry header : defaultHeaderMap.entrySet()) { + if (!headerParams.containsKey(header.getKey())) { + reqBuilder.header(header.getKey(), parameterToString(header.getValue())); + } + } + } + + /** + * Update query and header parameters based on authentication settings. + * + * @param authNames The authentications to apply + * @param queryParams List of query parameters + * @param headerParams Map of header parameters + */ + public void updateParamsForAuth(String[] authNames, List queryParams, Map headerParams) { + for (String authName : authNames) { + Authentication auth = authentications.get(authName); + if (auth == null) throw new RuntimeException("Authentication undefined: " + authName); + auth.applyToParams(queryParams, headerParams); + } + } + + /** + * Build a form-encoding request body with the given form parameters. + * + * @param formParams Form parameters in the form of Map + * @return RequestBody + */ + public RequestBody buildRequestBodyFormEncoding(Map formParams) { + FormEncodingBuilder formBuilder = new FormEncodingBuilder(); + for (Entry param : formParams.entrySet()) { + formBuilder.add(param.getKey(), parameterToString(param.getValue())); + } + return formBuilder.build(); + } + + /** + * Build a multipart (file uploading) request body with the given form parameters, + * which could contain text fields and file fields. + * + * @param formParams Form parameters in the form of Map + * @return RequestBody + */ + public RequestBody buildRequestBodyMultipart(Map formParams) { + MultipartBuilder mpBuilder = new MultipartBuilder().type(MultipartBuilder.FORM); + for (Entry param : formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + param.getKey() + "\"; filename=\"" + file.getName() + "\""); + MediaType mediaType = MediaType.parse(guessContentTypeFromFile(file)); + mpBuilder.addPart(partHeaders, RequestBody.create(mediaType, file)); + } else { + Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + param.getKey() + "\""); + mpBuilder.addPart(partHeaders, RequestBody.create(null, parameterToString(param.getValue()))); + } + } + return mpBuilder.build(); + } + + /** + * Guess Content-Type header from the given file (defaults to "application/octet-stream"). + * + * @param file The given file + * @return The guessed Content-Type + */ + public String guessContentTypeFromFile(File file) { + String contentType = URLConnection.guessContentTypeFromName(file.getName()); + if (contentType == null) { + return "application/octet-stream"; + } else { + return contentType; + } + } + + /** + * Apply SSL related settings to httpClient according to the current values of + * verifyingSsl and sslCaCert. + */ + private void applySslSettings() { + try { + TrustManager[] trustManagers = null; + HostnameVerifier hostnameVerifier = null; + if (!verifyingSsl) { + TrustManager trustAll = new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} + @Override + public X509Certificate[] getAcceptedIssuers() { return null; } + }; + SSLContext sslContext = SSLContext.getInstance("TLS"); + trustManagers = new TrustManager[]{ trustAll }; + hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { return true; } + }; + } else if (sslCaCert != null) { + char[] password = null; // Any password will work. + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + Collection certificates = certificateFactory.generateCertificates(sslCaCert); + if (certificates.isEmpty()) { + throw new IllegalArgumentException("expected non-empty set of trusted certificates"); + } + KeyStore caKeyStore = newEmptyKeyStore(password); + int index = 0; + for (Certificate certificate : certificates) { + String certificateAlias = "ca" + Integer.toString(index++); + caKeyStore.setCertificateEntry(certificateAlias, certificate); + } + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(caKeyStore); + trustManagers = trustManagerFactory.getTrustManagers(); + } + + if (keyManagers != null || trustManagers != null) { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagers, trustManagers, new SecureRandom()); + httpClient.setSslSocketFactory(sslContext.getSocketFactory()); + } else { + httpClient.setSslSocketFactory(null); + } + httpClient.setHostnameVerifier(hostnameVerifier); + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } + } + + private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException { + try { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, password); + return keyStore; + } catch (IOException e) { + throw new AssertionError(e); + } + } +} diff --git a/code for client/ApiException.java b/code for client/ApiException.java new file mode 100644 index 0000000..f3f0ae8 --- /dev/null +++ b/code for client/ApiException.java @@ -0,0 +1,89 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +import java.util.Map; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]")public class ApiException extends Exception { + private int code = 0; + private Map> responseHeaders = null; + private String responseBody = null; + + public ApiException() {} + + public ApiException(Throwable throwable) { + super(throwable); + } + + public ApiException(String message) { + super(message); + } + + public ApiException(String message, Throwable throwable, int code, Map> responseHeaders, String responseBody) { + super(message, throwable); + this.code = code; + this.responseHeaders = responseHeaders; + this.responseBody = responseBody; + } + + public ApiException(String message, int code, Map> responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } + + public ApiException(String message, Throwable throwable, int code, Map> responseHeaders) { + this(message, throwable, code, responseHeaders, null); + } + + public ApiException(int code, Map> responseHeaders, String responseBody) { + this((String) null, (Throwable) null, code, responseHeaders, responseBody); + } + + public ApiException(int code, String message) { + super(message); + this.code = code; + } + + public ApiException(int code, String message, Map> responseHeaders, String responseBody) { + this(code, message); + this.responseHeaders = responseHeaders; + this.responseBody = responseBody; + } + + /** + * Get the HTTP status code. + * + * @return HTTP status code + */ + public int getCode() { + return code; + } + + /** + * Get the HTTP response headers. + * + * @return A map of list of string + */ + public Map> getResponseHeaders() { + return responseHeaders; + } + + /** + * Get the HTTP response body. + * + * @return Response body in the form of string + */ + public String getResponseBody() { + return responseBody; + } +} diff --git a/code for client/ApiResponse.java b/code for client/ApiResponse.java new file mode 100644 index 0000000..804f7f4 --- /dev/null +++ b/code for client/ApiResponse.java @@ -0,0 +1,58 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +import java.util.List; +import java.util.Map; + +/** + * API response returned by API call. + * + * @param The type of data that is deserialized from response body + */ +public class ApiResponse { + final private int statusCode; + final private Map> headers; + final private T data; + + /** + * @param statusCode The status code of HTTP response + * @param headers The headers of HTTP response + */ + public ApiResponse(int statusCode, Map> headers) { + this(statusCode, headers, null); + } + + /** + * @param statusCode The status code of HTTP response + * @param headers The headers of HTTP response + * @param data The object deserialized from response bod + */ + public ApiResponse(int statusCode, Map> headers, T data) { + this.statusCode = statusCode; + this.headers = headers; + this.data = data; + } + + public int getStatusCode() { + return statusCode; + } + + public Map> getHeaders() { + return headers; + } + + public T getData() { + return data; + } +} diff --git a/code for client/Configuration.java b/code for client/Configuration.java new file mode 100644 index 0000000..d6ec1af --- /dev/null +++ b/code for client/Configuration.java @@ -0,0 +1,37 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]")public class Configuration { + private static ApiClient defaultApiClient = new ApiClient(); + + /** + * Get the default API client, which would be used when creating API + * instances without providing an API client. + * + * @return Default API client + */ + public static ApiClient getDefaultApiClient() { + return defaultApiClient; + } + + /** + * Set the default API client, which would be used when creating API + * instances without providing an API client. + * + * @param apiClient API client + */ + public static void setDefaultApiClient(ApiClient apiClient) { + defaultApiClient = apiClient; + } +} diff --git a/code for client/GzipRequestInterceptor.java b/code for client/GzipRequestInterceptor.java new file mode 100644 index 0000000..0924980 --- /dev/null +++ b/code for client/GzipRequestInterceptor.java @@ -0,0 +1,80 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +import com.squareup.okhttp.*; +import okio.Buffer; +import okio.BufferedSink; +import okio.GzipSink; +import okio.Okio; + +import java.io.IOException; + +/** + * Encodes request bodies using gzip. + * + * Taken from https://github.com/square/okhttp/issues/350 + */ +class GzipRequestInterceptor implements Interceptor { + @Override public Response intercept(Chain chain) throws IOException { + Request originalRequest = chain.request(); + if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) { + return chain.proceed(originalRequest); + } + + Request compressedRequest = originalRequest.newBuilder() + .header("Content-Encoding", "gzip") + .method(originalRequest.method(), forceContentLength(gzip(originalRequest.body()))) + .build(); + return chain.proceed(compressedRequest); + } + + private RequestBody forceContentLength(final RequestBody requestBody) throws IOException { + final Buffer buffer = new Buffer(); + requestBody.writeTo(buffer); + return new RequestBody() { + @Override + public MediaType contentType() { + return requestBody.contentType(); + } + + @Override + public long contentLength() { + return buffer.size(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + sink.write(buffer.snapshot()); + } + }; + } + + private RequestBody gzip(final RequestBody body) { + return new RequestBody() { + @Override public MediaType contentType() { + return body.contentType(); + } + + @Override public long contentLength() { + return -1; // We don't know the compressed length in advance! + } + + @Override public void writeTo(BufferedSink sink) throws IOException { + BufferedSink gzipSink = Okio.buffer(new GzipSink(sink)); + body.writeTo(gzipSink); + gzipSink.close(); + } + }; + } +} \ No newline at end of file diff --git a/code for client/JSON.java b/code for client/JSON.java new file mode 100644 index 0000000..11bc971 --- /dev/null +++ b/code for client/JSON.java @@ -0,0 +1,363 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.gsonfire.GsonFireBuilder; +import io.gsonfire.PostProcessor; +import io.gsonfire.TypeSelector; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.internal.bind.util.ISO8601Utils; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.format.DateTimeFormatter; + +import io.swagger.client.model.*; + +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Type; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Date; +import java.util.Map; +import java.util.HashMap; + +public class JSON { + private Gson gson; + private boolean isLenientOnJson = false; + private DateTypeAdapter dateTypeAdapter = new DateTypeAdapter(); + private SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter(); + private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter(); + private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); + + public static GsonBuilder createGson() { + GsonFireBuilder fireBuilder = new GsonFireBuilder() + ; + return fireBuilder.createGsonBuilder(); + } + + private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) { + JsonElement element = readElement.getAsJsonObject().get(discriminatorField); + if(null == element) { + throw new IllegalArgumentException("missing discriminator field: <" + discriminatorField + ">"); + } + return element.getAsString(); + } + + private static Class getClassByDiscriminator(Map> classByDiscriminatorValue, String discriminatorValue) { + Class clazz = classByDiscriminatorValue.get(discriminatorValue.toUpperCase()); + if(null == clazz) { + throw new IllegalArgumentException("cannot determine model class of name: <" + discriminatorValue + ">"); + } + return clazz; + } + + public JSON() { + gson = createGson() + .registerTypeAdapter(Date.class, dateTypeAdapter) + .registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter) + .registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter) + .registerTypeAdapter(LocalDate.class, localDateTypeAdapter) + .create(); + } + + /** + * Get Gson. + * + * @return Gson + */ + public Gson getGson() { + return gson; + } + + /** + * Set Gson. + * + * @param gson Gson + * @return JSON + */ + public JSON setGson(Gson gson) { + this.gson = gson; + return this; + } + + public JSON setLenientOnJson(boolean lenientOnJson) { + isLenientOnJson = lenientOnJson; + return this; + } + + /** + * Serialize the given Java object into JSON string. + * + * @param obj Object + * @return String representation of the JSON + */ + public String serialize(Object obj) { + return gson.toJson(obj); + } + + /** + * Deserialize the given JSON string to Java object. + * + * @param Type + * @param body The JSON string + * @param returnType The type to deserialize into + * @return The deserialized Java object + */ + @SuppressWarnings("unchecked") + public T deserialize(String body, Type returnType) { + try { + if (isLenientOnJson) { + JsonReader jsonReader = new JsonReader(new StringReader(body)); + // see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean) + jsonReader.setLenient(true); + return gson.fromJson(jsonReader, returnType); + } else { + return gson.fromJson(body, returnType); + } + } catch (JsonParseException e) { + // Fallback processing when failed to parse JSON form response body: + // return the response body string directly for the String return type; + if (returnType.equals(String.class)) + return (T) body; + else throw (e); + } + } + + /** + * Gson TypeAdapter for JSR310 OffsetDateTime type + */ + public static class OffsetDateTimeTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public OffsetDateTimeTypeAdapter() { + this(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + public OffsetDateTimeTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, OffsetDateTime date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public OffsetDateTime read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + if (date.endsWith("+0000")) { + date = date.substring(0, date.length()-5) + "Z"; + } + return OffsetDateTime.parse(date, formatter); + } + } + } + + /** + * Gson TypeAdapter for JSR310 LocalDate type + */ + public class LocalDateTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public LocalDateTypeAdapter() { + this(DateTimeFormatter.ISO_LOCAL_DATE); + } + + public LocalDateTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, LocalDate date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public LocalDate read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return LocalDate.parse(date, formatter); + } + } + } + + public JSON setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { + offsetDateTimeTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setLocalDateFormat(DateTimeFormatter dateFormat) { + localDateTypeAdapter.setFormat(dateFormat); + return this; + } + + /** + * Gson TypeAdapter for java.sql.Date type + * If the dateFormat is null, a simple "yyyy-MM-dd" format will be used + * (more efficient than SimpleDateFormat). + */ + public static class SqlDateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public SqlDateTypeAdapter() { + } + + public SqlDateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, java.sql.Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = date.toString(); + } + out.value(value); + } + } + + @Override + public java.sql.Date read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return new java.sql.Date(dateFormat.parse(date).getTime()); + } + return new java.sql.Date(ISO8601Utils.parse(date, new ParsePosition(0)).getTime()); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } + } + + /** + * Gson TypeAdapter for java.util.Date type + * If the dateFormat is null, ISO8601Utils will be used. + */ + public static class DateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public DateTypeAdapter() { + } + + public DateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = ISO8601Utils.format(date, true); + } + out.value(value); + } + } + + @Override + public Date read(JsonReader in) throws IOException { + try { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return dateFormat.parse(date); + } + return ISO8601Utils.parse(date, new ParsePosition(0)); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } + } + + public JSON setDateFormat(DateFormat dateFormat) { + dateTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setSqlDateFormat(DateFormat dateFormat) { + sqlDateTypeAdapter.setFormat(dateFormat); + return this; + } + +} diff --git a/code for client/Pair.java b/code for client/Pair.java new file mode 100644 index 0000000..6a5ed8b --- /dev/null +++ b/code for client/Pair.java @@ -0,0 +1,50 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]")public class Pair { + private String name = ""; + private String value = ""; + + public Pair (String name, String value) { + setName(name); + setValue(value); + } + + private void setName(String name) { + if (!isValidString(name)) return; + + this.name = name; + } + + private void setValue(String value) { + if (!isValidString(value)) return; + + this.value = value; + } + + public String getName() { + return this.name; + } + + public String getValue() { + return this.value; + } + + private boolean isValidString(String arg) { + if (arg == null) return false; + if (arg.trim().isEmpty()) return false; + + return true; + } +} diff --git a/code for client/ProgressRequestBody.java b/code for client/ProgressRequestBody.java new file mode 100644 index 0000000..8843237 --- /dev/null +++ b/code for client/ProgressRequestBody.java @@ -0,0 +1,76 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.RequestBody; + +import java.io.IOException; + +import okio.Buffer; +import okio.BufferedSink; +import okio.ForwardingSink; +import okio.Okio; +import okio.Sink; + +public class ProgressRequestBody extends RequestBody { + + public interface ProgressRequestListener { + void onRequestProgress(long bytesWritten, long contentLength, boolean done); + } + + private final RequestBody requestBody; + + private final ProgressRequestListener progressListener; + + public ProgressRequestBody(RequestBody requestBody, ProgressRequestListener progressListener) { + this.requestBody = requestBody; + this.progressListener = progressListener; + } + + @Override + public MediaType contentType() { + return requestBody.contentType(); + } + + @Override + public long contentLength() throws IOException { + return requestBody.contentLength(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + BufferedSink bufferedSink = Okio.buffer(sink(sink)); + requestBody.writeTo(bufferedSink); + bufferedSink.flush(); + } + + private Sink sink(Sink sink) { + return new ForwardingSink(sink) { + + long bytesWritten = 0L; + long contentLength = 0L; + + @Override + public void write(Buffer source, long byteCount) throws IOException { + super.write(source, byteCount); + if (contentLength == 0) { + contentLength = contentLength(); + } + + bytesWritten += byteCount; + progressListener.onRequestProgress(bytesWritten, contentLength, bytesWritten == contentLength); + } + }; + } +} diff --git a/code for client/ProgressResponseBody.java b/code for client/ProgressResponseBody.java new file mode 100644 index 0000000..98a20b1 --- /dev/null +++ b/code for client/ProgressResponseBody.java @@ -0,0 +1,75 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.ResponseBody; + +import java.io.IOException; + +import okio.Buffer; +import okio.BufferedSource; +import okio.ForwardingSource; +import okio.Okio; +import okio.Source; + +public class ProgressResponseBody extends ResponseBody { + + public interface ProgressListener { + void update(long bytesRead, long contentLength, boolean done); + } + + private final ResponseBody responseBody; + private final ProgressListener progressListener; + private BufferedSource bufferedSource; + + public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) { + this.responseBody = responseBody; + this.progressListener = progressListener; + } + + @Override + public MediaType contentType() { + return responseBody.contentType(); + } + + @Override + public long contentLength() throws IOException { + return responseBody.contentLength(); + } + + @Override + public BufferedSource source() throws IOException { + if (bufferedSource == null) { + bufferedSource = Okio.buffer(source(responseBody.source())); + } + return bufferedSource; + } + + private Source source(Source source) { + return new ForwardingSource(source) { + long totalBytesRead = 0L; + + @Override + public long read(Buffer sink, long byteCount) throws IOException { + long bytesRead = super.read(sink, byteCount); + // read() returns the number of bytes read, or -1 if this source is exhausted. + totalBytesRead += bytesRead != -1 ? bytesRead : 0; + progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1); + return bytesRead; + } + }; + } +} + + diff --git a/code for client/StringUtil.java b/code for client/StringUtil.java new file mode 100644 index 0000000..a117395 --- /dev/null +++ b/code for client/StringUtil.java @@ -0,0 +1,53 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]")public class StringUtil { + /** + * Check if the given array contains the given value (with case-insensitive comparison). + * + * @param array The array + * @param value The value to search + * @return true if the array contains the value + */ + public static boolean containsIgnoreCase(String[] array, String value) { + for (String str : array) { + if (value == null && str == null) return true; + if (value != null && value.equalsIgnoreCase(str)) return true; + } + return false; + } + + /** + * Join an array of strings with the given separator. + *

+ * Note: This might be replaced by utility method from commons-lang or guava someday + * if one of those libraries is added as dependency. + *

+ * + * @param array The array of strings + * @param separator The separator + * @return the resulting string + */ + public static String join(String[] array, String separator) { + int len = array.length; + if (len == 0) return ""; + + StringBuilder out = new StringBuilder(); + out.append(array[0]); + for (int i = 1; i < len; i++) { + out.append(separator).append(array[i]); + } + return out.toString(); + } +} diff --git a/code for client/api/CloudApi.java b/code for client/api/CloudApi.java new file mode 100644 index 0000000..4cc932c --- /dev/null +++ b/code for client/api/CloudApi.java @@ -0,0 +1,181 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.api; + +import io.swagger.client.ApiCallback; +import io.swagger.client.ApiClient; +import io.swagger.client.ApiException; +import io.swagger.client.ApiResponse; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.ProgressRequestBody; +import io.swagger.client.ProgressResponseBody; + +import com.google.gson.reflect.TypeToken; + +import java.io.IOException; + + +import io.swagger.client.model.Cloud; +import io.swagger.client.model.Error; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CloudApi { + private ApiClient apiClient; + + public CloudApi() { + this(Configuration.getDefaultApiClient()); + } + + public CloudApi(ApiClient apiClient) { + this.apiClient = apiClient; + } + + public ApiClient getApiClient() { + return apiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.apiClient = apiClient; + } + + /** + * Build call for createCloud + * @param body (required) + * @param progressListener Progress listener + * @param progressRequestListener Progress request listener + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + */ + public com.squareup.okhttp.Call createCloudCall(Cloud body, final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + Object localVarPostBody = body; + + // create path and map variables + String localVarPath = "/clouds"; + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + + Map localVarHeaderParams = new HashMap(); + + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) localVarHeaderParams.put("Accept", localVarAccept); + + final String[] localVarContentTypes = { + "application/json" + }; + final String localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + localVarHeaderParams.put("Content-Type", localVarContentType); + + if(progressListener != null) { + apiClient.getHttpClient().networkInterceptors().add(new com.squareup.okhttp.Interceptor() { + @Override + public com.squareup.okhttp.Response intercept(com.squareup.okhttp.Interceptor.Chain chain) throws IOException { + com.squareup.okhttp.Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ProgressResponseBody(originalResponse.body(), progressListener)) + .build(); + } + }); + } + + String[] localVarAuthNames = new String[] { }; + return apiClient.buildCall(localVarPath, "POST", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAuthNames, progressRequestListener); + } + + @SuppressWarnings("rawtypes") + private com.squareup.okhttp.Call createCloudValidateBeforeCall(Cloud body, final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + // verify the required parameter 'body' is set + if (body == null) { + throw new ApiException("Missing the required parameter 'body' when calling createCloud(Async)"); + } + + com.squareup.okhttp.Call call = createCloudCall(body, progressListener, progressRequestListener); + return call; + + + + + + } + + /** + * Метод создания заказа на облако + * + * @param body (required) + * @return Cloud + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public Cloud createCloud(Cloud body) throws ApiException { + ApiResponse resp = createCloudWithHttpInfo(body); + return resp.getData(); + } + + /** + * Метод создания заказа на облако + * + * @param body (required) + * @return ApiResponse<Cloud> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public ApiResponse createCloudWithHttpInfo(Cloud body) throws ApiException { + com.squareup.okhttp.Call call = createCloudValidateBeforeCall(body, null, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return apiClient.execute(call, localVarReturnType); + } + + /** + * Метод создания заказа на облако (asynchronously) + * + * @param body (required) + * @param callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + */ + public com.squareup.okhttp.Call createCloudAsync(Cloud body, final ApiCallback callback) throws ApiException { + + ProgressResponseBody.ProgressListener progressListener = null; + ProgressRequestBody.ProgressRequestListener progressRequestListener = null; + + if (callback != null) { + progressListener = new ProgressResponseBody.ProgressListener() { + @Override + public void update(long bytesRead, long contentLength, boolean done) { + callback.onDownloadProgress(bytesRead, contentLength, done); + } + }; + + progressRequestListener = new ProgressRequestBody.ProgressRequestListener() { + @Override + public void onRequestProgress(long bytesWritten, long contentLength, boolean done) { + callback.onUploadProgress(bytesWritten, contentLength, done); + } + }; + } + + com.squareup.okhttp.Call call = createCloudValidateBeforeCall(body, progressListener, progressRequestListener); + Type localVarReturnType = new TypeToken(){}.getType(); + apiClient.executeAsync(call, localVarReturnType, callback); + return call; + } +} diff --git a/code for client/api/CloudsApi.java b/code for client/api/CloudsApi.java new file mode 100644 index 0000000..97288dd --- /dev/null +++ b/code for client/api/CloudsApi.java @@ -0,0 +1,420 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.api; + +import io.swagger.client.ApiCallback; +import io.swagger.client.ApiClient; +import io.swagger.client.ApiException; +import io.swagger.client.ApiResponse; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.ProgressRequestBody; +import io.swagger.client.ProgressResponseBody; + +import com.google.gson.reflect.TypeToken; + +import java.io.IOException; + + +import io.swagger.client.model.Cloud; +import io.swagger.client.model.Clouds; +import io.swagger.client.model.Error; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CloudsApi { + private ApiClient apiClient; + + public CloudsApi() { + this(Configuration.getDefaultApiClient()); + } + + public CloudsApi(ApiClient apiClient) { + this.apiClient = apiClient; + } + + public ApiClient getApiClient() { + return apiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.apiClient = apiClient; + } + + /** + * Build call for deleteCloudByNumber + * @param cloudNumber Номер заказа (required) + * @param progressListener Progress listener + * @param progressRequestListener Progress request listener + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + */ + public com.squareup.okhttp.Call deleteCloudByNumberCall(String cloudNumber, final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/clouds{cloud_number}" + .replaceAll("\\{" + "cloud_number" + "\\}", apiClient.escapeString(cloudNumber.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + + Map localVarHeaderParams = new HashMap(); + + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) localVarHeaderParams.put("Accept", localVarAccept); + + final String[] localVarContentTypes = { + + }; + final String localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + localVarHeaderParams.put("Content-Type", localVarContentType); + + if(progressListener != null) { + apiClient.getHttpClient().networkInterceptors().add(new com.squareup.okhttp.Interceptor() { + @Override + public com.squareup.okhttp.Response intercept(com.squareup.okhttp.Interceptor.Chain chain) throws IOException { + com.squareup.okhttp.Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ProgressResponseBody(originalResponse.body(), progressListener)) + .build(); + } + }); + } + + String[] localVarAuthNames = new String[] { }; + return apiClient.buildCall(localVarPath, "DELETE", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAuthNames, progressRequestListener); + } + + @SuppressWarnings("rawtypes") + private com.squareup.okhttp.Call deleteCloudByNumberValidateBeforeCall(String cloudNumber, final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + // verify the required parameter 'cloudNumber' is set + if (cloudNumber == null) { + throw new ApiException("Missing the required parameter 'cloudNumber' when calling deleteCloudByNumber(Async)"); + } + + com.squareup.okhttp.Call call = deleteCloudByNumberCall(cloudNumber, progressListener, progressRequestListener); + return call; + + + + + + } + + /** + * Метод удаления заказа на облако по номеру + * + * @param cloudNumber Номер заказа (required) + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public void deleteCloudByNumber(String cloudNumber) throws ApiException { + deleteCloudByNumberWithHttpInfo(cloudNumber); + } + + /** + * Метод удаления заказа на облако по номеру + * + * @param cloudNumber Номер заказа (required) + * @return ApiResponse<Void> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public ApiResponse deleteCloudByNumberWithHttpInfo(String cloudNumber) throws ApiException { + com.squareup.okhttp.Call call = deleteCloudByNumberValidateBeforeCall(cloudNumber, null, null); + return apiClient.execute(call); + } + + /** + * Метод удаления заказа на облако по номеру (asynchronously) + * + * @param cloudNumber Номер заказа (required) + * @param callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + */ + public com.squareup.okhttp.Call deleteCloudByNumberAsync(String cloudNumber, final ApiCallback callback) throws ApiException { + + ProgressResponseBody.ProgressListener progressListener = null; + ProgressRequestBody.ProgressRequestListener progressRequestListener = null; + + if (callback != null) { + progressListener = new ProgressResponseBody.ProgressListener() { + @Override + public void update(long bytesRead, long contentLength, boolean done) { + callback.onDownloadProgress(bytesRead, contentLength, done); + } + }; + + progressRequestListener = new ProgressRequestBody.ProgressRequestListener() { + @Override + public void onRequestProgress(long bytesWritten, long contentLength, boolean done) { + callback.onUploadProgress(bytesWritten, contentLength, done); + } + }; + } + + com.squareup.okhttp.Call call = deleteCloudByNumberValidateBeforeCall(cloudNumber, progressListener, progressRequestListener); + apiClient.executeAsync(call, callback); + return call; + } + /** + * Build call for getAllClouds + * @param progressListener Progress listener + * @param progressRequestListener Progress request listener + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + */ + public com.squareup.okhttp.Call getAllCloudsCall(final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/clouds"; + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + + Map localVarHeaderParams = new HashMap(); + + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) localVarHeaderParams.put("Accept", localVarAccept); + + final String[] localVarContentTypes = { + + }; + final String localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + localVarHeaderParams.put("Content-Type", localVarContentType); + + if(progressListener != null) { + apiClient.getHttpClient().networkInterceptors().add(new com.squareup.okhttp.Interceptor() { + @Override + public com.squareup.okhttp.Response intercept(com.squareup.okhttp.Interceptor.Chain chain) throws IOException { + com.squareup.okhttp.Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ProgressResponseBody(originalResponse.body(), progressListener)) + .build(); + } + }); + } + + String[] localVarAuthNames = new String[] { }; + return apiClient.buildCall(localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAuthNames, progressRequestListener); + } + + @SuppressWarnings("rawtypes") + private com.squareup.okhttp.Call getAllCloudsValidateBeforeCall(final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + + com.squareup.okhttp.Call call = getAllCloudsCall(progressListener, progressRequestListener); + return call; + + + + + + } + + /** + * Метод получения списка заказов на облако + * + * @return Clouds + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public Clouds getAllClouds() throws ApiException { + ApiResponse resp = getAllCloudsWithHttpInfo(); + return resp.getData(); + } + + /** + * Метод получения списка заказов на облако + * + * @return ApiResponse<Clouds> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public ApiResponse getAllCloudsWithHttpInfo() throws ApiException { + com.squareup.okhttp.Call call = getAllCloudsValidateBeforeCall(null, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return apiClient.execute(call, localVarReturnType); + } + + /** + * Метод получения списка заказов на облако (asynchronously) + * + * @param callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + */ + public com.squareup.okhttp.Call getAllCloudsAsync(final ApiCallback callback) throws ApiException { + + ProgressResponseBody.ProgressListener progressListener = null; + ProgressRequestBody.ProgressRequestListener progressRequestListener = null; + + if (callback != null) { + progressListener = new ProgressResponseBody.ProgressListener() { + @Override + public void update(long bytesRead, long contentLength, boolean done) { + callback.onDownloadProgress(bytesRead, contentLength, done); + } + }; + + progressRequestListener = new ProgressRequestBody.ProgressRequestListener() { + @Override + public void onRequestProgress(long bytesWritten, long contentLength, boolean done) { + callback.onUploadProgress(bytesWritten, contentLength, done); + } + }; + } + + com.squareup.okhttp.Call call = getAllCloudsValidateBeforeCall(progressListener, progressRequestListener); + Type localVarReturnType = new TypeToken(){}.getType(); + apiClient.executeAsync(call, localVarReturnType, callback); + return call; + } + /** + * Build call for getCloudByNumber + * @param cloudNumber Номер заказа (required) + * @param progressListener Progress listener + * @param progressRequestListener Progress request listener + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + */ + public com.squareup.okhttp.Call getCloudByNumberCall(String cloudNumber, final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/clouds{cloud_number}" + .replaceAll("\\{" + "cloud_number" + "\\}", apiClient.escapeString(cloudNumber.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + + Map localVarHeaderParams = new HashMap(); + + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) localVarHeaderParams.put("Accept", localVarAccept); + + final String[] localVarContentTypes = { + + }; + final String localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + localVarHeaderParams.put("Content-Type", localVarContentType); + + if(progressListener != null) { + apiClient.getHttpClient().networkInterceptors().add(new com.squareup.okhttp.Interceptor() { + @Override + public com.squareup.okhttp.Response intercept(com.squareup.okhttp.Interceptor.Chain chain) throws IOException { + com.squareup.okhttp.Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ProgressResponseBody(originalResponse.body(), progressListener)) + .build(); + } + }); + } + + String[] localVarAuthNames = new String[] { }; + return apiClient.buildCall(localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAuthNames, progressRequestListener); + } + + @SuppressWarnings("rawtypes") + private com.squareup.okhttp.Call getCloudByNumberValidateBeforeCall(String cloudNumber, final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + // verify the required parameter 'cloudNumber' is set + if (cloudNumber == null) { + throw new ApiException("Missing the required parameter 'cloudNumber' when calling getCloudByNumber(Async)"); + } + + com.squareup.okhttp.Call call = getCloudByNumberCall(cloudNumber, progressListener, progressRequestListener); + return call; + + + + + + } + + /** + * Метод получения одного заказа на облако по номеру + * + * @param cloudNumber Номер заказа (required) + * @return Cloud + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public Cloud getCloudByNumber(String cloudNumber) throws ApiException { + ApiResponse resp = getCloudByNumberWithHttpInfo(cloudNumber); + return resp.getData(); + } + + /** + * Метод получения одного заказа на облако по номеру + * + * @param cloudNumber Номер заказа (required) + * @return ApiResponse<Cloud> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public ApiResponse getCloudByNumberWithHttpInfo(String cloudNumber) throws ApiException { + com.squareup.okhttp.Call call = getCloudByNumberValidateBeforeCall(cloudNumber, null, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return apiClient.execute(call, localVarReturnType); + } + + /** + * Метод получения одного заказа на облако по номеру (asynchronously) + * + * @param cloudNumber Номер заказа (required) + * @param callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + */ + public com.squareup.okhttp.Call getCloudByNumberAsync(String cloudNumber, final ApiCallback callback) throws ApiException { + + ProgressResponseBody.ProgressListener progressListener = null; + ProgressRequestBody.ProgressRequestListener progressRequestListener = null; + + if (callback != null) { + progressListener = new ProgressResponseBody.ProgressListener() { + @Override + public void update(long bytesRead, long contentLength, boolean done) { + callback.onDownloadProgress(bytesRead, contentLength, done); + } + }; + + progressRequestListener = new ProgressRequestBody.ProgressRequestListener() { + @Override + public void onRequestProgress(long bytesWritten, long contentLength, boolean done) { + callback.onUploadProgress(bytesWritten, contentLength, done); + } + }; + } + + com.squareup.okhttp.Call call = getCloudByNumberValidateBeforeCall(cloudNumber, progressListener, progressRequestListener); + Type localVarReturnType = new TypeToken(){}.getType(); + apiClient.executeAsync(call, localVarReturnType, callback); + return call; + } +} diff --git a/code for client/auth/ApiKeyAuth.java b/code for client/auth/ApiKeyAuth.java new file mode 100644 index 0000000..a543275 --- /dev/null +++ b/code for client/auth/ApiKeyAuth.java @@ -0,0 +1,73 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.auth; + +import io.swagger.client.Pair; + +import java.util.Map; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]")public class ApiKeyAuth implements Authentication { + private final String location; + private final String paramName; + + private String apiKey; + private String apiKeyPrefix; + + public ApiKeyAuth(String location, String paramName) { + this.location = location; + this.paramName = paramName; + } + + public String getLocation() { + return location; + } + + public String getParamName() { + return paramName; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getApiKeyPrefix() { + return apiKeyPrefix; + } + + public void setApiKeyPrefix(String apiKeyPrefix) { + this.apiKeyPrefix = apiKeyPrefix; + } + + @Override + public void applyToParams(List queryParams, Map headerParams) { + if (apiKey == null) { + return; + } + String value; + if (apiKeyPrefix != null) { + value = apiKeyPrefix + " " + apiKey; + } else { + value = apiKey; + } + if ("query".equals(location)) { + queryParams.add(new Pair(paramName, value)); + } else if ("header".equals(location)) { + headerParams.put(paramName, value); + } + } +} diff --git a/code for client/auth/Authentication.java b/code for client/auth/Authentication.java new file mode 100644 index 0000000..de8726f --- /dev/null +++ b/code for client/auth/Authentication.java @@ -0,0 +1,28 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.auth; + +import io.swagger.client.Pair; + +import java.util.Map; +import java.util.List; + +public interface Authentication { + /** + * Apply authentication settings to header and query params. + * + * @param queryParams List of query parameters + * @param headerParams Map of header parameters + */ + void applyToParams(List queryParams, Map headerParams); +} diff --git a/code for client/auth/HttpBasicAuth.java b/code for client/auth/HttpBasicAuth.java new file mode 100644 index 0000000..152962a --- /dev/null +++ b/code for client/auth/HttpBasicAuth.java @@ -0,0 +1,53 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.auth; + +import io.swagger.client.Pair; + +import com.squareup.okhttp.Credentials; + +import java.util.Map; +import java.util.List; + +import java.io.UnsupportedEncodingException; + +public class HttpBasicAuth implements Authentication { + private String username; + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public void applyToParams(List queryParams, Map headerParams) { + if (username == null && password == null) { + return; + } + headerParams.put("Authorization", Credentials.basic( + username == null ? "" : username, + password == null ? "" : password)); + } +} diff --git a/code for client/auth/OAuth.java b/code for client/auth/OAuth.java new file mode 100644 index 0000000..a3f6d27 --- /dev/null +++ b/code for client/auth/OAuth.java @@ -0,0 +1,37 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.auth; + +import io.swagger.client.Pair; + +import java.util.Map; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]")public class OAuth implements Authentication { + private String accessToken; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public void applyToParams(List queryParams, Map headerParams) { + if (accessToken != null) { + headerParams.put("Authorization", "Bearer " + accessToken); + } + } +} diff --git a/code for client/auth/OAuthFlow.java b/code for client/auth/OAuthFlow.java new file mode 100644 index 0000000..d6b4a52 --- /dev/null +++ b/code for client/auth/OAuthFlow.java @@ -0,0 +1,17 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.auth; + +public enum OAuthFlow { + accessCode, implicit, password, application +} diff --git a/code for client/model/Cloud.java b/code for client/model/Cloud.java new file mode 100644 index 0000000..119e741 --- /dev/null +++ b/code for client/model/Cloud.java @@ -0,0 +1,247 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.model; + +import java.util.Objects; +import java.util.Arrays; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.IOException; +/** + * Cloud + */ + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]") +public class Cloud { + @SerializedName("ID_cloud") + private String idCloud = null; + + @SerializedName("ID_client") + private String idClient = null; + + /** + * Операционная система сервера + */ + @JsonAdapter(OSEnum.Adapter.class) + public enum OSEnum { + WINDOWS("Windows"), + LINUX("Linux"); + + private String value; + + OSEnum(String value) { + this.value = value; + } + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + public static OSEnum fromValue(String input) { + for (OSEnum b : OSEnum.values()) { + if (b.value.equals(input)) { + return b; + } + } + return null; + } + public static class Adapter extends TypeAdapter { + @Override + public void write(final JsonWriter jsonWriter, final OSEnum enumeration) throws IOException { + jsonWriter.value(String.valueOf(enumeration.getValue())); + } + + @Override + public OSEnum read(final JsonReader jsonReader) throws IOException { + Object value = jsonReader.nextString(); + return OSEnum.fromValue((String)(value)); + } + } + } @SerializedName("OS") + private OSEnum OS = null; + + @SerializedName("RAM") + private Integer RAM = null; + + @SerializedName("ROM") + private Integer ROM = null; + + @SerializedName("CPU") + private Integer CPU = null; + + public Cloud idCloud(String idCloud) { + this.idCloud = idCloud; + return this; + } + + /** + * Get idCloud + * @return idCloud + **/ + @Schema(example = "r382m292", required = true, description = "") + public String getIdCloud() { + return idCloud; + } + + public void setIdCloud(String idCloud) { + this.idCloud = idCloud; + } + + public Cloud idClient(String idClient) { + this.idClient = idClient; + return this; + } + + /** + * Get idClient + * @return idClient + **/ + @Schema(example = "j234l234", required = true, description = "") + public String getIdClient() { + return idClient; + } + + public void setIdClient(String idClient) { + this.idClient = idClient; + } + + public Cloud OS(OSEnum OS) { + this.OS = OS; + return this; + } + + /** + * Операционная система сервера + * @return OS + **/ + @Schema(required = true, description = "Операционная система сервера") + public OSEnum getOS() { + return OS; + } + + public void setOS(OSEnum OS) { + this.OS = OS; + } + + public Cloud RAM(Integer RAM) { + this.RAM = RAM; + return this; + } + + /** + * Оперативная память сервера + * @return RAM + **/ + @Schema(example = "64", required = true, description = "Оперативная память сервера") + public Integer getRAM() { + return RAM; + } + + public void setRAM(Integer RAM) { + this.RAM = RAM; + } + + public Cloud ROM(Integer ROM) { + this.ROM = ROM; + return this; + } + + /** + * Внутренняя память сервера + * @return ROM + **/ + @Schema(example = "1024", required = true, description = "Внутренняя память сервера") + public Integer getROM() { + return ROM; + } + + public void setROM(Integer ROM) { + this.ROM = ROM; + } + + public Cloud CPU(Integer CPU) { + this.CPU = CPU; + return this; + } + + /** + * Процессор сервера + * @return CPU + **/ + @Schema(example = "12497", description = "Процессор сервера") + public Integer getCPU() { + return CPU; + } + + public void setCPU(Integer CPU) { + this.CPU = CPU; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Cloud cloud = (Cloud) o; + return Objects.equals(this.idCloud, cloud.idCloud) && + Objects.equals(this.idClient, cloud.idClient) && + Objects.equals(this.OS, cloud.OS) && + Objects.equals(this.RAM, cloud.RAM) && + Objects.equals(this.ROM, cloud.ROM) && + Objects.equals(this.CPU, cloud.CPU); + } + + @Override + public int hashCode() { + return Objects.hash(idCloud, idClient, OS, RAM, ROM, CPU); + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Cloud {\n"); + + sb.append(" idCloud: ").append(toIndentedString(idCloud)).append("\n"); + sb.append(" idClient: ").append(toIndentedString(idClient)).append("\n"); + sb.append(" OS: ").append(toIndentedString(OS)).append("\n"); + sb.append(" RAM: ").append(toIndentedString(RAM)).append("\n"); + sb.append(" ROM: ").append(toIndentedString(ROM)).append("\n"); + sb.append(" CPU: ").append(toIndentedString(CPU)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} diff --git a/code for client/model/Clouds.java b/code for client/model/Clouds.java new file mode 100644 index 0000000..37e9fa2 --- /dev/null +++ b/code for client/model/Clouds.java @@ -0,0 +1,64 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.client.model.Cloud; +import java.util.ArrayList; +import java.util.List; +/** + * Clouds + */ + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]") +public class Clouds extends ArrayList { + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return super.equals(o); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Clouds {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} diff --git a/code for client/model/Error.java b/code for client/model/Error.java new file mode 100644 index 0000000..0e62103 --- /dev/null +++ b/code for client/model/Error.java @@ -0,0 +1,114 @@ +/* + * Заказ облачных ресурсов + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 0.0.1 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package io.swagger.client.model; + +import java.util.Objects; +import java.util.Arrays; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.IOException; +/** + * Error + */ + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2022-12-15T18:05:27.749Z[GMT]") +public class Error { + @SerializedName("code_error") + private Integer codeError = null; + + @SerializedName("message_error") + private String messageError = null; + + public Error codeError(Integer codeError) { + this.codeError = codeError; + return this; + } + + /** + * Get codeError + * @return codeError + **/ + @Schema(required = true, description = "") + public Integer getCodeError() { + return codeError; + } + + public void setCodeError(Integer codeError) { + this.codeError = codeError; + } + + public Error messageError(String messageError) { + this.messageError = messageError; + return this; + } + + /** + * Get messageError + * @return messageError + **/ + @Schema(required = true, description = "") + public String getMessageError() { + return messageError; + } + + public void setMessageError(String messageError) { + this.messageError = messageError; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Error error = (Error) o; + return Objects.equals(this.codeError, error.codeError) && + Objects.equals(this.messageError, error.messageError); + } + + @Override + public int hashCode() { + return Objects.hash(codeError, messageError); + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Error {\n"); + + sb.append(" codeError: ").append(toIndentedString(codeError)).append("\n"); + sb.append(" messageError: ").append(toIndentedString(messageError)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} From 11c0694751b633ef7140eb56c5467bb20bf2806b Mon Sep 17 00:00:00 2001 From: SashAwl <98090080+SashAwl@users.noreply.github.com> Date: Thu, 15 Dec 2022 21:51:09 +0300 Subject: [PATCH 4/4] Code for server --- code for server/RFC3339DateFormat.java | 22 ++ code for server/Swagger2SpringBoot.java | 52 ++++ code for server/api/ApiException.java | 10 + code for server/api/ApiOriginFilter.java | 27 ++ code for server/api/ApiResponseMessage.java | 69 +++++ code for server/api/CloudsApi.java | 64 +++++ code for server/api/CloudsApiController.java | 81 ++++++ code for server/api/CloudscloudNumberApi.java | 62 +++++ .../api/CloudscloudNumberApiController.java | 71 ++++++ code for server/api/NotFoundException.java | 10 + .../CustomInstantDeserializer.java | 232 +++++++++++++++++ .../configuration/HomeController.java | 16 ++ .../configuration/JacksonConfiguration.java | 23 ++ .../configuration/LocalDateConverter.java | 21 ++ .../configuration/LocalDateTimeConverter.java | 21 ++ .../SwaggerDocumentationConfig.java | 58 +++++ .../configuration/SwaggerUiConfiguration.java | 23 ++ code for server/model/Cloud.java | 235 ++++++++++++++++++ code for server/model/Clouds.java | 55 ++++ code for server/model/Error.java | 105 ++++++++ 20 files changed, 1257 insertions(+) create mode 100644 code for server/RFC3339DateFormat.java create mode 100644 code for server/Swagger2SpringBoot.java create mode 100644 code for server/api/ApiException.java create mode 100644 code for server/api/ApiOriginFilter.java create mode 100644 code for server/api/ApiResponseMessage.java create mode 100644 code for server/api/CloudsApi.java create mode 100644 code for server/api/CloudsApiController.java create mode 100644 code for server/api/CloudscloudNumberApi.java create mode 100644 code for server/api/CloudscloudNumberApiController.java create mode 100644 code for server/api/NotFoundException.java create mode 100644 code for server/configuration/CustomInstantDeserializer.java create mode 100644 code for server/configuration/HomeController.java create mode 100644 code for server/configuration/JacksonConfiguration.java create mode 100644 code for server/configuration/LocalDateConverter.java create mode 100644 code for server/configuration/LocalDateTimeConverter.java create mode 100644 code for server/configuration/SwaggerDocumentationConfig.java create mode 100644 code for server/configuration/SwaggerUiConfiguration.java create mode 100644 code for server/model/Cloud.java create mode 100644 code for server/model/Clouds.java create mode 100644 code for server/model/Error.java diff --git a/code for server/RFC3339DateFormat.java b/code for server/RFC3339DateFormat.java new file mode 100644 index 0000000..538b6f2 --- /dev/null +++ b/code for server/RFC3339DateFormat.java @@ -0,0 +1,22 @@ +package io.swagger; + +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; +import com.fasterxml.jackson.databind.util.ISO8601Utils; + +import java.text.FieldPosition; +import java.util.Date; + + +public class RFC3339DateFormat extends ISO8601DateFormat { + + private static final long serialVersionUID = 1L; + + // Same as ISO8601DateFormat but serializing milliseconds. + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + String value = ISO8601Utils.format(date, true); + toAppendTo.append(value); + return toAppendTo; + } + +} \ No newline at end of file diff --git a/code for server/Swagger2SpringBoot.java b/code for server/Swagger2SpringBoot.java new file mode 100644 index 0000000..c6ccccb --- /dev/null +++ b/code for server/Swagger2SpringBoot.java @@ -0,0 +1,52 @@ +package io.swagger; + +import io.swagger.configuration.LocalDateConverter; +import io.swagger.configuration.LocalDateTimeConverter; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.ExitCodeGenerator; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +import springfox.documentation.oas.annotations.EnableOpenApi; + +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@SpringBootApplication +@EnableOpenApi +@ComponentScan(basePackages = { "io.swagger", "io.swagger.api" , "io.swagger.configuration"}) +public class Swagger2SpringBoot implements CommandLineRunner { + + @Override + public void run(String... arg0) throws Exception { + if (arg0.length > 0 && arg0[0].equals("exitcode")) { + throw new ExitException(); + } + } + + public static void main(String[] args) throws Exception { + new SpringApplication(Swagger2SpringBoot.class).run(args); + } + + @Configuration + static class CustomDateConfig extends WebMvcConfigurerAdapter { + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new LocalDateConverter("yyyy-MM-dd")); + registry.addConverter(new LocalDateTimeConverter("yyyy-MM-dd'T'HH:mm:ss.SSS")); + } + } + + class ExitException extends RuntimeException implements ExitCodeGenerator { + private static final long serialVersionUID = 1L; + + @Override + public int getExitCode() { + return 10; + } + + } +} diff --git a/code for server/api/ApiException.java b/code for server/api/ApiException.java new file mode 100644 index 0000000..0172f9c --- /dev/null +++ b/code for server/api/ApiException.java @@ -0,0 +1,10 @@ +package io.swagger.api; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +public class ApiException extends Exception { + private int code; + public ApiException (int code, String msg) { + super(msg); + this.code = code; + } +} diff --git a/code for server/api/ApiOriginFilter.java b/code for server/api/ApiOriginFilter.java new file mode 100644 index 0000000..6f2dfcf --- /dev/null +++ b/code for server/api/ApiOriginFilter.java @@ -0,0 +1,27 @@ +package io.swagger.api; + +import java.io.IOException; + +import javax.servlet.*; +import javax.servlet.http.HttpServletResponse; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +public class ApiOriginFilter implements javax.servlet.Filter { + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + HttpServletResponse res = (HttpServletResponse) response; + res.addHeader("Access-Control-Allow-Origin", "*"); + res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); + res.addHeader("Access-Control-Allow-Headers", "Content-Type"); + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } +} diff --git a/code for server/api/ApiResponseMessage.java b/code for server/api/ApiResponseMessage.java new file mode 100644 index 0000000..e472d04 --- /dev/null +++ b/code for server/api/ApiResponseMessage.java @@ -0,0 +1,69 @@ +package io.swagger.api; + +import javax.xml.bind.annotation.XmlTransient; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +@javax.xml.bind.annotation.XmlRootElement +public class ApiResponseMessage { + public static final int ERROR = 1; + public static final int WARNING = 2; + public static final int INFO = 3; + public static final int OK = 4; + public static final int TOO_BUSY = 5; + + int code; + String type; + String message; + + public ApiResponseMessage(){} + + public ApiResponseMessage(int code, String message){ + this.code = code; + switch(code){ + case ERROR: + setType("error"); + break; + case WARNING: + setType("warning"); + break; + case INFO: + setType("info"); + break; + case OK: + setType("ok"); + break; + case TOO_BUSY: + setType("too busy"); + break; + default: + setType("unknown"); + break; + } + this.message = message; + } + + @XmlTransient + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/code for server/api/CloudsApi.java b/code for server/api/CloudsApi.java new file mode 100644 index 0000000..98f85aa --- /dev/null +++ b/code for server/api/CloudsApi.java @@ -0,0 +1,64 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.36). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package io.swagger.api; + +import io.swagger.model.Cloud; +import io.swagger.model.Clouds; +import io.swagger.model.Error; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.bind.annotation.CookieValue; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.util.List; +import java.util.Map; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +@Validated +public interface CloudsApi { + + @Operation(summary = "Метод создания заказа на облако", description = "", tags={ "Cloud" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Успешный ответ с одним заказом", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Cloud.class))), + + @ApiResponse(responseCode = "200", description = "Ответ в остальных случаях", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class))) }) + @RequestMapping(value = "/clouds", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity createCloud(@Parameter(in = ParameterIn.DEFAULT, description = "", required=true, schema=@Schema()) @Valid @RequestBody Cloud body); + + + @Operation(summary = "Метод получения списка заказов на облако", description = "", tags={ "Clouds" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Успешный ответ со списком заказов в облаке", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Clouds.class))), + + @ApiResponse(responseCode = "200", description = "Ответ в остальных случаях", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class))) }) + @RequestMapping(value = "/clouds", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity getAllClouds(); + +} + diff --git a/code for server/api/CloudsApiController.java b/code for server/api/CloudsApiController.java new file mode 100644 index 0000000..a2ef66f --- /dev/null +++ b/code for server/api/CloudsApiController.java @@ -0,0 +1,81 @@ +package io.swagger.api; + +import io.swagger.model.Cloud; +import io.swagger.model.Clouds; +import io.swagger.model.Error; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.CookieValue; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.*; +import javax.validation.Valid; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +@RestController +public class CloudsApiController implements CloudsApi { + + private static final Logger log = LoggerFactory.getLogger(CloudsApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public CloudsApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity createCloud(@Parameter(in = ParameterIn.DEFAULT, description = "", required=true, schema=@Schema()) @Valid @RequestBody Cloud body) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"ROM\" : 1024,\n \"OS\" : \"Windows\",\n \"ID_client\" : \"j234l234\",\n \"CPU\" : 12497,\n \"ID_cloud\" : \"r382m292\",\n \"RAM\" : 64\n}", Cloud.class), HttpStatus.NOT_IMPLEMENTED); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + + public ResponseEntity getAllClouds() { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("[ {\n \"ROM\" : 1024,\n \"OS\" : \"Windows\",\n \"ID_client\" : \"j234l234\",\n \"CPU\" : 12497,\n \"ID_cloud\" : \"r382m292\",\n \"RAM\" : 64\n}, {\n \"ROM\" : 1024,\n \"OS\" : \"Windows\",\n \"ID_client\" : \"j234l234\",\n \"CPU\" : 12497,\n \"ID_cloud\" : \"r382m292\",\n \"RAM\" : 64\n} ]", Clouds.class), HttpStatus.NOT_IMPLEMENTED); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/code for server/api/CloudscloudNumberApi.java b/code for server/api/CloudscloudNumberApi.java new file mode 100644 index 0000000..7d6898a --- /dev/null +++ b/code for server/api/CloudscloudNumberApi.java @@ -0,0 +1,62 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.36). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package io.swagger.api; + +import io.swagger.model.Cloud; +import io.swagger.model.Error; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.bind.annotation.CookieValue; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.util.List; +import java.util.Map; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +@Validated +public interface CloudscloudNumberApi { + + @Operation(summary = "Метод удаления заказа на облако по номеру", description = "", tags={ "Clouds" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Успешно удалено"), + + @ApiResponse(responseCode = "200", description = "Ответ в остальных случаях", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class))) }) + @RequestMapping(value = "/clouds{cloud_number}", + produces = { "application/json" }, + method = RequestMethod.DELETE) + ResponseEntity deleteCloudByNumber(@Parameter(in = ParameterIn.PATH, description = "Номер заказа", required=true, schema=@Schema()) @PathVariable("cloud_number") String cloudNumber); + + + @Operation(summary = "Метод получения одного заказа на облако по номеру", description = "", tags={ "Clouds" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Успешный ответ с одним заказом", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Cloud.class))), + + @ApiResponse(responseCode = "200", description = "Ответ в остальных случаях", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class))) }) + @RequestMapping(value = "/clouds{cloud_number}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity getCloudByNumber(@Parameter(in = ParameterIn.PATH, description = "Номер заказа", required=true, schema=@Schema()) @PathVariable("cloud_number") String cloudNumber); + +} + diff --git a/code for server/api/CloudscloudNumberApiController.java b/code for server/api/CloudscloudNumberApiController.java new file mode 100644 index 0000000..69c4cb8 --- /dev/null +++ b/code for server/api/CloudscloudNumberApiController.java @@ -0,0 +1,71 @@ +package io.swagger.api; + +import io.swagger.model.Cloud; +import io.swagger.model.Error; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.CookieValue; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.*; +import javax.validation.Valid; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +@RestController +public class CloudscloudNumberApiController implements CloudscloudNumberApi { + + private static final Logger log = LoggerFactory.getLogger(CloudscloudNumberApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public CloudscloudNumberApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity deleteCloudByNumber(@Parameter(in = ParameterIn.PATH, description = "Номер заказа", required=true, schema=@Schema()) @PathVariable("cloud_number") String cloudNumber) { + String accept = request.getHeader("Accept"); + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + + public ResponseEntity getCloudByNumber(@Parameter(in = ParameterIn.PATH, description = "Номер заказа", required=true, schema=@Schema()) @PathVariable("cloud_number") String cloudNumber) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"ROM\" : 1024,\n \"OS\" : \"Windows\",\n \"ID_client\" : \"j234l234\",\n \"CPU\" : 12497,\n \"ID_cloud\" : \"r382m292\",\n \"RAM\" : 64\n}", Cloud.class), HttpStatus.NOT_IMPLEMENTED); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/code for server/api/NotFoundException.java b/code for server/api/NotFoundException.java new file mode 100644 index 0000000..3e2a69a --- /dev/null +++ b/code for server/api/NotFoundException.java @@ -0,0 +1,10 @@ +package io.swagger.api; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +public class NotFoundException extends ApiException { + private int code; + public NotFoundException (int code, String msg) { + super(code, msg); + this.code = code; + } +} diff --git a/code for server/configuration/CustomInstantDeserializer.java b/code for server/configuration/CustomInstantDeserializer.java new file mode 100644 index 0000000..6e5b8ed --- /dev/null +++ b/code for server/configuration/CustomInstantDeserializer.java @@ -0,0 +1,232 @@ +package io.swagger.configuration; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonTokenId; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.datatype.threetenbp.DecimalUtils; +import com.fasterxml.jackson.datatype.threetenbp.deser.ThreeTenDateTimeDeserializerBase; +import com.fasterxml.jackson.datatype.threetenbp.function.BiFunction; +import com.fasterxml.jackson.datatype.threetenbp.function.Function; +import org.threeten.bp.DateTimeException; +import org.threeten.bp.DateTimeUtils; +import org.threeten.bp.Instant; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZoneId; +import org.threeten.bp.ZonedDateTime; +import org.threeten.bp.format.DateTimeFormatter; +import org.threeten.bp.temporal.Temporal; +import org.threeten.bp.temporal.TemporalAccessor; + +import java.io.IOException; +import java.math.BigDecimal; + +/** + * Deserializer for ThreeTen temporal {@link Instant}s, {@link OffsetDateTime}, and {@link ZonedDateTime}s. + * Adapted from the jackson threetenbp InstantDeserializer to add support for deserializing rfc822 format. + * + * @author Nick Williams + */ +public class CustomInstantDeserializer + extends ThreeTenDateTimeDeserializerBase { + private static final long serialVersionUID = 1L; + + public static final CustomInstantDeserializer INSTANT = new CustomInstantDeserializer( + Instant.class, DateTimeFormatter.ISO_INSTANT, + new Function() { + @Override + public Instant apply(TemporalAccessor temporalAccessor) { + return Instant.from(temporalAccessor); + } + }, + new Function() { + @Override + public Instant apply(FromIntegerArguments a) { + return Instant.ofEpochMilli(a.value); + } + }, + new Function() { + @Override + public Instant apply(FromDecimalArguments a) { + return Instant.ofEpochSecond(a.integer, a.fraction); + } + }, + null + ); + + public static final CustomInstantDeserializer OFFSET_DATE_TIME = new CustomInstantDeserializer( + OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME, + new Function() { + @Override + public OffsetDateTime apply(TemporalAccessor temporalAccessor) { + return OffsetDateTime.from(temporalAccessor); + } + }, + new Function() { + @Override + public OffsetDateTime apply(FromIntegerArguments a) { + return OffsetDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId); + } + }, + new Function() { + @Override + public OffsetDateTime apply(FromDecimalArguments a) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId); + } + }, + new BiFunction() { + @Override + public OffsetDateTime apply(OffsetDateTime d, ZoneId z) { + return d.withOffsetSameInstant(z.getRules().getOffset(d.toLocalDateTime())); + } + } + ); + + public static final CustomInstantDeserializer ZONED_DATE_TIME = new CustomInstantDeserializer( + ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME, + new Function() { + @Override + public ZonedDateTime apply(TemporalAccessor temporalAccessor) { + return ZonedDateTime.from(temporalAccessor); + } + }, + new Function() { + @Override + public ZonedDateTime apply(FromIntegerArguments a) { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId); + } + }, + new Function() { + @Override + public ZonedDateTime apply(FromDecimalArguments a) { + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId); + } + }, + new BiFunction() { + @Override + public ZonedDateTime apply(ZonedDateTime zonedDateTime, ZoneId zoneId) { + return zonedDateTime.withZoneSameInstant(zoneId); + } + } + ); + + protected final Function fromMilliseconds; + + protected final Function fromNanoseconds; + + protected final Function parsedToValue; + + protected final BiFunction adjust; + + protected CustomInstantDeserializer(Class supportedType, + DateTimeFormatter parser, + Function parsedToValue, + Function fromMilliseconds, + Function fromNanoseconds, + BiFunction adjust) { + super(supportedType, parser); + this.parsedToValue = parsedToValue; + this.fromMilliseconds = fromMilliseconds; + this.fromNanoseconds = fromNanoseconds; + this.adjust = adjust == null ? new BiFunction() { + @Override + public T apply(T t, ZoneId zoneId) { + return t; + } + } : adjust; + } + + @SuppressWarnings("unchecked") + protected CustomInstantDeserializer(CustomInstantDeserializer base, DateTimeFormatter f) { + super((Class) base.handledType(), f); + parsedToValue = base.parsedToValue; + fromMilliseconds = base.fromMilliseconds; + fromNanoseconds = base.fromNanoseconds; + adjust = base.adjust; + } + + @Override + protected JsonDeserializer withDateFormat(DateTimeFormatter dtf) { + if (dtf == _formatter) { + return this; + } + return new CustomInstantDeserializer(this, dtf); + } + + @Override + public T deserialize(JsonParser parser, DeserializationContext context) throws IOException { + //NOTE: Timestamps contain no timezone info, and are always in configured TZ. Only + //string values have to be adjusted to the configured TZ. + switch (parser.getCurrentTokenId()) { + case JsonTokenId.ID_NUMBER_FLOAT: { + BigDecimal value = parser.getDecimalValue(); + long seconds = value.longValue(); + int nanoseconds = DecimalUtils.extractNanosecondDecimal(value, seconds); + return fromNanoseconds.apply(new FromDecimalArguments( + seconds, nanoseconds, getZone(context))); + } + + case JsonTokenId.ID_NUMBER_INT: { + long timestamp = parser.getLongValue(); + if (context.isEnabled(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)) { + return this.fromNanoseconds.apply(new FromDecimalArguments( + timestamp, 0, this.getZone(context) + )); + } + return this.fromMilliseconds.apply(new FromIntegerArguments( + timestamp, this.getZone(context) + )); + } + + case JsonTokenId.ID_STRING: { + String string = parser.getText().trim(); + if (string.length() == 0) { + return null; + } + if (string.endsWith("+0000")) { + string = string.substring(0, string.length() - 5) + "Z"; + } + T value; + try { + TemporalAccessor acc = _formatter.parse(string); + value = parsedToValue.apply(acc); + if (context.isEnabled(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)) { + return adjust.apply(value, this.getZone(context)); + } + } catch (DateTimeException e) { + throw _peelDTE(e); + } + return value; + } + } + throw context.mappingException("Expected type float, integer, or string."); + } + + private ZoneId getZone(DeserializationContext context) { + // Instants are always in UTC, so don't waste compute cycles + return (_valueClass == Instant.class) ? null : DateTimeUtils.toZoneId(context.getTimeZone()); + } + + private static class FromIntegerArguments { + public final long value; + public final ZoneId zoneId; + + private FromIntegerArguments(long value, ZoneId zoneId) { + this.value = value; + this.zoneId = zoneId; + } + } + + private static class FromDecimalArguments { + public final long integer; + public final int fraction; + public final ZoneId zoneId; + + private FromDecimalArguments(long integer, int fraction, ZoneId zoneId) { + this.integer = integer; + this.fraction = fraction; + this.zoneId = zoneId; + } + } +} diff --git a/code for server/configuration/HomeController.java b/code for server/configuration/HomeController.java new file mode 100644 index 0000000..689c5ea --- /dev/null +++ b/code for server/configuration/HomeController.java @@ -0,0 +1,16 @@ +package io.swagger.configuration; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Home redirection to swagger api documentation + */ +@Controller +public class HomeController { + @RequestMapping(value = "/") + public String index() { + System.out.println("/swagger-ui/index.html"); + return "redirect:/swagger-ui/"; + } +} diff --git a/code for server/configuration/JacksonConfiguration.java b/code for server/configuration/JacksonConfiguration.java new file mode 100644 index 0000000..2609d72 --- /dev/null +++ b/code for server/configuration/JacksonConfiguration.java @@ -0,0 +1,23 @@ +package io.swagger.configuration; + +import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.threeten.bp.Instant; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZonedDateTime; + +@Configuration +public class JacksonConfiguration { + + @Bean + @ConditionalOnMissingBean(ThreeTenModule.class) + ThreeTenModule threeTenModule() { + ThreeTenModule module = new ThreeTenModule(); + module.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT); + module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME); + module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME); + return module; + } +} diff --git a/code for server/configuration/LocalDateConverter.java b/code for server/configuration/LocalDateConverter.java new file mode 100644 index 0000000..e7ceddd --- /dev/null +++ b/code for server/configuration/LocalDateConverter.java @@ -0,0 +1,21 @@ +package io.swagger.configuration; + +import org.springframework.core.convert.converter.Converter; +import org.threeten.bp.LocalDate; +import org.threeten.bp.format.DateTimeFormatter; + +public class LocalDateConverter implements Converter { + private final DateTimeFormatter formatter; + + public LocalDateConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDate convert(String source) { + if(source == null || source.isEmpty()) { + return null; + } + return LocalDate.parse(source, this.formatter); + } +} diff --git a/code for server/configuration/LocalDateTimeConverter.java b/code for server/configuration/LocalDateTimeConverter.java new file mode 100644 index 0000000..a8ac0ab --- /dev/null +++ b/code for server/configuration/LocalDateTimeConverter.java @@ -0,0 +1,21 @@ +package io.swagger.configuration; + +import org.springframework.core.convert.converter.Converter; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.format.DateTimeFormatter; + +public class LocalDateTimeConverter implements Converter { + private final DateTimeFormatter formatter; + + public LocalDateTimeConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDateTime convert(String source) { + if(source == null || source.isEmpty()) { + return null; + } + return LocalDateTime.parse(source, this.formatter); + } +} diff --git a/code for server/configuration/SwaggerDocumentationConfig.java b/code for server/configuration/SwaggerDocumentationConfig.java new file mode 100644 index 0000000..a62176c --- /dev/null +++ b/code for server/configuration/SwaggerDocumentationConfig.java @@ -0,0 +1,58 @@ +package io.swagger.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.service.ApiInfo; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +@Configuration +public class SwaggerDocumentationConfig { + + @Bean + public Docket customImplementation(){ + return new Docket(DocumentationType.OAS_30) + .select() + .apis(RequestHandlerSelectors.basePackage("io.swagger.api")) + .build() + .directModelSubstitute(org.threeten.bp.LocalDate.class, java.sql.Date.class) + .directModelSubstitute(org.threeten.bp.OffsetDateTime.class, java.util.Date.class) + .apiInfo(apiInfo()); + } + + ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("Заказ облачных ресурсов") + .description("No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)") + .license("") + .licenseUrl("http://unlicense.org") + .termsOfServiceUrl("") + .version("0.0.1") + .contact(new Contact("","", "")) + .build(); + } + + @Bean + public OpenAPI openApi() { + return new OpenAPI() + .info(new Info() + .title("Заказ облачных ресурсов") + .description("No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)") + .termsOfService("") + .version("0.0.1") + .license(new License() + .name("") + .url("http://unlicense.org")) + .contact(new io.swagger.v3.oas.models.info.Contact() + .email(""))); + } + +} diff --git a/code for server/configuration/SwaggerUiConfiguration.java b/code for server/configuration/SwaggerUiConfiguration.java new file mode 100644 index 0000000..a9d4d0d --- /dev/null +++ b/code for server/configuration/SwaggerUiConfiguration.java @@ -0,0 +1,23 @@ +package io.swagger.configuration; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") +@Configuration +public class SwaggerUiConfiguration implements WebMvcConfigurer { + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry. + addResourceHandler("/swagger-ui/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/") + .resourceChain(false); + } + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/swagger-ui/").setViewName("forward:/swagger-ui/index.html"); + } +} diff --git a/code for server/model/Cloud.java b/code for server/model/Cloud.java new file mode 100644 index 0000000..0a88f32 --- /dev/null +++ b/code for server/model/Cloud.java @@ -0,0 +1,235 @@ +package io.swagger.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import javax.validation.Valid; +import javax.validation.constraints.*; + +/** + * Cloud + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") + + +public class Cloud { + @JsonProperty("ID_cloud") + private String idCloud = null; + + @JsonProperty("ID_client") + private String idClient = null; + + /** + * Операционная система сервера + */ + public enum OSEnum { + WINDOWS("Windows"), + + LINUX("Linux"); + + private String value; + + OSEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static OSEnum fromValue(String text) { + for (OSEnum b : OSEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("OS") + private OSEnum OS = null; + + @JsonProperty("RAM") + private Integer RAM = null; + + @JsonProperty("ROM") + private Integer ROM = null; + + @JsonProperty("CPU") + private Integer CPU = null; + + public Cloud idCloud(String idCloud) { + this.idCloud = idCloud; + return this; + } + + /** + * Get idCloud + * @return idCloud + **/ + @Schema(example = "r382m292", required = true, description = "") + @NotNull + + public String getIdCloud() { + return idCloud; + } + + public void setIdCloud(String idCloud) { + this.idCloud = idCloud; + } + + public Cloud idClient(String idClient) { + this.idClient = idClient; + return this; + } + + /** + * Get idClient + * @return idClient + **/ + @Schema(example = "j234l234", required = true, description = "") + @NotNull + + public String getIdClient() { + return idClient; + } + + public void setIdClient(String idClient) { + this.idClient = idClient; + } + + public Cloud OS(OSEnum OS) { + this.OS = OS; + return this; + } + + /** + * Операционная система сервера + * @return OS + **/ + @Schema(required = true, description = "Операционная система сервера") + @NotNull + + public OSEnum getOS() { + return OS; + } + + public void setOS(OSEnum OS) { + this.OS = OS; + } + + public Cloud RAM(Integer RAM) { + this.RAM = RAM; + return this; + } + + /** + * Оперативная память сервера + * @return RAM + **/ + @Schema(example = "64", required = true, description = "Оперативная память сервера") + @NotNull + + public Integer getRAM() { + return RAM; + } + + public void setRAM(Integer RAM) { + this.RAM = RAM; + } + + public Cloud ROM(Integer ROM) { + this.ROM = ROM; + return this; + } + + /** + * Внутренняя память сервера + * @return ROM + **/ + @Schema(example = "1024", required = true, description = "Внутренняя память сервера") + @NotNull + + public Integer getROM() { + return ROM; + } + + public void setROM(Integer ROM) { + this.ROM = ROM; + } + + public Cloud CPU(Integer CPU) { + this.CPU = CPU; + return this; + } + + /** + * Процессор сервера + * @return CPU + **/ + @Schema(example = "12497", description = "Процессор сервера") + + public Integer getCPU() { + return CPU; + } + + public void setCPU(Integer CPU) { + this.CPU = CPU; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Cloud cloud = (Cloud) o; + return Objects.equals(this.idCloud, cloud.idCloud) && + Objects.equals(this.idClient, cloud.idClient) && + Objects.equals(this.OS, cloud.OS) && + Objects.equals(this.RAM, cloud.RAM) && + Objects.equals(this.ROM, cloud.ROM) && + Objects.equals(this.CPU, cloud.CPU); + } + + @Override + public int hashCode() { + return Objects.hash(idCloud, idClient, OS, RAM, ROM, CPU); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Cloud {\n"); + + sb.append(" idCloud: ").append(toIndentedString(idCloud)).append("\n"); + sb.append(" idClient: ").append(toIndentedString(idClient)).append("\n"); + sb.append(" OS: ").append(toIndentedString(OS)).append("\n"); + sb.append(" RAM: ").append(toIndentedString(RAM)).append("\n"); + sb.append(" ROM: ").append(toIndentedString(ROM)).append("\n"); + sb.append(" CPU: ").append(toIndentedString(CPU)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/code for server/model/Clouds.java b/code for server/model/Clouds.java new file mode 100644 index 0000000..89137de --- /dev/null +++ b/code for server/model/Clouds.java @@ -0,0 +1,55 @@ +package io.swagger.model; + +import java.util.Objects; +import io.swagger.model.Cloud; +import java.util.ArrayList; +import java.util.List; +import org.springframework.validation.annotation.Validated; +import javax.validation.Valid; +import javax.validation.constraints.*; + +/** + * Clouds + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") + + +public class Clouds extends ArrayList { + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Clouds {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/code for server/model/Error.java b/code for server/model/Error.java new file mode 100644 index 0000000..510fb6e --- /dev/null +++ b/code for server/model/Error.java @@ -0,0 +1,105 @@ +package io.swagger.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import javax.validation.Valid; +import javax.validation.constraints.*; + +/** + * Error + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-12-15T17:59:53.540Z[GMT]") + + +public class Error { + @JsonProperty("code_error") + private Integer codeError = null; + + @JsonProperty("message_error") + private String messageError = null; + + public Error codeError(Integer codeError) { + this.codeError = codeError; + return this; + } + + /** + * Get codeError + * @return codeError + **/ + @Schema(required = true, description = "") + @NotNull + + public Integer getCodeError() { + return codeError; + } + + public void setCodeError(Integer codeError) { + this.codeError = codeError; + } + + public Error messageError(String messageError) { + this.messageError = messageError; + return this; + } + + /** + * Get messageError + * @return messageError + **/ + @Schema(required = true, description = "") + @NotNull + + public String getMessageError() { + return messageError; + } + + public void setMessageError(String messageError) { + this.messageError = messageError; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Error error = (Error) o; + return Objects.equals(this.codeError, error.codeError) && + Objects.equals(this.messageError, error.messageError); + } + + @Override + public int hashCode() { + return Objects.hash(codeError, messageError); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Error {\n"); + + sb.append(" codeError: ").append(toIndentedString(codeError)).append("\n"); + sb.append(" messageError: ").append(toIndentedString(messageError)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +}