Compare commits
No commits in common. "master" and "jsonPayload" have entirely different histories.
master
...
jsonPayloa
15
pom.xml
15
pom.xml
|
@ -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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,10 +10,6 @@ import lombok.Data;
|
|||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import static eu.openaire.api.mappers.Utils.API_CURSOR_DESC;
|
||||
import static eu.openaire.api.mappers.Utils.API_PAGE_DESC;
|
||||
import static eu.openaire.api.mappers.Utils.API_PAGE_SIZE_DESC;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Data
|
||||
|
@ -96,7 +92,7 @@ public class DataSourceRequest implements PaginatedRequest {
|
|||
|
||||
@Min(value = 1)
|
||||
@Parameter(
|
||||
description = API_PAGE_DESC,
|
||||
description = "Page number of the results",
|
||||
schema = @Schema(defaultValue = "1", type = "integer")
|
||||
)
|
||||
private int page = 1;
|
||||
|
@ -104,17 +100,11 @@ public class DataSourceRequest implements PaginatedRequest {
|
|||
@Min(value = 1, message = "Page size must be at least 1")
|
||||
@Max(value = 100, message = "Page size must be at most 100")
|
||||
@Parameter(
|
||||
description = API_PAGE_SIZE_DESC,
|
||||
description = "Number of results per page",
|
||||
schema = @Schema(defaultValue = "10", type = "integer")
|
||||
)
|
||||
private int pageSize = 10;
|
||||
|
||||
@Parameter(
|
||||
description = API_CURSOR_DESC,
|
||||
schema = @Schema(type = "string")
|
||||
)
|
||||
private String cursor;
|
||||
|
||||
@Parameter(
|
||||
description = "The field to sort the results by and the sort direction. The format should be in the format `fieldname ASC|DESC`, organizations can be only sorted by the 'relevance'." ,
|
||||
schema = @Schema(defaultValue = "relevance DESC")
|
||||
|
|
|
@ -10,10 +10,6 @@ import lombok.Data;
|
|||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import static eu.openaire.api.mappers.Utils.API_CURSOR_DESC;
|
||||
import static eu.openaire.api.mappers.Utils.API_PAGE_DESC;
|
||||
import static eu.openaire.api.mappers.Utils.API_PAGE_SIZE_DESC;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Data
|
||||
|
@ -75,22 +71,19 @@ public class OrganizationRequest implements PaginatedRequest {
|
|||
|
||||
@Min(value = 1)
|
||||
@Parameter(
|
||||
description = API_PAGE_DESC,
|
||||
schema = @Schema(defaultValue = "1", type = "integer"))
|
||||
description = "Page number of the results",
|
||||
schema = @Schema(defaultValue = "1", type = "integer")
|
||||
)
|
||||
private int page = 1;
|
||||
|
||||
@Min(value = 1, message = "Page size must be at least 1")
|
||||
@Max(value = 100, message = "Page size must be at most 100")
|
||||
@Parameter(
|
||||
description = API_PAGE_SIZE_DESC,
|
||||
schema = @Schema(defaultValue = "10", type = "integer"))
|
||||
description = "Number of results per page",
|
||||
schema = @Schema(defaultValue = "10", type = "integer")
|
||||
)
|
||||
private int pageSize = 10;
|
||||
|
||||
@Parameter(
|
||||
description = API_CURSOR_DESC,
|
||||
schema = @Schema(type = "string"))
|
||||
private String cursor;
|
||||
|
||||
@Parameter(
|
||||
description = "The field to sort the results by and the sort direction. The format should be in the format `fieldname ASC|DESC`, organizations can be only sorted by the 'relevance'." ,
|
||||
schema = @Schema(defaultValue = "relevance DESC")
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package eu.openaire.api.dto.request;
|
||||
|
||||
public interface PaginatedRequest {
|
||||
|
||||
int getPage();
|
||||
|
||||
int getPageSize();
|
||||
String getCursor();
|
||||
}
|
||||
|
|
|
@ -9,10 +9,9 @@ import jakarta.validation.constraints.Pattern;
|
|||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import static eu.openaire.api.mappers.Utils.API_CURSOR_DESC;
|
||||
import static eu.openaire.api.mappers.Utils.API_PAGE_DESC;
|
||||
import static eu.openaire.api.mappers.Utils.API_PAGE_SIZE_DESC;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
@ -74,28 +73,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",
|
||||
|
@ -135,22 +138,19 @@ public class ProjectRequest implements PaginatedRequest {
|
|||
|
||||
@Min(value = 1)
|
||||
@Parameter(
|
||||
description = API_PAGE_DESC,
|
||||
schema = @Schema(defaultValue = "1", type = "integer"))
|
||||
description = "Page number of the results",
|
||||
schema = @Schema(defaultValue = "1", type = "integer")
|
||||
)
|
||||
private int page = 1;
|
||||
|
||||
@Min(value = 1, message = "Page size must be at least 1")
|
||||
@Max(value = 100, message = "Page size must be at most 100")
|
||||
@Parameter(
|
||||
description = API_PAGE_SIZE_DESC,
|
||||
schema = @Schema(defaultValue = "10", type = "integer"))
|
||||
description = "Number of results per page",
|
||||
schema = @Schema(defaultValue = "10", type = "integer")
|
||||
)
|
||||
private int pageSize = 10;
|
||||
|
||||
@Parameter(
|
||||
description = API_CURSOR_DESC,
|
||||
schema = @Schema(type = "string"))
|
||||
private String cursor;
|
||||
|
||||
@Parameter(
|
||||
description = "The field to sort the results by and the sort direction. The format should be in the format `fieldname ASC|DESC`, where fieldname is one of 'relevance', 'startDate', 'endDate'. Multiple sorting parameters should be comma-separated." ,
|
||||
schema = @Schema(defaultValue = "relevance DESC")
|
||||
|
|
|
@ -9,10 +9,9 @@ import jakarta.validation.constraints.Pattern;
|
|||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import static eu.openaire.api.mappers.Utils.API_CURSOR_DESC;
|
||||
import static eu.openaire.api.mappers.Utils.API_PAGE_DESC;
|
||||
import static eu.openaire.api.mappers.Utils.API_PAGE_SIZE_DESC;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
@ -73,14 +72,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",
|
||||
|
@ -291,7 +294,7 @@ public class ResearchProductsRequest implements PaginatedRequest {
|
|||
|
||||
@Min(value = 1)
|
||||
@Parameter(
|
||||
description = API_PAGE_DESC,
|
||||
description = "Page number of the results",
|
||||
schema = @Schema(defaultValue = "1", type = "integer")
|
||||
)
|
||||
private int page = 1;
|
||||
|
@ -299,17 +302,11 @@ public class ResearchProductsRequest implements PaginatedRequest {
|
|||
@Min(value = 1, message = "Page size must be at least 1")
|
||||
@Max(value = 100, message = "Page size must be at most 100")
|
||||
@Parameter(
|
||||
description = API_PAGE_SIZE_DESC,
|
||||
description = "Number of results per page",
|
||||
schema = @Schema(defaultValue = "10", type = "integer")
|
||||
)
|
||||
private int pageSize = 10;
|
||||
|
||||
@Parameter(
|
||||
description = API_CURSOR_DESC,
|
||||
schema = @Schema(type = "string")
|
||||
)
|
||||
private String cursor;
|
||||
|
||||
@Parameter(
|
||||
description = "The field to sort the results by and the sort direction. The format should be in the format `fieldname ASC|DESC`, where fieldname is one of 'relevance', 'publicationDate', 'dateOfCollection', 'influence', 'popularity', 'citationCount', 'impulse'. Multiple sorting parameters should be comma-separated.",
|
||||
schema = @Schema(defaultValue = "relevance DESC")
|
||||
|
|
|
@ -11,7 +11,7 @@ public class PaginationValidator implements Validator {
|
|||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private static final int MAX_RESULTS = 10000;
|
||||
private final int MAX_RESULTS = 10000;
|
||||
|
||||
public PaginationValidator(HttpServletRequest request) {
|
||||
this.request = request;
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
package eu.openaire.api.dto.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import static eu.openaire.api.mappers.Utils.API_NEXT_CURSOR_DESC;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class SearchHeader {
|
||||
private SearchHeaderDebug debug;
|
||||
private Long numFound;
|
||||
private Float maxScore;
|
||||
private Integer queryTime;
|
||||
private Integer page;
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = API_NEXT_CURSOR_DESC)
|
||||
private String nextCursor;
|
||||
private SearchHeaderDebug debug;
|
||||
|
||||
private long numFound;
|
||||
|
||||
private float maxScore;
|
||||
|
||||
private int queryTime;
|
||||
|
||||
private int page;
|
||||
|
||||
private int pageSize;
|
||||
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@ import org.springframework.web.context.request.WebRequest;
|
|||
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestControllerAdvice
|
||||
|
@ -23,9 +21,6 @@ public class ServiceExceptionHandler {
|
|||
|
||||
private final Logger log = LogManager.getLogger(this.getClass());
|
||||
|
||||
private static final String URL_REGEX = "https?://\\S*";
|
||||
private static final Pattern URL_PATTERN = Pattern.compile(URL_REGEX);
|
||||
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
public ResponseEntity<ErrorResponse> handleNotFoundException(NotFoundException e, WebRequest request) {
|
||||
return this.handleException(e.getMessage(), request, HttpStatus.NOT_FOUND);
|
||||
|
@ -55,9 +50,8 @@ public class ServiceExceptionHandler {
|
|||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ErrorResponse> handleAllOtherExceptions(Exception e, WebRequest request) {
|
||||
//todo: log4j2.xml - add error appender
|
||||
e.printStackTrace();
|
||||
return this.handleException(e.getMessage(), request, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
return this.handleException("An internal server error occurred", request, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
private ResponseEntity<ErrorResponse> handleException(String message, WebRequest request, HttpStatus httpStatus) {
|
||||
|
@ -65,7 +59,7 @@ public class ServiceExceptionHandler {
|
|||
String path = String.format("%s?%s", req.getRequestURI(), req.getQueryString());
|
||||
|
||||
ErrorResponse response = ErrorResponse.builder()
|
||||
.message(obfuscateUrlsInMessage(message))
|
||||
.message(message)
|
||||
.error(httpStatus.getReasonPhrase())
|
||||
.code(httpStatus.value())
|
||||
.timestamp(new Date())
|
||||
|
@ -76,9 +70,4 @@ public class ServiceExceptionHandler {
|
|||
.status(httpStatus)
|
||||
.body(response);
|
||||
}
|
||||
|
||||
private static String obfuscateUrlsInMessage(String message) {
|
||||
Matcher matcher = URL_PATTERN.matcher(message);
|
||||
return matcher.replaceAll("[https://***].");
|
||||
}
|
||||
}
|
|
@ -9,37 +9,11 @@ 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 {
|
||||
|
||||
private Utils() {}
|
||||
|
||||
public static final String API_PAGE_DESC = """
|
||||
Page number of the results,\s
|
||||
used for basic start/rows pagination.\s
|
||||
Max dataset to retrieve - 10000 records.\s
|
||||
To get more than that, use cursor-based pagination.""";
|
||||
|
||||
public static final String API_PAGE_SIZE_DESC = "Number of results per page";
|
||||
|
||||
/* todo: maybe mention that if a big dataset is required, then download directly the compressed data file
|
||||
like this, we avoid high load on this microservice */
|
||||
public static final String API_CURSOR_DESC = """
|
||||
Cursor-based pagination. Initial value: `cursor=*`.\s
|
||||
Cursor should be used when it is required to retrieve a big dataset (more than 10000 records).\s
|
||||
To get the next page of results, use nextCursor returned in the response.
|
||||
""";
|
||||
|
||||
public static final String API_NEXT_CURSOR_DESC = """
|
||||
nextCursor - to be used in the next request to get the next page of results.\s
|
||||
You can repeat this process until you’ve fetched as many results as you want,\s
|
||||
or until the nextCursor returned matches the current cursor you’ve already specified,\s
|
||||
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 +26,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 +48,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 +138,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 +175,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;
|
||||
|
|
|
@ -14,7 +14,6 @@ public interface DataSourceRequestMapper {
|
|||
@Mapping(target = "start", expression = "java( calculateStart(src.getPage(), src.getPageSize()) )")
|
||||
@Mapping(target = "rows", source = "pageSize")
|
||||
@Mapping(target = "debugQuery", source = "debugQuery")
|
||||
@Mapping(target = "cursor", source = "cursor")
|
||||
@Mapping(target = "sort", expression = "java( eu.openaire.api.mappers.Utils.formatSortByParam(src.getSortBy(), SolrFieldsMapper.dataSourceSortMapping) )")
|
||||
SolrQueryParams toSolrQuery(DataSourceRequest src);
|
||||
|
||||
|
|
|
@ -4,33 +4,23 @@ import eu.openaire.api.dto.response.SearchHeader;
|
|||
import eu.openaire.api.dto.response.SearchHeaderDebug;
|
||||
import eu.openaire.api.solr.SolrQueryParams;
|
||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingTarget;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface ResponseHeaderMapper {
|
||||
|
||||
@Mapping(target = "numFound", expression = "java( Long.valueOf(queryResponse.getResults().getNumFound()) )")
|
||||
@Mapping(target = "numFound", source = "queryResponse.results.numFound")
|
||||
@Mapping(target = "maxScore", source = "queryResponse.results.maxScore")
|
||||
@Mapping(target = "page", source = "page")
|
||||
@Mapping(target = "pageSize", source = "pageSize")
|
||||
@Mapping(target = "nextCursor", source = "queryResponse.nextCursorMark")
|
||||
@Mapping(target = "queryTime", expression = "java( (int) queryResponse.getHeader().get(\"QTime\") )")
|
||||
@Mapping(target = "debug", expression = "java( mapDebug(queryResponse, solrQueryParams, debugQuery) )")
|
||||
SearchHeader toSearchHeader(QueryResponse queryResponse, SolrQueryParams solrQueryParams,
|
||||
boolean debugQuery, int page, int pageSize);
|
||||
|
||||
@AfterMapping
|
||||
default void removePage(@MappingTarget SearchHeader searchHeader) {
|
||||
if (searchHeader.getNextCursor() != null) {
|
||||
searchHeader.setPage(null);
|
||||
}
|
||||
}
|
||||
|
||||
default SearchHeaderDebug mapDebug(QueryResponse queryResponse, SolrQueryParams solrQueryParams, boolean debugQuery) {
|
||||
if (!debugQuery) {
|
||||
return null;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import org.apache.solr.client.solrj.SolrServerException;
|
|||
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||
import org.apache.solr.client.solrj.response.SolrPingResponse;
|
||||
import org.apache.solr.common.SolrDocument;
|
||||
import org.apache.solr.common.params.CursorMarkParams;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -20,33 +19,31 @@ import java.io.IOException;
|
|||
public class SolrRepository {
|
||||
|
||||
private final SolrConnectionManager solrConnectionManager;
|
||||
|
||||
private final Logger log = LogManager.getLogger(this.getClass());
|
||||
private static final String UNIQUE_KEY = "__indexrecordidentifier";
|
||||
|
||||
public SolrDocument getById(String id) throws SolrServerException, IOException {
|
||||
return solrConnectionManager.getSolrClient().getById(id);
|
||||
}
|
||||
|
||||
public QueryResponse query(SolrQueryParams queryParams) throws SolrServerException, IOException {
|
||||
SolrQuery query = new SolrQuery();
|
||||
query.setQuery(queryParams.getQueryString()); // add Q
|
||||
|
||||
for (String fq : queryParams.getFilterQueries()) { // add FQ
|
||||
SolrQuery query = new SolrQuery();
|
||||
|
||||
// add Q
|
||||
query.setQuery(queryParams.getQueryString());
|
||||
|
||||
// add FQ
|
||||
for (String fq : queryParams.getFilterQueries()) {
|
||||
query.addFilterQuery(fq);
|
||||
}
|
||||
|
||||
query.addField(queryParams.getFieldList()); // add FL
|
||||
// add FL
|
||||
query.addField(queryParams.getFieldList());
|
||||
|
||||
// set pagination
|
||||
query.setRows(queryParams.getRows());
|
||||
String cursor = queryParams.getCursor();
|
||||
|
||||
if (cursor != null && !cursor.isEmpty()) { // set cursor-based pagination
|
||||
query.set(CursorMarkParams.CURSOR_MARK_PARAM, cursor);
|
||||
query.addSort(UNIQUE_KEY, SolrQuery.ORDER.asc);
|
||||
} else { // set basic page/page-size pagination
|
||||
// set pagination parameters
|
||||
query.setStart(queryParams.getStart());
|
||||
}
|
||||
query.setRows(queryParams.getRows());
|
||||
|
||||
// set sorting
|
||||
for (var sortClause : queryParams.getSort()) {
|
||||
|
@ -58,16 +55,10 @@ public class SolrRepository {
|
|||
query.set("debugQuery", "on");
|
||||
}
|
||||
|
||||
try {
|
||||
log.info(query);
|
||||
|
||||
return solrConnectionManager.getSolrClient().query(query);
|
||||
} catch (SolrServerException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SolrServerException(e);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public SolrPingResponse ping() throws SolrServerException, IOException {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -2,16 +2,24 @@ package eu.openaire.api.solr;
|
|||
|
||||
import lombok.Data;
|
||||
import org.apache.solr.client.solrj.SolrQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class SolrQueryParams {
|
||||
private String queryString = "*:*";
|
||||
private List<String> filterQueries;
|
||||
private String fieldList = "__json";
|
||||
private Boolean debugQuery = false;
|
||||
private int start;
|
||||
private int rows;
|
||||
private List<SolrQuery.SortClause> sort;
|
||||
private String cursor;
|
||||
|
||||
String queryString = "*:*";
|
||||
|
||||
List<String> filterQueries;
|
||||
|
||||
String fieldList = "__json";
|
||||
|
||||
Boolean debugQuery = false;
|
||||
|
||||
int start;
|
||||
|
||||
int rows;
|
||||
|
||||
List<SolrQuery.SortClause> sort;
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue