495 lines
18 KiB
Java
495 lines
18 KiB
Java
package eu.dnetlib.openaire.dsm;
|
|
|
|
import static eu.dnetlib.openaire.dsm.dao.utils.DsmMappingUtils.asDbEntry;
|
|
import static eu.dnetlib.openaire.dsm.dao.utils.DsmMappingUtils.asDetails;
|
|
import static eu.dnetlib.openaire.dsm.dao.utils.DsmMappingUtils.copyNonNullProperties;
|
|
import static eu.dnetlib.openaire.dsm.dao.utils.DsmMappingUtils.createId;
|
|
|
|
import java.nio.charset.Charset;
|
|
import java.util.Collection;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.Set;
|
|
import java.util.function.Function;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Stream;
|
|
|
|
import javax.transaction.Transactional;
|
|
|
|
import org.apache.commons.io.IOUtils;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
import org.springframework.data.domain.Page;
|
|
import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
import org.springframework.jdbc.core.RowMapper;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
import com.google.common.collect.Lists;
|
|
|
|
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.common.ISClient;
|
|
import eu.dnetlib.openaire.dsm.dao.CountryTermRepository;
|
|
import eu.dnetlib.openaire.dsm.dao.DatasourceDao;
|
|
import eu.dnetlib.openaire.dsm.dao.MongoLoggerClient;
|
|
import eu.dnetlib.openaire.dsm.dao.ResponseUtils;
|
|
import eu.dnetlib.openaire.dsm.dao.VocabularyClient;
|
|
import eu.dnetlib.openaire.dsm.dao.utils.DsmMappingUtils;
|
|
import eu.dnetlib.openaire.dsm.domain.db.ApiDbEntry;
|
|
import eu.dnetlib.openaire.dsm.domain.db.DatasourceDbEntry;
|
|
import eu.dnetlib.openaire.dsm.domain.db.IdentityDbEntry;
|
|
import eu.dnetlib.openaire.exporter.exceptions.DsmApiException;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.AggregationHistoryResponseV1;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.AggregationHistoryResponseV2;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.AggregationInfo;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.AggregationInfoV1;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.ApiDetails;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.ApiDetailsResponse;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.DatasourceDetailResponse;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.DatasourceDetails;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.DatasourceDetailsUpdate;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.DatasourceDetailsWithApis;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.DatasourceSnippetResponse;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.RegisteredDatasourceInfo;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.RequestFilter;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.RequestSort;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.RequestSortOrder;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.SimpleDatasourceInfo;
|
|
import eu.dnetlib.openaire.exporter.model.dsm.SimpleResponse;
|
|
import eu.dnetlib.openaire.exporter.model.vocabularies.Country;
|
|
import eu.dnetlib.openaire.exporter.model.vocabularies.Vocabulary;
|
|
|
|
@Component
|
|
@ConditionalOnProperty(value = "openaire.exporter.enable.dsm", havingValue = "true")
|
|
public class DsmCore {
|
|
|
|
private static final Log log = LogFactory.getLog(DsmCore.class);
|
|
|
|
@Autowired
|
|
private MongoLoggerClient mongoLoggerClient;
|
|
|
|
@Autowired
|
|
private ISClient isClient;
|
|
|
|
@Autowired
|
|
private VocabularyClient vocabularyClient;
|
|
|
|
@Autowired
|
|
private DatasourceDao<DatasourceDbEntry, ApiDbEntry> dsDao;
|
|
|
|
@Autowired
|
|
private CountryTermRepository countryTermRepository;
|
|
|
|
@Autowired
|
|
private JdbcTemplate jdbcTemplate;
|
|
|
|
public List<Country> listCountries() throws DsmApiException {
|
|
final List<Country> countries = Lists.newArrayList();
|
|
final Vocabulary v = vocabularyClient.getCountries();
|
|
countries.addAll(countryTermRepository.findAll()
|
|
.stream()
|
|
.filter(Objects::nonNull)
|
|
.map(t -> new Country(t.getTerm(), v.getEnglishName(t.getTerm())))
|
|
.collect(Collectors.toList()));
|
|
return countries;
|
|
}
|
|
|
|
public DatasourceDetailResponse searchDsDetails(final RequestSort requestSortBy,
|
|
final RequestSortOrder order,
|
|
final RequestFilter requestFilter,
|
|
final int page,
|
|
final int size)
|
|
throws DsmApiException {
|
|
|
|
try {
|
|
final Page<DatasourceDbEntry> dsPage = dsDao.search(requestSortBy, order, requestFilter, page, size);
|
|
return ResponseUtils.detailsResponse(dsPage.map(d -> asDetails(d)).getContent(), dsPage.getTotalElements());
|
|
} catch (final DsmException e) {
|
|
log.error("error searching datasources", e);
|
|
throw new DsmApiException(e.getCode(), "error searching datasources", e);
|
|
}
|
|
}
|
|
|
|
public DatasourceSnippetResponse searchSnippet(final RequestSort requestSortBy,
|
|
final RequestSortOrder order,
|
|
final RequestFilter requestFilter,
|
|
final int page,
|
|
final int size)
|
|
throws DsmApiException {
|
|
try {
|
|
final Page<DatasourceDbEntry> dsPage = dsDao.search(requestSortBy, order, requestFilter, page, size);
|
|
return ResponseUtils.snippetResponse(dsPage.map(DsmMappingUtils::asSnippetExtended).getContent(), dsPage.getTotalElements());
|
|
} catch (final DsmException e) {
|
|
log.error("error searching datasources", e);
|
|
throw new DsmApiException(e.getCode(), "error searching datasources", e);
|
|
}
|
|
}
|
|
|
|
public DatasourceSnippetResponse searchRegistered(final RequestSort requestSortBy,
|
|
final RequestSortOrder order,
|
|
final RequestFilter requestFilter,
|
|
final int page,
|
|
final int size)
|
|
throws DsmApiException {
|
|
try {
|
|
final Page<DatasourceDbEntry> dsPage = dsDao.searchRegistered(requestSortBy, order, requestFilter, page, size);
|
|
return ResponseUtils.snippetResponse(dsPage.map(DsmMappingUtils::asSnippetExtended).getContent(), dsPage.getTotalElements());
|
|
} catch (final DsmException e) {
|
|
log.error("error searching datasources", e);
|
|
throw new DsmApiException(e.getCode(), "error searching datasources", e);
|
|
}
|
|
}
|
|
|
|
public List<String> findBaseURLs(final RequestFilter requestFilter, final int page, final int size) throws DsmApiException {
|
|
try {
|
|
return dsDao.findApiBaseURLs(requestFilter, page, size);
|
|
} catch (final DsmException e) {
|
|
log.error("error searching datasource base urls", e);
|
|
throw new DsmApiException(e.getCode(), "error searching datasource base urls", e);
|
|
}
|
|
}
|
|
|
|
public ApiDetailsResponse getApis(final String dsId) throws DsmApiException {
|
|
try {
|
|
final DatasourceDbEntry ds = dsDao.getDs(dsId);
|
|
final List<? extends ApiDbEntry> apis = dsDao.getApis(dsId);
|
|
final List<ApiDetails> api = apis.stream()
|
|
.map(DsmMappingUtils::asDetails)
|
|
.map(a -> a.setEoscDatasourceType(ds.getEoscDatasourceType()))
|
|
.map(a -> a.setTypology(ds.getTypology()))
|
|
.collect(Collectors.toList());
|
|
return ResponseUtils.apiResponse(api, api.size());
|
|
} catch (final DsmException e) {
|
|
log.error(String.format("error searching datasource api %s", dsId), e);
|
|
throw new DsmApiException(e.getCode(), String.format("error searching datasource api %s", dsId), e);
|
|
}
|
|
}
|
|
|
|
public void setManaged(final String dsId, final boolean managed) throws DsmApiException {
|
|
log.info(String.format("updated ds '%s' managed with '%s'", dsId, managed));
|
|
try {
|
|
dsDao.setManaged(dsId, managed);
|
|
} catch (final DsmException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public boolean isManaged(final String dsId) throws DsmApiException {
|
|
try {
|
|
return dsDao.isManaged(dsId);
|
|
} catch (final DsmException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public boolean exist(final DatasourceDetails d) throws DsmApiException {
|
|
try {
|
|
return dsDao.existDs(d.getId());
|
|
} catch (final DsmException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public void save(final DatasourceDetails d) throws DsmApiException {
|
|
try {
|
|
dsDao.saveDs(asDbEntry(d));
|
|
log.info("DS saved, " + d.getId());
|
|
} catch (final DsmException e) {
|
|
log.error(ExceptionUtils.getStackTrace(e));
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
@Transactional
|
|
public void save(final DatasourceDetailsWithApis d) throws DsmApiException {
|
|
try {
|
|
dsDao.saveDs(asDbEntry(d.getDatasource()));
|
|
final List<ApiDetails> apis = d.getApis();
|
|
if (apis != null) {
|
|
for (final ApiDetails api : apis) {
|
|
api.setDatasource(d.getDatasource().getId());
|
|
addApi(api);
|
|
}
|
|
}
|
|
} catch (final DsmException e) {
|
|
log.error(ExceptionUtils.getStackTrace(e));
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public void updateDatasource(final DatasourceDetailsUpdate d) throws DsmApiException {
|
|
try {
|
|
// initialize with current values from DB
|
|
final DatasourceDbEntry ds = dsDao.getDs(d.getId());
|
|
|
|
if (ds == null) { throw new DsmNotFoundException(String.format("ds '%s' does not exist", d.getId())); }
|
|
|
|
final DatasourceDbEntry update = asDbEntry(d);
|
|
if (d.getIdentities() != null) {
|
|
final Set<IdentityDbEntry> identities = new HashSet<>(
|
|
Stream.of(update.getIdentities(), ds.getIdentities())
|
|
.flatMap(Collection::stream)
|
|
.collect(Collectors.toMap(i -> i.getIssuertype() + i.getPid(), Function.identity(), (i1, i2) -> i1))
|
|
.values());
|
|
copyNonNullProperties(update, ds);
|
|
ds.setIdentities(identities);
|
|
} else {
|
|
copyNonNullProperties(update, ds);
|
|
}
|
|
|
|
dsDao.saveDs(ds);
|
|
} catch (final DsmException e) {
|
|
log.error(ExceptionUtils.getStackTrace(e));
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
// TODO remove if unused
|
|
public void deleteDs(final String dsId) throws DsmApiException {
|
|
log.info(String.format("deleted datasource '%s'", dsId));
|
|
try {
|
|
dsDao.deleteDs(dsId);
|
|
} catch (final DsmException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
// API
|
|
|
|
public void updateApiOaiSet(final String dsId, final String apiId, final String oaiSet) throws DsmApiException {
|
|
try {
|
|
dsDao.upsertApiOaiSet(apiId, oaiSet);
|
|
} catch (final DsmException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public void updateApiBaseurl(final String dsId, final String apiId, final String baseUrl) throws DsmApiException {
|
|
log.info(String.format("updated api '%s' baseurl with '%s'", apiId, baseUrl));
|
|
try {
|
|
dsDao.updateApiBaseUrl(apiId, baseUrl);
|
|
} catch (final DsmException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public void updateApiCompatibility(final String dsId, final String apiId, final String compliance, final boolean override) throws DsmApiException {
|
|
log.info(String.format("updated api '%s' compliance with '%s'", apiId, compliance));
|
|
try {
|
|
dsDao.updateCompliance(null, apiId, compliance, override);
|
|
} catch (final DsmException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public void addApi(final ApiDetails api) throws DsmApiException {
|
|
if (StringUtils.isBlank(api.getId())) {
|
|
api.setId(createId(api));
|
|
log.info(String.format("missing api id, created '%s'", api.getId()));
|
|
}
|
|
try {
|
|
dsDao.addApi(asDbEntry(api));
|
|
log.info("API saved, id: " + api.getId());
|
|
} catch (final DsmException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public void deleteApi(final String apiId) throws DsmApiException {
|
|
// TODO handle the api removal in case of associated workflows.
|
|
try {
|
|
dsDao.deleteApi(null, apiId);
|
|
} catch (final DsmForbiddenException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
} catch (final DsmNotFoundException e) {
|
|
throw new DsmApiException(e.getCode(), e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public void dropCaches() {
|
|
mongoLoggerClient.dropCache();
|
|
isClient.dropCache();
|
|
vocabularyClient.dropCache();
|
|
}
|
|
|
|
// HELPERS //////////////
|
|
|
|
public SimpleResponse<RegisteredDatasourceInfo> searchRecentRegistered(final int size) throws Throwable {
|
|
try {
|
|
final String sql =
|
|
IOUtils.toString(getClass().getResourceAsStream("/eu/dnetlib/openaire/sql/recent_registered_datasources.sql.st"), Charset.defaultCharset());
|
|
|
|
final List<RegisteredDatasourceInfo> list = jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(RegisteredDatasourceInfo.class), size);
|
|
|
|
return ResponseUtils.simpleResponse(list);
|
|
} catch (final Throwable e) {
|
|
log.error("error searching recent datasources", e);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
public Long countRegisteredAfter(final String fromDate, final String typeFilter) throws Throwable {
|
|
try {
|
|
if (StringUtils.isNotBlank(typeFilter)) {
|
|
final String sql =
|
|
IOUtils.toString(getClass().getResourceAsStream("/eu/dnetlib/openaire/sql/recent_registered_datasources_fromDate_typology.st.sql"), Charset
|
|
.defaultCharset());
|
|
|
|
return jdbcTemplate.queryForObject(sql, Long.class, fromDate, typeFilter + "%");
|
|
} else {
|
|
final String sql =
|
|
IOUtils.toString(getClass().getResourceAsStream("/eu/dnetlib/openaire/sql/recent_registered_datasources_fromDate.st.sql"), Charset
|
|
.defaultCharset());
|
|
|
|
return jdbcTemplate.queryForObject(sql, Long.class, fromDate);
|
|
}
|
|
|
|
} catch (final Throwable e) {
|
|
log.error("error searching recent datasources", e);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
@Deprecated
|
|
public AggregationHistoryResponseV1 aggregationhistoryV1(final String dsId) throws DsmApiException {
|
|
final List<AggregationInfoV1> history = mongoLoggerClient.getAggregationHistoryV1(dsId);
|
|
final AggregationHistoryResponseV1 rsp = new AggregationHistoryResponseV1(history);
|
|
rsp.setHeader(ResponseUtils.header(history.size()));
|
|
return rsp;
|
|
}
|
|
|
|
public AggregationHistoryResponseV2 aggregationhistoryV2(final String dsId) throws DsmApiException {
|
|
final List<AggregationInfo> history = mongoLoggerClient.getAggregationHistoryV2(dsId);
|
|
final AggregationHistoryResponseV2 rsp = new AggregationHistoryResponseV2(history);
|
|
rsp.setHeader(ResponseUtils.header(history.size()));
|
|
return rsp;
|
|
|
|
}
|
|
|
|
public SimpleResponse<SimpleDatasourceInfo> searchRecentRegisteredV2(final int size) throws Throwable {
|
|
try {
|
|
final String sql =
|
|
IOUtils.toString(getClass().getResourceAsStream("/eu/dnetlib/openaire/sql/recent_registered_datasources_v2.sql.st"), Charset.defaultCharset());
|
|
|
|
final List<SimpleDatasourceInfo> list =
|
|
jdbcTemplate.query(sql, rowMapperForSimpleDatasourceInfo(), size);
|
|
|
|
return ResponseUtils.simpleResponse(list);
|
|
} catch (final Throwable e) {
|
|
log.error("error searching recent datasources", e);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
public Long countFirstCollect(final String fromDate, final String typeFilter) throws Throwable {
|
|
try {
|
|
if (StringUtils.isNotBlank(typeFilter)) {
|
|
final String sql =
|
|
IOUtils
|
|
.toString(getClass().getResourceAsStream("/eu/dnetlib/openaire/sql/count_first_collected_datasources_fromDate_typology.st.sql"), Charset
|
|
.defaultCharset());
|
|
|
|
return jdbcTemplate.queryForObject(sql, Long.class, typeFilter + "%", fromDate);
|
|
} else {
|
|
final String sql =
|
|
IOUtils.toString(getClass().getResourceAsStream("/eu/dnetlib/openaire/sql/count_first_collected_datasources_fromDate.st.sql"), Charset
|
|
.defaultCharset());
|
|
|
|
return jdbcTemplate.queryForObject(sql, Long.class, fromDate);
|
|
}
|
|
|
|
} catch (final Throwable e) {
|
|
log.error("error searching datasources using the first collection date", e);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
public List<SimpleDatasourceInfo> getFirstCollectedAfter(final String fromDate, final String typeFilter) throws Throwable {
|
|
try {
|
|
if (StringUtils.isNotBlank(typeFilter)) {
|
|
final String sql =
|
|
IOUtils
|
|
.toString(getClass().getResourceAsStream("/eu/dnetlib/openaire/sql/first_collected_datasources_fromDate_typology.st.sql"), Charset
|
|
.defaultCharset());
|
|
|
|
return jdbcTemplate.query(sql, rowMapperForSimpleDatasourceInfo(), typeFilter + "%", fromDate);
|
|
|
|
} else {
|
|
final String sql =
|
|
IOUtils
|
|
.toString(getClass().getResourceAsStream("/eu/dnetlib/openaire/sql/first_collected_datasources_fromDate.st.sql"), Charset
|
|
.defaultCharset());
|
|
|
|
return jdbcTemplate.query(sql, rowMapperForSimpleDatasourceInfo(), fromDate);
|
|
|
|
}
|
|
} catch (final Throwable e) {
|
|
log.error("error searching datasources using the first collection date", e);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
private RowMapper<SimpleDatasourceInfo> rowMapperForSimpleDatasourceInfo() {
|
|
|
|
return (rs, rowNum) -> {
|
|
final SimpleDatasourceInfo info = new SimpleDatasourceInfo();
|
|
|
|
info.setId(rs.getString("id"));
|
|
info.setOfficialName(rs.getString("officialName"));
|
|
info.setEnglishName(rs.getString("englishName"));
|
|
info.setTypology(rs.getString("typology"));
|
|
info.setEoscType(rs.getString("eoscType"));
|
|
info.setEoscDatasourceType(rs.getString("eoscDatasourceType"));
|
|
info.setRegisteredBy(rs.getString("registeredBy"));
|
|
info.setRegistrationDate(rs.getString("registrationDate"));
|
|
info.setFirstCollectionDate(rs.getString("firstCollectionDate"));
|
|
info.setLastCollectionDate(rs.getString("lastCollectionDate"));
|
|
info.setLastCollectionTotal(rs.getLong("lastCollectionTotal"));
|
|
|
|
final Set<String> compatibilities = new HashSet<>();
|
|
for (final String s : (String[]) rs.getArray("compatibilities").getArray()) {
|
|
compatibilities.add(s);
|
|
}
|
|
|
|
// The order of the condition is important
|
|
if (compatibilities.contains("openaire-cris_1.1")) {
|
|
info.setCompatibility("openaire-cris_1.1");
|
|
} else if (compatibilities.contains("openaire4.0")) {
|
|
info.setCompatibility("openaire4.0");
|
|
} else if (compatibilities.contains("driver") && compatibilities.contains("openaire2.0")) {
|
|
info.setCompatibility("driver-openaire2.0");
|
|
} else if (compatibilities.contains("driver")) {
|
|
info.setCompatibility("driver");
|
|
} else if (compatibilities.contains("openaire2.0")) {
|
|
info.setCompatibility("openaire2.0");
|
|
} else if (compatibilities.contains("openaire3.0")) {
|
|
info.setCompatibility("openaire3.0");
|
|
} else if (compatibilities.contains("openaire2.0_data")) {
|
|
info.setCompatibility("openaire2.0_data");
|
|
} else if (compatibilities.contains("native")) {
|
|
info.setCompatibility("native");
|
|
} else if (compatibilities.contains("hostedBy")) {
|
|
info.setCompatibility("hostedBy");
|
|
} else if (compatibilities.contains("notCompatible")) {
|
|
info.setCompatibility("notCompatible");
|
|
} else {
|
|
info.setCompatibility("UNKNOWN");
|
|
}
|
|
|
|
for (final String s : (String[]) rs.getArray("organizations").getArray()) {
|
|
info.getOrganizations().put(StringUtils.substringBefore(s, "@@@").trim(), StringUtils.substringAfter(s, "@@@").trim());
|
|
}
|
|
|
|
return info;
|
|
};
|
|
}
|
|
|
|
}
|