diff --git a/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/common/AbstractExporterController.java b/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/common/AbstractExporterController.java index c11e15f0..711b7eb2 100644 --- a/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/common/AbstractExporterController.java +++ b/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/common/AbstractExporterController.java @@ -3,12 +3,9 @@ package eu.dnetlib.openaire.common; import java.util.List; import java.util.stream.Collectors; -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import eu.dnetlib.enabling.datasources.common.DsmException; -import eu.dnetlib.enabling.datasources.common.DsmForbiddenException; -import eu.dnetlib.enabling.datasources.common.DsmNotFoundException; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.commons.lang3.time.StopWatch; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.http.HttpStatus; @@ -17,6 +14,13 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; +import com.fasterxml.jackson.annotation.JsonAutoDetect; + +import eu.dnetlib.enabling.datasources.common.DsmException; +import eu.dnetlib.enabling.datasources.common.DsmForbiddenException; +import eu.dnetlib.enabling.datasources.common.DsmNotFoundException; +import eu.dnetlib.openaire.dsm.domain.Response; + /** * Created by claudio on 18/07/2017. */ @@ -25,7 +29,9 @@ public abstract class AbstractExporterController { private static final Log log = LogFactory.getLog(AbstractExporterController.class); // NOPMD by marko on 11/24/08 5:02 PM @ResponseBody - @ExceptionHandler({DsmException.class}) + @ExceptionHandler({ + DsmException.class + }) @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) public ErrorMessage handleDSMException(final Exception e) { return _handleError(e); @@ -39,7 +45,9 @@ public abstract class AbstractExporterController { } @ResponseBody - @ExceptionHandler({DsmNotFoundException.class}) + @ExceptionHandler({ + DsmNotFoundException.class + }) @ResponseStatus(value = HttpStatus.NOT_FOUND) public ErrorMessage handleNotFoundException(final Exception e) { return _handleError(e); @@ -50,23 +58,33 @@ public abstract class AbstractExporterController { @ResponseStatus(HttpStatus.BAD_REQUEST) public List processValidationError(final MethodArgumentNotValidException e) { return e.getBindingResult() - .getFieldErrors().stream() - .map(fe -> new ErrorMessage( - String.format("field '%s'", fe.getField()), - String.format("rejected value '%s'", fe.getRejectedValue()), - fe.getDefaultMessage())) - .collect(Collectors.toList()); + .getFieldErrors() + .stream() + .map(fe -> new ErrorMessage( + String.format("field '%s'", fe.getField()), + String.format("rejected value '%s'", fe.getRejectedValue()), + fe.getDefaultMessage())) + .collect(Collectors.toList()); } private ErrorMessage _handleError(final Exception e) { log.error(e); if (StringUtils.containsIgnoreCase(ExceptionUtils.getRootCauseMessage(e), "Broken pipe")) { - return null; //socket is closed, cannot return any response + return null; // socket is closed, cannot return any response } else { return new ErrorMessage(e); } } + // HELPERS + protected T prepareResponse(final int page, final int size, final StopWatch stopWatch, final T rsp) { + rsp.getHeader() + .setTime(stopWatch.getTime()) + .setPage(page) + .setSize(size); + return rsp; + } + @JsonAutoDetect public class ErrorMessage { diff --git a/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/dsm/DsmApiController.java b/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/dsm/DsmApiController.java index 99450dc5..180cf716 100755 --- a/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/dsm/DsmApiController.java +++ b/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/dsm/DsmApiController.java @@ -16,10 +16,11 @@ import org.apache.http.HttpStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -28,7 +29,6 @@ import eu.dnetlib.enabling.datasources.common.DsmForbiddenException; import eu.dnetlib.enabling.datasources.common.DsmNotFoundException; import eu.dnetlib.openaire.common.AbstractExporterController; import eu.dnetlib.openaire.common.OperationManager; -import eu.dnetlib.openaire.dsm.dao.ResponseUtils; import eu.dnetlib.openaire.dsm.domain.AggregationHistoryResponse; import eu.dnetlib.openaire.dsm.domain.ApiDetails; import eu.dnetlib.openaire.dsm.domain.ApiDetailsResponse; @@ -41,8 +41,6 @@ import eu.dnetlib.openaire.dsm.domain.RegisteredDatasourceInfo; import eu.dnetlib.openaire.dsm.domain.RequestFilter; import eu.dnetlib.openaire.dsm.domain.RequestSort; import eu.dnetlib.openaire.dsm.domain.RequestSortOrder; -import eu.dnetlib.openaire.dsm.domain.Response; -import eu.dnetlib.openaire.dsm.domain.SimpleDatasourceInfo; import eu.dnetlib.openaire.dsm.domain.SimpleResponse; import eu.dnetlib.openaire.vocabularies.Country; import io.swagger.v3.oas.annotations.Operation; @@ -61,9 +59,9 @@ public class DsmApiController extends AbstractExporterController { @Autowired private DsmCore dsmCore; - @RequestMapping(value = "/ds/countries", produces = { + @GetMapping(value = "/ds/countries", produces = { "application/json" - }, method = RequestMethod.GET) + }) @Operation(summary = "list the datasource countries", description = "list the datasource countries", tags = { DS, R }) @@ -75,9 +73,9 @@ public class DsmApiController extends AbstractExporterController { return dsmCore.listCountries(); } - @RequestMapping(value = "/ds/searchdetails/{page}/{size}", produces = { + @PostMapping(value = "/ds/searchdetails/{page}/{size}", produces = { "application/json" - }, method = RequestMethod.POST) + }) @Operation(summary = "search datasources", description = "Returns list of Datasource details.", tags = { DS, R }) @@ -96,9 +94,9 @@ public class DsmApiController extends AbstractExporterController { return prepareResponse(page, size, stop, rsp); } - @RequestMapping(value = "/ds/aggregationhistory/{dsId}", produces = { + @GetMapping(value = "/ds/aggregationhistory/{dsId}", produces = { "application/json" - }, method = RequestMethod.GET) + }) @Operation(summary = "search datasources", description = "Returns list of Datasource details.", tags = { DS, R }) @@ -112,9 +110,9 @@ public class DsmApiController extends AbstractExporterController { return prepareResponse(0, rsp.getAggregationInfo().size(), stop, rsp); } - @RequestMapping(value = "/ds/searchsnippet/{page}/{size}", produces = { + @PostMapping(value = "/ds/searchsnippet/{page}/{size}", produces = { "application/json" - }, method = RequestMethod.POST) + }) @Operation(summary = "search datasources", description = "Returns list of Datasource basic info.", tags = { DS, R }) @@ -133,9 +131,9 @@ public class DsmApiController extends AbstractExporterController { return prepareResponse(page, size, stop, rsp); } - @RequestMapping(value = "/ds/searchregistered/{page}/{size}", produces = { + @PostMapping(value = "/ds/searchregistered/{page}/{size}", produces = { "application/json" - }, method = RequestMethod.POST) + }) @Operation(summary = "search among registered datasources", description = "Returns list of Datasource basic info.", tags = { DS, R @@ -155,9 +153,9 @@ public class DsmApiController extends AbstractExporterController { return prepareResponse(page, size, stop, rsp); } - @RequestMapping(value = "/ds/recentregistered/{size}", produces = { + @GetMapping(value = "/ds/recentregistered/{size}", produces = { "application/json" - }, method = RequestMethod.GET) + }) @Operation(summary = "return the latest datasources that were registered through Provide", description = "Returns list of Datasource basic info.", tags = { DS, R @@ -172,9 +170,9 @@ public class DsmApiController extends AbstractExporterController { return prepareResponse(1, size, stop, rsp); } - @RequestMapping(value = "/ds/countregistered", produces = { + @GetMapping(value = "/ds/countregistered", produces = { "application/json" - }, method = RequestMethod.GET) + }) @Operation(summary = "return the number of datasources registered after the given date", description = "Returns a number.", tags = { DS, R @@ -188,9 +186,9 @@ public class DsmApiController extends AbstractExporterController { return dsmCore.countRegisteredAfter(fromDate, typologyFilter); } - @RequestMapping(value = "/ds/api/{dsId}", produces = { + @GetMapping(value = "/ds/api/{dsId}", produces = { "application/json" - }, method = RequestMethod.GET) + }) @Operation(summary = "get the list of API for a given datasource", description = "Returns the list of API for a given datasource.", tags = { API, R @@ -207,9 +205,9 @@ public class DsmApiController extends AbstractExporterController { return prepareResponse(0, rsp.getApi().size(), stop, rsp); } - @RequestMapping(value = "/api/baseurl/{page}/{size}", produces = { + @PostMapping(value = "/api/baseurl/{page}/{size}", produces = { "application/json" - }, method = RequestMethod.POST) + }) @Operation(summary = "search for the list of base URLs of Datasource APIs managed by a user", description = "Returns the list of base URLs of Datasource APIs managed by a user", tags = { DS, API, R }) @@ -225,7 +223,7 @@ public class DsmApiController extends AbstractExporterController { return dsmCore.findBaseURLs(requestFilter, page, size); } - @RequestMapping(value = "/ds/api/{apiId}", method = RequestMethod.DELETE) + @DeleteMapping(value = "/ds/api/{apiId}") @Operation(summary = "delete an API", description = "delete an API, if removable", tags = { API, W }) @@ -239,7 +237,7 @@ public class DsmApiController extends AbstractExporterController { dsmCore.deleteApi(apiId); } - @RequestMapping(value = "/ds/manage", method = RequestMethod.POST) + @PostMapping(value = "/ds/manage") @Operation(summary = "set the managed status for a given datasource", description = "set the managed status for a given datasource", tags = { DS, W }) @@ -254,7 +252,7 @@ public class DsmApiController extends AbstractExporterController { dsmCore.setManaged(id, managed); } - @RequestMapping(value = "/ds/managed/{id}", method = RequestMethod.GET) + @GetMapping(value = "/ds/managed/{id}") @Operation(summary = "get the datasource managed status", description = "get the datasource managed status", tags = { DS, R }) @@ -266,7 +264,7 @@ public class DsmApiController extends AbstractExporterController { return dsmCore.isManaged(id); } - @RequestMapping(value = "/ds/add", method = RequestMethod.POST) + @PostMapping(value = "/ds/add") @Operation(summary = "add a new Datasource", description = "add a new Datasource", tags = { DS, W }) @@ -283,7 +281,7 @@ public class DsmApiController extends AbstractExporterController { dsmCore.save(datasource); } - @RequestMapping(value = "/ds/addWithApis", method = RequestMethod.POST) + @PostMapping(value = "/ds/addWithApis") @Operation(summary = "add a new Datasource and its apis", description = "add a new Datasource and its apis", tags = { DS, W }) @@ -300,7 +298,7 @@ public class DsmApiController extends AbstractExporterController { dsmCore.save(d); } - @RequestMapping(value = "/ds/update", method = RequestMethod.POST) + @PostMapping(value = "/ds/update") @Operation(summary = "update Datasource details", description = "update Datasource details", tags = { DS, W }) @@ -314,7 +312,7 @@ public class DsmApiController extends AbstractExporterController { dsmCore.updateDatasource(ds); } - @RequestMapping(value = "/ds/api/baseurl", method = RequestMethod.POST) + @PostMapping(value = "/ds/api/baseurl") @Operation(summary = "update the base URL of a datasource interface", description = "update the base URL of a datasource interface", tags = { API, W }) @@ -330,7 +328,7 @@ public class DsmApiController extends AbstractExporterController { dsmCore.updateApiBaseurl(dsId, apiId, baseUrl); } - @RequestMapping(value = "/ds/api/compliance", method = RequestMethod.POST) + @PostMapping(value = "/ds/api/compliance") @Operation(summary = "update the compatibility of a datasource interface", description = "update the compatibility of a datasource interface", tags = { API, W }) @@ -347,7 +345,7 @@ public class DsmApiController extends AbstractExporterController { dsmCore.updateApiCompatibility(dsId, apiId, compliance, override); } - @RequestMapping(value = "/ds/api/oaiset", method = RequestMethod.POST) + @PostMapping(value = "/ds/api/oaiset") @Operation(summary = "update the OAI set of a datasource interface", description = "update the OAI set of a datasource interface", tags = { API, W }) @@ -363,7 +361,7 @@ public class DsmApiController extends AbstractExporterController { dsmCore.updateApiOaiSet(dsId, apiId, oaiSet); } - @RequestMapping(value = "/ds/api/add", method = RequestMethod.POST) + @PostMapping(value = "/ds/api/add") @Operation(summary = "adds a new Interface to one Datasource", description = "adds an Interface to one Datasource", tags = { API, W }) @@ -381,7 +379,7 @@ public class DsmApiController extends AbstractExporterController { @Autowired private OperationManager operationManager; - @RequestMapping(value = "/dsm/ops", method = RequestMethod.GET) + @GetMapping(value = "/dsm/ops") @Operation(summary = "get the number of pending operations", description = "get the number of pending operations", tags = { R, M }) @@ -393,7 +391,7 @@ public class DsmApiController extends AbstractExporterController { return operationManager.getOpSize(); } - @RequestMapping(value = "/dsm/killops", method = RequestMethod.POST) + @PostMapping(value = "/dsm/killops") @Operation(summary = "interrupts the pending operations", description = "return the number of interrupted operations", tags = { W, M }) @@ -405,7 +403,7 @@ public class DsmApiController extends AbstractExporterController { return operationManager.dropAll(); } - @RequestMapping(value = "/dsm/dropcache", method = RequestMethod.POST) + @PostMapping(value = "/dsm/dropcache") @Operation(summary = "drop the caches", description = "drop the internal caches", tags = { W, M }) @@ -417,68 +415,4 @@ public class DsmApiController extends AbstractExporterController { dsmCore.dropCaches(); } - // HELPERS - private T prepareResponse(final int page, final int size, final StopWatch stopWatch, final T rsp) { - rsp.getHeader() - .setTime(stopWatch.getTime()) - .setPage(page) - .setSize(size); - return rsp; - } - - // ------------------------------ - - @RequestMapping(value = "/ds/recentregistered/v2/{size}", produces = { - "application/json" - }, method = RequestMethod.GET) - @Operation(summary = "return the latest datasources that were registered through Provide (v2)", description = "Returns list of Datasource basic info.", tags = { - DS, - R - }) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK"), - @ApiResponse(responseCode = "500", description = "unexpected error") - }) - public SimpleResponse recentRegisteredV2(@PathVariable final int size) throws Throwable { - final StopWatch stop = StopWatch.createStarted(); - final SimpleResponse rsp = dsmCore.searchRecentRegisteredV2(size); - return prepareResponse(1, size, stop, rsp); - } - - @RequestMapping(value = "/ds/countfirstcollect", produces = { - "application/json" - }, method = RequestMethod.GET) - @Operation(summary = "return the number of datasources registered after the given date", description = "Returns a number.", tags = { - DS, - R - }) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK"), - @ApiResponse(responseCode = "500", description = "unexpected error") - }) - public Long countFirstCollectAfter(@RequestParam final String fromDate, - @RequestParam(required = false) final String typologyFilter) throws Throwable { - return dsmCore.countFirstCollect(fromDate, typologyFilter); - } - - @RequestMapping(value = "/ds/firstCollected", produces = { - "application/json" - }, method = RequestMethod.GET) - @Operation(summary = "return the datasources that were collected for the first time after the specified date", description = "Returns list of Datasource basic info.", tags = { - DS, - R - }) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK"), - @ApiResponse(responseCode = "500", description = "unexpected error") - }) - public SimpleResponse firstCollectedAfter(@RequestParam final String fromDate, - @RequestParam(required = false) final String typologyFilter) throws Throwable { - final StopWatch stop = StopWatch.createStarted(); - final List list = dsmCore.getFirstCollectedAfter(fromDate, typologyFilter); - final SimpleResponse rsp = ResponseUtils.simpleResponse(list); - - return prepareResponse(1, list.size(), stop, rsp); - } - } diff --git a/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/dsm/DsmApiControllerV2.java b/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/dsm/DsmApiControllerV2.java new file mode 100644 index 00000000..356494e5 --- /dev/null +++ b/apps/dnet-exporter-api/src/main/java/eu/dnetlib/openaire/dsm/DsmApiControllerV2.java @@ -0,0 +1,86 @@ +package eu.dnetlib.openaire.dsm; + +import static eu.dnetlib.openaire.common.ExporterConstants.DS; +import static eu.dnetlib.openaire.common.ExporterConstants.R; + +import java.util.List; + +import org.apache.commons.lang3.time.StopWatch; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import eu.dnetlib.openaire.common.AbstractExporterController; +import eu.dnetlib.openaire.dsm.dao.ResponseUtils; +import eu.dnetlib.openaire.dsm.domain.SimpleDatasourceInfo; +import eu.dnetlib.openaire.dsm.domain.SimpleResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +@RestController +@CrossOrigin(origins = { + "*" +}) +@ConditionalOnProperty(value = "openaire.exporter.enable.dsm", havingValue = "true") +@Tag(name = "OpenAIRE DSM API (version 2.0)", description = "the OpenAIRE Datasource Manager API 2.0") +@RequestMapping("/dsm/2.0") +public class DsmApiControllerV2 extends AbstractExporterController { + + @Autowired + private DsmCore dsmCore; + + @GetMapping("/recentregistered/{size}") + @Operation(summary = "return the latest datasources that were registered through Provide (v2)", description = "Returns list of Datasource basic info.", tags = { + DS, + R + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "500", description = "unexpected error") + }) + public SimpleResponse recentRegisteredV2(@PathVariable final int size) throws Throwable { + final StopWatch stop = StopWatch.createStarted(); + final SimpleResponse rsp = dsmCore.searchRecentRegisteredV2(size); + return prepareResponse(1, size, stop, rsp); + } + + @GetMapping("/countfirstcollect") + @Operation(summary = "return the number of datasources registered after the given date", description = "Returns a number.", tags = { + DS, + R + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "500", description = "unexpected error") + }) + public Long countFirstCollectAfter(@RequestParam final String fromDate, + @RequestParam(required = false) final String typologyFilter) throws Throwable { + return dsmCore.countFirstCollect(fromDate, typologyFilter); + } + + @GetMapping("/firstCollected") + @Operation(summary = "return the datasources that were collected for the first time after the specified date", description = "Returns list of Datasource basic info.", tags = { + DS, + R + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "500", description = "unexpected error") + }) + public SimpleResponse firstCollectedAfter(@RequestParam final String fromDate, + @RequestParam(required = false) final String typologyFilter) throws Throwable { + final StopWatch stop = StopWatch.createStarted(); + final List list = dsmCore.getFirstCollectedAfter(fromDate, typologyFilter); + final SimpleResponse rsp = ResponseUtils.simpleResponse(list); + + return prepareResponse(1, list.size(), stop, rsp); + } + +}