Compare commits

..

No commits in common. "master" and "9719_cursor-based_pagination" have entirely different histories.

12 changed files with 70 additions and 158 deletions

15
pom.xml
View File

@ -163,21 +163,6 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!-- Add dump schema dependency -->
<dependency>
<groupId>eu.dnetlib.dhp</groupId>

View File

@ -2,10 +2,8 @@ package eu.openaire.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy
public class OpenaireRestApiApplication {
public static void main(String[] args) {

View File

@ -1,50 +0,0 @@
package eu.openaire.api.config.metrics;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class MetricsAspect {
private final MeterRegistry meterRegistry;
@Autowired
public MetricsAspect(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
/***
* Advice for timing methods annotated with {@link Timed}.
*/
@Around("@annotation(io.micrometer.core.annotation.Timed)")
public Object timeAnnotatedMethods(ProceedingJoinPoint joinPoint) throws Throwable {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = method.getName();
String timerName = className + "." + methodName;
Timer.Sample sample = Timer.start(meterRegistry);
try {
return joinPoint.proceed();
} finally {
sample.stop(Timer.builder(timerName)
.tags("application", "openaire-search-api")
.tags("class", className)
.tags("method", methodName)
.publishPercentiles(0.5, 0.95)
.register(meterRegistry));
}
}
}

View File

@ -9,6 +9,9 @@ import jakarta.validation.constraints.Pattern;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static eu.openaire.api.mappers.Utils.API_CURSOR_DESC;
import static eu.openaire.api.mappers.Utils.API_PAGE_DESC;
@ -74,28 +77,32 @@ public class ProjectRequest implements PaginatedRequest {
private String[] fundingStreamId;
@Parameter(
description = "Gets the projects with start date greater than or equal to the given date. Provide a date in YYYY or YYYY-MM-DD format",
schema = @Schema(type = "string")
description = "Gets the projects with start date greater than or equal to the given date. Please provide a date formatted as YYYY-MM-DD",
schema = @Schema(type = "string", format = "date")
)
private String fromStartDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate fromStartDate;
@Parameter(
description = "Gets the projects with start date less than or equal to the given date. Provide a date in YYYY or YYYY-MM-DD format",
schema = @Schema(type = "string")
description = "Gets the projects with start date less than or equal to the given date. Please provide a date formatted as YYYY-MM-DD",
schema = @Schema(type = "string", format = "date")
)
private String toStartDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate toStartDate;
@Parameter(
description = "Gets the projects with end date greater than or equal to the given date. Provide a date in YYYY or YYYY-MM-DD format",
schema = @Schema(type = "string")
description = "Gets the projects with end date greater than or equal to the given date. Please provide a date formatted as YYYY-MM-DD",
schema = @Schema(type = "string", format = "date")
)
private String fromEndDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate fromEndDate;
@Parameter(
description = "Gets the projects with end date less than or equal to the given date. Provide a date in YYYY or YYYY-MM-DD format",
schema = @Schema(type = "string")
description = "Gets the projects with end date less than or equal to the given date. Please provide a date formatted as YYYY-MM-DD",
schema = @Schema(type = "string", format = "date")
)
private String toEndDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate toEndDate;
@Parameter(
description = "The name or short name of the related organization",

View File

@ -9,6 +9,9 @@ import jakarta.validation.constraints.Pattern;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static eu.openaire.api.mappers.Utils.API_CURSOR_DESC;
import static eu.openaire.api.mappers.Utils.API_PAGE_DESC;
@ -73,14 +76,18 @@ public class ResearchProductsRequest implements PaginatedRequest {
private String[] type;
@Parameter(
description = "Gets the research products whose publication date is greater than or equal to he given date. Provide a date in YYYY or YYYY-MM-DD format",
schema = @Schema(type = "string"))
private String fromPublicationDate;
description = "Gets the research products whose publication date is greater than or equal to he given date. Please provide a date formatted as YYYY-MM-DD",
schema = @Schema(type = "string", format = "date")
)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate fromPublicationDate;
@Parameter(
description = "Gets the research products whose publication date is less than or equal to the given date. Provide a date in YYYY or YYYY-MM-DD format",
schema = @Schema(type = "string"))
private String toPublicationDate;
description = "Gets the research products whose publication date is less than or equal to the given date. Please provide a date formatted as YYYY-MM-DD",
schema = @Schema(type = "string", format = "date")
)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate toPublicationDate;
@Parameter(
description = "List of subjects associated to the research product",

View File

@ -9,7 +9,6 @@ import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
public class Utils {
@ -39,7 +38,7 @@ public class Utils {
indicating that there are no more results.
""";
public static String escapeAndJoin(String[] tokens, String predicate, boolean addQuotes, String suffix) {
static public String escapeAndJoin(String[] tokens, String predicate, boolean addQuotes, String suffix) {
tokens = Arrays.stream(tokens)
// remove empty tokens
@ -52,7 +51,7 @@ public class Utils {
return String.join(" " + predicate + " ", tokens);
}
public static String handleInput(String token, boolean addQuotes, String suffix) {
static public String handleInput(String token, boolean addQuotes, String suffix) {
boolean hasLogicalOperator = containsLogicalOperator(token);
@ -74,11 +73,11 @@ public class Utils {
return sb.toString();
}
private static boolean containsLogicalOperator(String input) {
static private boolean containsLogicalOperator(String input) {
return input.contains("AND") || input.contains("OR") || input.contains("NOT");
}
public static String escapeInput(String input, String suffix) {
static public String escapeInput(String input, String suffix) {
// Split the input into tokens at whitespace or parentheses or quotes
String[] tokens = input.split("(\\s+|(?=[()\\\"]|(?<=[()\\\"])))");
@ -164,66 +163,24 @@ public class Utils {
}
return value;
}
private static void removeLastElementIfSpace(List<String> list) {
static private void removeLastElementIfSpace(List<String> list) {
if (list.get(list.size() - 1).equals(" ")) {
list.remove(list.size() - 1);
}
}
public static boolean isNullOrEmpty(String str) {
static public boolean isNullOrEmpty(String str) {
return str == null || str.isBlank();
}
public static boolean isNullOrEmpty(String[] str) {
static public boolean isNullOrEmpty(String[] str) {
return str == null || str.length == 0;
}
public static String formatSolrDateRange(String fieldName, String fromDate, String toDate) {
if (fromDate != null && toDate != null) {
return String.format(fieldName,
appendHHMMSS(appendMMDD(fromDate, "-01-01")),
appendHHMMSS(appendMMDD(toDate, "-12-31")));
} else {
if (fromDate != null) {
return String.format(fieldName,
appendHHMMSS(appendMMDD(fromDate, "-01-01")), "*");
}
if (toDate != null) {
return String.format(fieldName, "*",
appendHHMMSS(appendMMDD(toDate, "-12-31")));
}
}
return null;
}
/***
* Append -mm-dd if date came in yyyy format
* @return LocalDate in yyyy-mm-dd format
*/
private static LocalDate appendMMDD(String date, String monthDaySuffix) {
try {
if (date.length() == 10) { //yyyy-mm-dd
return LocalDate.parse(date);
} else if (date.length() == 4) { //yyyy
return LocalDate.parse(date + monthDaySuffix);
} else {
throw new IllegalArgumentException("Invalid date format");
}
} catch (DateTimeParseException e) {
throw new IllegalArgumentException("Failed to parse date: " + date, e);
}
}
/***
* The incoming date comes in yyyy-mm-dd, so we have to append hh-mm-ss, also.
* @return String in yyyy-MM-dd'T'HH:mm:ss'Z' format
*/
private static String appendHHMMSS(LocalDate date) {
static private String formatDate(LocalDate date) {
// IMPORTANT: all dates are indexed in 12:00:00 in the index (not sure why)
// so we need to set this time to the date (this should change if dates are indexed in a different way)
@ -243,7 +200,23 @@ public class Utils {
return zdt.format(formatter);
}
public static List<SolrQuery.SortClause> formatSortByParam(String sortBy, Map<String, String> fieldMapping) {
static public String formatSolrDateRange(String fieldName, LocalDate fromDate, LocalDate toDate) {
if (fromDate != null && toDate != null) {
return String.format(fieldName, Utils.formatDate(fromDate), Utils.formatDate(toDate));
} else {
if (fromDate != null) {
return String.format(fieldName, Utils.formatDate(fromDate), "*");
}
if (toDate != null) {
return String.format(fieldName, "*", Utils.formatDate(toDate));
}
}
return null;
}
static public List<SolrQuery.SortClause> formatSortByParam(String sortBy, Map<String, String> fieldMapping) {
if (Utils.isNullOrEmpty(sortBy)) {
return null;

View File

@ -139,8 +139,11 @@ public interface ResearchProductMapper {
return null;
List<Pid> orcid = authorPidList
.stream()
.filter(ap -> ModelConstants.ORCID.equals(ap.getTypeCode()))
.toList();
.filter(
ap -> ap
.getTypeCode()
.equals(ModelConstants.ORCID))
.collect(Collectors.toList());
if (orcid.size() == 1) {
return getAuthorPid(orcid.get(0));
}
@ -148,8 +151,11 @@ public interface ResearchProductMapper {
return null;
orcid = authorPidList
.stream()
.filter(ap -> ModelConstants.ORCID_PENDING.equals(ap.getTypeCode()))
.toList();
.filter(
ap -> ap
.getTypeCode()
.equals(ModelConstants.ORCID_PENDING))
.collect(Collectors.toList());
if (orcid.size() == 1) {
return getAuthorPid(orcid.get(0));
}

View File

@ -11,7 +11,6 @@ import eu.openaire.api.mappers.response.ResponseResultsMapper;
import eu.openaire.api.mappers.response.entities.DatasourceMapper;
import eu.openaire.api.repositories.SolrRepository;
import eu.openaire.api.solr.SolrQueryParams;
import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
@ -38,7 +37,6 @@ public class DataSourceService {
private final Logger log = LogManager.getLogger(this.getClass());
@SneakyThrows
@Timed
public Datasource getById(String id) {
var doc = solrRepository.getById(id);
@ -50,7 +48,6 @@ public class DataSourceService {
}
@SneakyThrows
@Timed
public SearchResponse<Datasource> search(DataSourceRequest request) {
SolrQueryParams solrQueryParams = dataSourceRequestMapper.toSolrQuery(request);

View File

@ -11,7 +11,6 @@ import eu.openaire.api.mappers.response.ResponseResultsMapper;
import eu.openaire.api.mappers.response.entities.OrganizationMapper;
import eu.openaire.api.repositories.SolrRepository;
import eu.openaire.api.solr.SolrQueryParams;
import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
@ -38,7 +37,6 @@ public class OrganizationService {
private final Logger log = LogManager.getLogger(this.getClass());
@SneakyThrows
@Timed
public Organization getById(String id) {
var doc = solrRepository.getById(id);
@ -50,7 +48,6 @@ public class OrganizationService {
}
@SneakyThrows
@Timed
public SearchResponse<Organization> search(OrganizationRequest request) {
SolrQueryParams solrQueryParams = organizationRequestMapper.toSolrQuery(request);

View File

@ -11,7 +11,6 @@ import eu.openaire.api.mappers.response.ResponseResultsMapper;
import eu.openaire.api.mappers.response.entities.ProjectMapper;
import eu.openaire.api.repositories.SolrRepository;
import eu.openaire.api.solr.SolrQueryParams;
import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
@ -38,7 +37,6 @@ public class ProjectService {
private final Logger log = LogManager.getLogger(this.getClass());
@SneakyThrows
@Timed
public Project getById(String id) {
var doc = solrRepository.getById(id);
@ -50,7 +48,6 @@ public class ProjectService {
}
@SneakyThrows
@Timed
public SearchResponse<Project> search(ProjectRequest request) {
SolrQueryParams solrQueryParams = projectRequestMapper.toSolrQuery(request);

View File

@ -11,7 +11,6 @@ import eu.openaire.api.mappers.response.ResponseResultsMapper;
import eu.openaire.api.mappers.response.entities.ResearchProductMapper;
import eu.openaire.api.repositories.SolrRepository;
import eu.openaire.api.solr.SolrQueryParams;
import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
@ -38,7 +37,6 @@ public class ResearchProductService {
private final Logger log = LogManager.getLogger(this.getClass());
@SneakyThrows
@Timed
public GraphResult getById(String id) {
var doc = solrRepository.getById(id);
@ -51,7 +49,6 @@ public class ResearchProductService {
}
@SneakyThrows
@Timed
public SearchResponse<GraphResult> search(ResearchProductsRequest request) {
SolrQueryParams solrQueryParams = researchProductsRequestMapper.toSolrQuery(request);

View File

@ -15,10 +15,8 @@ server.error.include-stacktrace=never
# Enable the health endpoint
management.endpoint.health.enabled=true
# Expose health, info and metrics endpoint
management.endpoints.web.exposure.include=health,info,prometheus
management.endpoint.prometheus.enabled=true
management.metrics.export.prometheus.enabled=true
# Expose the health endpoint
management.endpoints.web.exposure.include=health,info
# Customize health endpoint settings
management.endpoint.health.show-details=always