Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1529 added first implementation of extensible artifact search REST API #1556

Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e6f872d
#1529 added first implementation of extensible artifact search REST API
jan-vcapgemini Jul 21, 2022
0628f8a
#1529 added missing dependencies
jan-vcapgemini Jul 21, 2022
575dfbd
#1529 implemented requested changes
jan-vcapgemini Jul 28, 2022
e97a415
#1529 fixed jFrog API
jan-vcapgemini Jul 28, 2022
c9e0340
#1529 implemented requested changes
jan-vcapgemini Aug 8, 2022
8e947db
#1529 implemented requested changes
jan-vcapgemini Aug 8, 2022
eb78cad
#1529 implemented requested changes
jan-vcapgemini Aug 8, 2022
b1b6532
#1529 adjusted nexus REST API
jan-vcapgemini Aug 9, 2022
de019ba
#1529 disabled jfrog REST API test
jan-vcapgemini Aug 9, 2022
fc3049a
#1529 added optimizations + authentication
jan-vcapgemini Aug 11, 2022
8a8f774
#1529 applied factory pattern
jan-vcapgemini Aug 12, 2022
644c6ad
#1529 moved utility methods from factory class to util class
jan-vcapgemini Aug 15, 2022
b2cca28
changed javadoc
EduardKrieger Aug 17, 2022
d5b3589
#1529 implemented requested changes
jan-vcapgemini Aug 17, 2022
b427129
#1529 implemented requested changes
jan-vcapgemini Aug 17, 2022
77890ab
#1529 implemented requested changes
jan-vcapgemini Aug 17, 2022
3b1c998
#1529 added missing javadoc
jan-vcapgemini Aug 17, 2022
aba2434
#1529 implemented requested changes
jan-vcapgemini Aug 17, 2022
5406713
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
ff95670
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
eac63f6
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
d1af594
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
f65539e
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
f9abab3
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
f28296e
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
dccffb7
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
a939d56
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
82a8727
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
28dfb4e
#1529 implemented requested changes
jan-vcapgemini Aug 24, 2022
ef6c9cd
#1529 added WireMock to tests
jan-vcapgemini Sep 1, 2022
e91f1f5
#1529 reduced WireMock logging
jan-vcapgemini Sep 1, 2022
314586d
#1529 updated jackson
jan-vcapgemini Sep 1, 2022
7026913
#1529 fixed FileUtils issue
jan-vcapgemini Sep 1, 2022
4eee9e0
#1529 implemented requested changes
jan-vcapgemini Sep 9, 2022
c413980
#1529 implemented requested changes
jan-vcapgemini Sep 9, 2022
1b26cf9
#1529 implemented requested changes
jan-vcapgemini Sep 9, 2022
a76fc14
#1529 removed jersey dependencies
jan-vcapgemini Sep 9, 2022
9d37871
#1529 updated okhttp
jan-vcapgemini Sep 9, 2022
341ae34
#1529 added okhttp version to root pom
jan-vcapgemini Sep 9, 2022
bd76bca
#1529 added okio
jan-vcapgemini Sep 9, 2022
63346f0
#1529 implemented requested changes
jan-vcapgemini Sep 14, 2022
f86f3aa
#1529 implemented requested changes
jan-vcapgemini Sep 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion cobigen/cobigen-core-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>

<!-- Proper process reader -->
<dependency>
<groupId>org.zeroturnaround</groupId>
Expand All @@ -40,11 +40,43 @@
<artifactId>core-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>3.0.7</version>
</dependency>

<dependency>
jan-vcapgemini marked this conversation as resolved.
Show resolved Hide resolved
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>3.0.7</version>
</dependency>

<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>3.0.7</version>
</dependency>

<dependency>
<groupId>org.glassfish.jersey.security</groupId>
<artifactId>oauth2-client</artifactId>
<version>3.0.7</version>
</dependency>

<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-standalone</artifactId>
<version>2.27.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.devonfw.cobigen.api.constants;

