com.mooltiverse.oss.nyx.services.gitlab.API Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of main Show documentation
Show all versions of main Show documentation
com.mooltiverse.oss.nyx:main:3.0.7 null
/*
* Copyright 2020 Mooltiverse
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mooltiverse.oss.nyx.services.gitlab;
import static com.mooltiverse.oss.nyx.log.Markers.SERVICE;
import static com.mooltiverse.oss.nyx.services.gitlab.GitLab.logger;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mooltiverse.oss.nyx.entities.Attachment;
import com.mooltiverse.oss.nyx.io.TransportException;
import com.mooltiverse.oss.nyx.services.SecurityException;
/**
* A superclass for various API versions.
*/
abstract class API {
/**
* The instance of the remote base URI.
*/
protected final URI uri;
/**
* Builds this object using the given uri to use as the remote endpoint.
*
* @param uri the remote API endpoint. It can't be {@code null}
*/
protected API(URI uri) {
super();
Objects.requireNonNull(uri, "API base URI cannot be null");
this.uri = uri;
}
/**
* Creates a new repository for the currently authenticated user.
*
* Please note that if the service has been configured with repository owner and name those attributes are ignored
* by this method as the owner is always the authenticated user (the one owning the configured credentials) and the
* name is always the {@code name} attribute.
*
* @param name the repository name. Cannot be {@code null}
* @param description the repository description. It may be {@code null}
* @param restricted when {@code true} the repository will have private visibility, otherwise it will be public
* @param initialize when {@code true} the repository is also initialized with a default README file
*
* @return the attributes of the new repository. Never {@code null}
*
* @throws TransportException if a transport related error occurs while communicating with the server
* @throws SecurityException if authentication fails
*/
abstract Map createRepository(String name, String description, boolean restricted, boolean initialize)
throws TransportException, SecurityException;
/**
* Deletes a repository for the currently authenticated user.
*
* Please note that if the service has been configured with repository owner and name those attributes are ignored
* by this method as the owner is always the authenticated user (the one owning the configured credentials) and the
* name is always the {@code name} attribute.
*
* @param name the repository name. Cannot be {@code null}
*
* @throws TransportException if a transport related error occurs while communicating with the server
* @throws SecurityException if authentication fails
*/
abstract void deleteRepository(String name)
throws TransportException, SecurityException;
/**
* Returns an HTTP client builder with all reusable attributes set. The returned object is not aware of any authentication
* method.
* After retrieving the client builder with this method you can set custom properties if you need to and then get a new client
* instance with {@link HttpClient.Builder#build()}.
*
* @return an HTTP client builder with all reusable attributes set.
*/
abstract HttpClient.Builder getClientBuilder();
/**
* Finds the release in the given repository by the release tag.
*
* @param owner the name of the owner of the repository to get the release for. It can't be {@code null}
* @param repository the name of the repository to get the release for. It can't be {@code null}
* @param tag the release tag (i.e. {@code 1.2.3}, {@code v4.5.6}). It can't be {@code null}
*
* @return the attributes of the requested release, if available, or {@code null} otherwise
*
* @throws SecurityException if authentication or authorization fails
* @throws TransportException if communication to the remote endpoint fails
* @throws UnsupportedOperationException if the underlying implementation does not
* {@link #supports(Service.Feature) support} the {@link Service.Feature#RELEASES} feature.
*/
abstract Map getReleaseByTag(String owner, String repository, String tag)
throws SecurityException, TransportException;
/**
* Returns a set of published assets for the release identified by the given attributes.
*
* @param owner the name of the owner of the repository of the release. It can't be {@code null}
* @param repository the name of the repository of the release. It can't be {@code null}
* @param tag the release tag (i.e. {@code 1.2.3}, {@code v4.5.6}). It can't be {@code null}
*
* @return the published release artifacts
*
* @throws SecurityException if authentication or authorization fails
* @throws TransportException if communication to the remote endpoint fails
* @throws UnsupportedOperationException if the underlying implementation does not
* {@link #supports(Service.Feature) support} the {@link Service.Feature.RELEASE_ASSETS} feature.
*/
abstract Set listReleaseAssets(String owner, String repository, String tag)
throws SecurityException, TransportException;
/**
* Returns an HTTP request builder with all reusable attributes set.
* After retrieving the request builder with this method you can set custom properties if you need to and then get a new request
* instance with {@link HttpRequest.Builder#build()}.
*
* @param authenticate if {@code true} the returned object will be able to send authenticated requests
*
* @return an HTTP request builder with all reusable attributes set.
*
* @throws SecurityException if {@code authenticate} is {@code true} and authentication fails
*/
abstract HttpRequest.Builder getRequestBuilder(boolean authenticate)
throws SecurityException;
/**
* Retrieves the attributes of the user with the given ID. If the given used ID is {@code null}
* then the current authenticated user for the given session is retrieved, otherwise the user with the
* given ID is fetched. The authenticated user is the one owning the configured credentials.
*
* @param userID the ID of the user to retrieve the attributes for. When {@code null} the attributes
* of the authenticated user are returned
*
* @return the attributes of the requested user. When {@code userID} is {@code null} the result value
* is never {@code null}, otherwise it may be {@code null} if no used with the given ID is available
*
* @throws TransportException if a transport related error occurs while communicating with the server
* @throws SecurityException if authentication fails
*/
abstract Map getUserAttributes(String userID)
throws TransportException, SecurityException;
/**
* Returns an HTTP client with all reusable attributes set. The returned object is not aware of any authentication method.
*
* @return an HTTP client with all reusable attributes set.
*/
HttpClient newClient() {
return getClientBuilder().build();
}
/**
* Publishes a new release.
*
* @param owner the name of the owner of the repository to create the release for. It can't be {@code null}
* @param repository the name of the repository to create the release for. It can't be {@code null}
* @param title the release title, it may be the same of {@code tag} but not necessarily. It may be {@code null}
* @param tag tag to publish the release for (i.e. {@code 1.2.3}, {@code v4.5.6}). It can't be {@code null}
* @param description the release description. This is usually a Markdown text containing release notes or a changelog
* or something like that giving an overall description of the release
*
* @return the attributes of the new release
*
* @throws SecurityException if authentication or authorization fails
* @throws TransportException if communication to the remote endpoint fails
* @throws UnsupportedOperationException if the underlying implementation does not
* {@link #supports(Service.Feature) support} the {@link Service.Feature#RELEASES} feature.
*/
abstract Map publishRelease(String owner, String repository, String title, String tag, String description)
throws SecurityException, TransportException;
/**
* Publishes a set of assets for a release.
*
* @param owner the name of the owner of the repository to create the assets for. It can't be {@code null}
* @param repository the name of the repository to create the assets for. It can't be {@code null}
* @param version the assets version, which should be the same as the release. It can't be {@code null}
* @param assets the set of assets to publish. Each asset is interpreted differently depending on its
* {@link Attachment#getPath() path}. If the asset path is a relatve path or has {@code file} as the scheme/protocol
* it is interpreted as a local file to upload, and the link of the uploaded asset will be returned along with the
* release. If the asset path is a remote link it will be just attached as such to the release with no further
* uploading and the same link will be listed among the release assets
*
* @return the published release artifacts
*
* @throws SecurityException if authentication or authorization fails
* @throws TransportException if communication to the remote endpoint fails
* @throws UnsupportedOperationException if the underlying implementation does not
* {@link #supports(Service.Feature) support} the {@link Service.Feature.RELEASE_ASSETS} feature.
*/
abstract Set publishReleaseAssets(String owner, String repository, String version, Set assets)
throws SecurityException, TransportException;
/**
* Sends the given request and returns the response, logging as needed.
*
* @param request the request to send
*
* @return the response
*
* @throws IOException if thrown by the underlying implementation
* @throws InterruptedException if thrown by the underlying implementation
* @throws IllegalArgumentException if thrown by the underlying implementation
*/
protected HttpResponse sendRequest(HttpRequest request)
throws IOException, InterruptedException, IllegalArgumentException {
logger.debug(SERVICE, "HTTP request: '{}' '{}'", request.method(), request.uri());
logger.trace(SERVICE, "HTTP request headers: '{}'", request.headers().toString());
HttpResponse response = newClient().send(request, BodyHandlers.ofString());
logger.debug(SERVICE, "HTTP response code: '{}'", response.statusCode());
logger.trace(SERVICE, "HTTP response headers: '{}'", response.headers().toString());
logger.trace(SERVICE, "HTTP response body:");
logger.trace(SERVICE, response.body());
return response;
}
/**
* Parses the given string as a JSON object tree and returns each item in the resulting map.
*
* @param body the JSON string to parse
*
* @return the map of properties parsed from the given body
*
* @throws TransportException in case unmarshalling fails
*/
protected Map unmarshalJSONBody(String body)
throws TransportException {
try {
JsonNode rootNode = new ObjectMapper().readTree(body);
if (rootNode == null)
throw new TransportException("Unmarshalling JSON content returned a null object");
return GitLabEntity.toAttributeMap(rootNode);
}
catch (JsonProcessingException jpe) {
throw new TransportException("An error occurred while unmarshalling JSON response", jpe);
}
}
/**
* Parses the given string as a collection of JSON object tree and returns each item in the resulting list of maps.
*
* @param body the JSON collection to parse
*
* @return the list of map of properties parsed from the given body
*
* @throws TransportException in case unmarshalling fails
*/
protected List