Skip to content

Commit

Permalink
Implement lookup for Orcid person entries
Browse files Browse the repository at this point in the history
  • Loading branch information
sven1103 committed Jan 16, 2025
1 parent a13e076 commit 8d4d839
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@
import static life.qbic.logging.service.LoggerFactory.logger;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -34,7 +39,7 @@
public class OrcidRepository implements PersonRepository {

private static final Logger log = logger(OrcidRepository.class);
private final String tokenEndpoint;
private static final String PAGINATED_QUERY = "https://pub.orcid.org/v3.0/expanded-search/?start=%s&rows=%s&q=%s";
private String token;
private String refreshToken;
private HttpClient httpClient;
Expand All @@ -47,7 +52,6 @@ public OrcidRepository(@Value("${qbic.orcid.api.client.id}") String clientID,
var authResponse = authenticate(httpClient, clientID, clientSecret, tokenEndpoint);
this.refreshToken = authResponse.refresh_token();
this.token = authResponse.access_token();
this.tokenEndpoint = tokenEndpoint;
}

private static HttpClient createHttpClient() {
Expand All @@ -56,7 +60,8 @@ private static HttpClient createHttpClient() {
Duration.ofSeconds(10)).build();
}

private static AuthResponse authenticate(HttpClient client, String clientID, String clientSecret, String tokenEndpoint) {
private static AuthResponse authenticate(HttpClient client, String clientID, String clientSecret,
String tokenEndpoint) {
var params = Map.of("client_id", clientID, "client_secret", clientSecret, "scope",
"/read-public", "grant_type", "client_credentials");

Expand All @@ -83,24 +88,77 @@ private static AuthResponse authenticate(HttpClient client, String clientID, Str
Thread.currentThread().interrupt();
}
log.error("Error sending orcid request", e);
throw new QueryException("Authentication failed", e);
throw new OrcidRepository.QueryException("Authentication failed", e);
}

}

private static PersonEntry convert(OrcidRecord record) {
return new PersonEntry(record.givenName + record.familyName,
Arrays.stream(record.email()).findFirst().orElse(""), "https://orcid.org/" + record.orcidID,
record.orcidID);
}

@Override
public List<PersonEntry> findAll(String query, int limit, int offset) {
return List.of();
var queryUrl =String.format(PAGINATED_QUERY, offset, limit, query);
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(queryUrl))
.headers("Authorization", "Bearer " + token, "Accept", "application/json").GET()
.build();

try {
var response = httpClient.send(request, BodyHandlers.ofString());
ObjectMapper mapper = new ObjectMapper();
var node = mapper.readTree(response.body());
var value = node.get("expanded-result");

return new ArrayList<>(
Arrays.stream(mapper.convertValue(value, OrcidRecord[].class))
.map(OrcidRepository::convert).toList());
} catch (IOException | InterruptedException e) {
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
log.error("Error sending orcid request", e);
throw new OrcidRepository.QueryException("Person repository seems not available", e);
}
}
}

class QueryException extends RuntimeException {
public QueryException(String message, Throwable cause) {
super(message, cause);
@JsonIgnoreProperties(ignoreUnknown = true)
record AuthResponse(String access_token, String token_type, String expires_in,
String refresh_token, String scope, String orcid) {

}

@JsonIgnoreProperties(ignoreUnknown = true)
record OrcidRecord(@JsonProperty("orcid-id") String orcidID,
@JsonProperty("given-names") String givenName,
@JsonProperty("family-names") String familyName,
@JsonProperty("credit-name") String creditName,
@JsonProperty("email") String[] email) {

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
OrcidRecord that = (OrcidRecord) o;
return Objects.equals(orcidID, that.orcidID) && Objects.deepEquals(email,
that.email) && Objects.equals(givenName, that.givenName)
&& Objects.equals(familyName, that.familyName) && Objects.equals(
creditName, that.creditName);
}

@Override
public int hashCode() {
return Objects.hash(orcidID, givenName, familyName, creditName, Arrays.hashCode(email));
}
}
}

@JsonIgnoreProperties(ignoreUnknown = true)
record AuthResponse(String access_token, String token_type, String expires_in, String refresh_token, String scope, String orcid) {
static class QueryException extends RuntimeException {

public QueryException(String message, Throwable cause) {
super(message, cause);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package life.qbic.projectmanagement.application.contact;

import java.net.URL;

/**
* <b><record short description - 1 Line!></b>
*
* <p><More detailed description - When to use, what it solves, etc.></p>
*
* @since <version tag>
*/
public record PersonEntry(String fullName, String email, URL orcidURL, String orcidID) {
public record PersonEntry(String fullName, String email, String orcidURL, String orcidID) {

}

0 comments on commit 8d4d839

Please sign in to comment.