/**
* Constants needed for handling the maven search REST APIs
*/
public class MavenSearchRepositoryConstants {
jan-vcapgemini marked this conversation as resolved.
Show resolved Hide resolved

/**
* Maven repository URL
*/
public static String MAVEN_REPOSITORY_URL = "https://search.maven.org";

/**
* Maven repository download link
*/
public static String MAVEN_REPOSITORY_DOWNLOAD_LINK = "https://repo1.maven.org/maven2";

/**
* Maven target link
*/
public static String MAVEN_TARGET_LINK = "solrsearch/select";

/**
* Nexus2 repository URL
*/
public static String NEXUS2_REPOSITORY_URL = "https://s01.oss.sonatype.org";

/**
* Nexus2 repository link
*/
public static String NEXUS2_REPOSITORY_LINK = "service/local/repositories/releases/content";

/**
* Nexus2 target link
*/
public static String NEXUS2_TARGET_LINK = "service/local/lucene/search";

/**
* Nexus3 target link
*/
public static String NEXUS3_TARGET_LINK = "service/rest/v1/search";

/**
* Nexus3 repository URL
*/
public static String NEXUS3_REPOSITORY_URL = "";

/**
* Jfrog repository URL
*/
public static String JFROG_REPOSITORY_URL = "http://localhost:8082/artifactory";

/**
* Jfrog target link
*/
public static String JFROG_TARGET_LINK = "api/search/gavc";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.devonfw.cobigen.api.constants;

/**
* Maven search repository types used to identify and name the available search REST API types (add new search
* repository types/versions here)
*/
public enum MavenSearchRepositoryType {
jan-vcapgemini marked this conversation as resolved.
Show resolved Hide resolved

/**
* Nexus2 search repository type
*/
nexus2,
EduardKrieger marked this conversation as resolved.
Show resolved Hide resolved

/**
* Nexus3 search repository type
*/
nexus3,

/**
* Maven search repository type
*/
maven,

/**
* Jfrog search repository type
*/
jfrog
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.devonfw.cobigen.api.exception;

/** Exception to indicate that the REST search API encountered a problem while accessing the server. */
public class RestSearchResponseException extends CobiGenRuntimeException {

private static final long serialVersionUID = 1L;

/**
* Creates a new {@link RestSearchResponseException} with the given message
*
* @param message error message of the exception
*/
public RestSearchResponseException(String message) {

super(message);
}

/**
* Creates a new {@link RestSearchResponseException} with the specified message and the causing {@link Throwable}
*
* @param message describing the exception
* @param cause the causing Throwable
*/
public RestSearchResponseException(String message, Throwable cause) {

super(message, cause);
}

/**
* Creates a new {@link RestSearchResponseException} with the specified message and the causing {@link Throwable}
*
* @param message describing the exception
* @param statusCode status code causing the {@link RestSearchResponseException} or null if not available
*/
public RestSearchResponseException(String message, String statusCode) {

super(message + statusCode);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@

import com.devonfw.cobigen.api.constants.MavenConstants;
import com.devonfw.cobigen.api.exception.CobiGenRuntimeException;
import com.devonfw.cobigen.api.exception.RestSearchResponseException;
import com.devonfw.cobigen.api.util.to.SearchResponseFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Lists;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteSource;
Expand Down Expand Up @@ -340,4 +343,26 @@ public static Path getProjectRoot(Path inputFile, boolean topLevel) {
LOG.debug("Project root could not be found.");
return null;
}

/**
* Retrieves a list of download URLs by groupId from the specified repository search REST API using authentication
* with bearer token
*
* @param baseURL String of the repository server URL
* @param groupId the groupId to search for
* @param authToken bearer token to use for authentication
* @return List of artifact download URLS or null if an error occurred
*/
public static List<URL> retrieveMavenArtifactsByGroupId(String baseURL, String groupId, String authToken) {

try {
return SearchResponseFactory.searchArtifactDownloadLinks(baseURL, groupId, authToken);
} catch (RestSearchResponseException | JsonProcessingException | MalformedURLException e) {
LOG.error("Unable to get artifacts from " + baseURL + " by groupId " + groupId, e);
// TODO: Handle Eclipse, CLI and MavenPlugin here (f.e. with a new Exception)
return null;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package com.devonfw.cobigen.api.util.to;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.stream.Collectors;

import org.glassfish.jersey.client.oauth2.OAuth2ClientSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.devonfw.cobigen.api.constants.MavenSearchRepositoryType;
import com.devonfw.cobigen.api.exception.RestSearchResponseException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Feature;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

/**
* This interface should be inherited for all maven REST search API responses to properly convert {@link JsonProperty}
* from responses to valid download URLs
*/
public abstract class AbstractSearchResponse {

/** Logger instance. */
@JsonIgnore
private static final Logger LOG = LoggerFactory.getLogger(AbstractSearchResponse.class);

/**
* @return the {@link MavenSearchRepositoryType} type
*/
public abstract MavenSearchRepositoryType getRepositoryType();

/**
* Creates a list of download URLs
*
* @return List of download links
* @throws MalformedURLException if an URL was not valid
*/
public abstract List<URL> retrieveDownloadURLs() throws MalformedURLException;

/**
* Removes duplicates from list of download URLs
*
* @param downloadUrls list of download URLs
* @return List of download links
* @throws MalformedURLException if an URL was not valid
*/
public List<URL> removeDuplicatedDownloadURLs(List<URL> downloadUrls) throws MalformedURLException {

return downloadUrls.stream().distinct().collect(Collectors.toList());
}

/**
* Retrieves the json response from a repository URL and a group ID
*
* @param repositoryUrl URL of the repository
* @param groupId to search for
* @return String of json response
* @throws RestSearchResponseException if the request did not return status 200
*/
public String retrieveJsonResponse(String repositoryUrl, String groupId) throws RestSearchResponseException {

return retrieveJsonResponse(repositoryUrl, groupId, null);
}

/**
* Retrieves the json response from a repository URL, a group ID and a bearer authentication token
*
* @param repositoryUrl URL of the repository
* @param groupId to search for
* @param authToken bearer token to use for authentication
* @return String of json response
* @throws RestSearchResponseException if the request did not return status 200
*/
public abstract String retrieveJsonResponse(String repositoryUrl, String groupId, String authToken)
throws RestSearchResponseException;

/**
* Creates a @WebTarget with provided authentication token
*
* @param targetLink link to get response from
* @param token bearer token to use for authentication
* @return WebTarget to use as resource
*/
private static WebTarget bearerAuthenticationWithOAuth2AtClientLevel(String targetLink, String token) {

Feature feature = OAuth2ClientSupport.feature(token);
Client client = ClientBuilder.newBuilder().register(feature).build();

WebTarget target = client.target(targetLink);
return target;
}

/**
* Retrieves a json response by given REST API target link using bearer authentication token
*
* @param targetLink link to get response from
* @param authToken bearer token to use for authentication
* @param searchRepositoryType the type of the search repository
* @return String of json response
* @throws RestSearchResponseException if the returned status code was not 200 OK
*/
public static String retrieveJsonResponseWithAuthenticationToken(String targetLink, String authToken,
MavenSearchRepositoryType searchRepositoryType) throws RestSearchResponseException {

LOG.info("Starting {} search REST API request with URL: {}.", searchRepositoryType, targetLink);

WebTarget target = null;

if (authToken != null) {
target = bearerAuthenticationWithOAuth2AtClientLevel(targetLink, authToken);
} else {
Client client = ClientBuilder.newClient();
target = client.target(targetLink);
}

Response response = null;
Invocation.Builder request = target.request(MediaType.APPLICATION_JSON);
response = request.get();

int status = response.getStatus();
String jsonResponse = "";
if (status == 200) {
jsonResponse = response.readEntity(String.class);
} else {
throw new RestSearchResponseException("The search REST API returned the unexpected status code: ",
String.valueOf(status));
}
return jsonResponse;
}

/**
* Creates a download link (concatenates maven repository link with groupId, artifact and version)
*
* @param mavenRepo link to the maven repository to use
* @param groupId for the download link
* @param artifactId for the download link
* @param version for the download link
* @param fileEnding file ending for the download link
* @return concatenated download link
* @throws MalformedURLException if the URL was not valid
*/
protected static URL createDownloadLink(String mavenRepo, String groupId, String artifactId, String version,
String fileEnding) throws MalformedURLException {

String parsedGroupId = groupId.replace(".", "/");
String downloadFile = artifactId + "-" + version + fileEnding;
String downloadLink = mavenRepo + "/" + parsedGroupId + "/" + artifactId + "/" + version + "/" + downloadFile;
URL url = new URL(downloadLink);
return url;
}

}
Loading