package eu.europeana.cloud.service.uis.persistent;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import eu.europeana.cloud.common.exceptions.ProviderDoesNotExistException;
import eu.europeana.cloud.common.model.CloudId;
import eu.europeana.cloud.common.model.IdentifierErrorInfo;
import eu.europeana.cloud.common.model.LocalId;
import eu.europeana.cloud.service.uis.UniqueIdentifierService;
import eu.europeana.cloud.service.uis.persistent.dao.CassandraDataProviderDAO;
import eu.europeana.cloud.service.uis.persistent.dao.CassandraCloudIdDAO;
import eu.europeana.cloud.service.uis.persistent.dao.CassandraLocalIdDAO;
import eu.europeana.cloud.service.uis.encoder.IdGenerator;
import eu.europeana.cloud.service.uis.exception.CloudIdAlreadyExistException;
import eu.europeana.cloud.service.uis.exception.CloudIdDoesNotExistException;
import eu.europeana.cloud.service.uis.exception.DatabaseConnectionException;
import eu.europeana.cloud.service.uis.exception.IdHasBeenMappedException;
import eu.europeana.cloud.service.uis.exception.RecordDatasetEmptyException;
import eu.europeana.cloud.service.uis.exception.RecordDoesNotExistException;
import eu.europeana.cloud.service.uis.exception.RecordExistsException;
import eu.europeana.cloud.service.uis.exception.RecordIdDoesNotExistException;
import eu.europeana.cloud.service.uis.status.IdentifierErrorTemplate;
/**
* Cassandra implementation of the Unique Identifier Service
*
* @author Yorgos.Mamakis@ kb.nl
*/
@Service
public class CassandraUniqueIdentifierService implements UniqueIdentifierService {
private CassandraCloudIdDAO cloudIdDao;
private CassandraLocalIdDAO localIdDao;
private CassandraDataProviderDAO dataProviderDao;
private String hostList;
private String keyspace;
private String port;
private static final Logger LOGGER = LoggerFactory.getLogger(CassandraUniqueIdentifierService.class);
/**
* Initialization of the service with its DAOs
*
* @param cloudIdDao
* cloud identifier DAO
* @param localIdDao
* local identifier DAO
* @param dataProviderDao
*/
public CassandraUniqueIdentifierService(CassandraCloudIdDAO cloudIdDao, CassandraLocalIdDAO localIdDao,
CassandraDataProviderDAO dataProviderDao) {
LOGGER.info("PersistentUniqueIdentifierService starting...");
this.cloudIdDao = cloudIdDao;
this.localIdDao = localIdDao;
this.dataProviderDao = dataProviderDao;
this.hostList = cloudIdDao.getHostList();
this.keyspace = cloudIdDao.getKeyspace();
this.port = cloudIdDao.getPort();
LOGGER.info("PersistentUniqueIdentifierService started successfully...");
}
@Override
public CloudId createCloudId(String... recordInfo)
throws DatabaseConnectionException, RecordExistsException, ProviderDoesNotExistException,
RecordDatasetEmptyException, CloudIdDoesNotExistException, CloudIdAlreadyExistException {
LOGGER.info("createCloudId() creating cloudId");
String providerId = recordInfo[0];
LOGGER.info("createCloudId() creating cloudId providerId={}", providerId);
if (dataProviderDao.getProvider(providerId) == null) {
LOGGER.warn("ProviderDoesNotExistException for providerId={}", providerId);
throw new ProviderDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getErrorInfo(providerId)));
}
String recordId = recordInfo.length > 1 ? recordInfo[1] : IdGenerator.timeEncode(providerId);
LOGGER.info("createCloudId() creating cloudId providerId='{}', recordId='{}'", providerId, recordId);
if (!localIdDao.searchActive(providerId, recordId).isEmpty()) {
LOGGER.warn("RecordExistsException for providerId={}, recordId={}", providerId, recordId);
throw new RecordExistsException(new IdentifierErrorInfo(
IdentifierErrorTemplate.RECORD_EXISTS.getHttpCode(),
IdentifierErrorTemplate.RECORD_EXISTS.getErrorInfo(providerId, recordId)));
}
String id = IdGenerator.encodeWithSha256AndBase32("/" + providerId + "/" + recordId);
List<CloudId> cloudIds = cloudIdDao.insert(false, id, providerId, recordId);
localIdDao.insert(providerId, recordId, id);
CloudId cloudId = new CloudId();
cloudId.setId(cloudIds.get(0).getId());
LocalId lId = new LocalId();
lId.setProviderId(providerId);
lId.setRecordId(recordId);
cloudId.setLocalId(lId);
return cloudId;
}
@Override
public CloudId getCloudId(String providerId, String recordId)
throws DatabaseConnectionException, RecordDoesNotExistException, ProviderDoesNotExistException,
RecordDatasetEmptyException {
LOGGER.info("getCloudId() providerId='{}', recordId='{}'", providerId, recordId);
List<CloudId> cloudIds = localIdDao.searchActive(providerId, recordId);
if (cloudIds.isEmpty()) {
throw new RecordDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.RECORD_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.RECORD_DOES_NOT_EXIST.getErrorInfo(providerId, recordId)));
}
final CloudId cloudId = cloudIds.get(0);
LOGGER.info("getCloudId() returning cloudId='{}'", cloudId);
return cloudId;
}
@Override
public List<CloudId> getLocalIdsByCloudId(String cloudId)
throws DatabaseConnectionException, CloudIdDoesNotExistException, ProviderDoesNotExistException,
RecordDatasetEmptyException {
LOGGER.info("getLocalIdsByCloudId() cloudId='{}'", cloudId);
List<CloudId> cloudIds = cloudIdDao.searchActive(cloudId);
if (cloudIds.isEmpty()) {
LOGGER.warn("CloudIdDoesNotExistException for cloudId={}", cloudId);
throw new CloudIdDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.CLOUDID_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.CLOUDID_DOES_NOT_EXIST.getErrorInfo(cloudId)));
}
List<CloudId> localIds = new ArrayList<>();
for (CloudId cId : cloudIds) {
if (localIdDao.searchActive(cId.getLocalId().getProviderId(), cId.getLocalId().getRecordId()).size() > 0) {
localIds.add(cId);
}
}
return localIds;
}
@Override
public List<CloudId> getLocalIdsByProvider(String providerId, String start, int end)
throws DatabaseConnectionException, ProviderDoesNotExistException, RecordDatasetEmptyException {
LOGGER.info("getLocalIdsByProvider() providerId='{}', start='{}', end='{}'", providerId, end);
if (dataProviderDao.getProvider(providerId) == null) {
LOGGER.warn("ProviderDoesNotExistException for providerId='{}', start='{}', end='{}'", providerId, start,
end);
throw new ProviderDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getErrorInfo(providerId)));
}
List<CloudId> cloudIds = null;
if (start == null) {
cloudIds = localIdDao.searchActive(providerId);
} else {
cloudIds = localIdDao.searchActiveWithPagination(start, end, providerId);
}
List<CloudId> localIds = new ArrayList<>();
for (CloudId cloudId : cloudIds) {
localIds.add(cloudId);
}
return localIds;
}
@Override
public List<CloudId> getCloudIdsByProvider(String providerId, String startRecordId, int limit)
throws DatabaseConnectionException, ProviderDoesNotExistException, RecordDatasetEmptyException {
LOGGER.info("getCloudIdsByProvider() providerId='{}', startRecordId='{}', end='{}'", providerId, startRecordId, limit);
if (dataProviderDao.getProvider(providerId) == null) {
LOGGER.warn("ProviderDoesNotExistException for providerId='{}', startRecordId='{}', end='{}'", providerId, startRecordId,
limit);
throw new ProviderDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getErrorInfo(providerId)));
}
if (startRecordId == null) {
return localIdDao.searchActive(providerId);
} else {
return localIdDao.searchActiveWithPagination(startRecordId, limit, providerId);
}
}
@Override
public CloudId createIdMapping(String cloudId, String providerId, String recordId)
throws DatabaseConnectionException, CloudIdDoesNotExistException, IdHasBeenMappedException,
ProviderDoesNotExistException, RecordDatasetEmptyException, CloudIdAlreadyExistException {
LOGGER.info("createIdMapping() creating mapping for cloudId='{}', providerId='{}', providerId='{}' ...",
cloudId, providerId, providerId);
if (dataProviderDao.getProvider(providerId) == null) {
LOGGER.warn("ProviderDoesNotExistException for cloudId='{}', providerId='{}', recordId='{}'", cloudId,
providerId, recordId);
throw new ProviderDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getErrorInfo(providerId)));
}
List<CloudId> cloudIds = cloudIdDao.searchActive(cloudId);
if (cloudIds.isEmpty()) {
LOGGER.warn("CloudIdDoesNotExistException for cloudId='{}', providerId='{}', recordId='{}'", cloudId,
providerId, recordId);
throw new CloudIdDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.CLOUDID_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.CLOUDID_DOES_NOT_EXIST.getErrorInfo(cloudId)));
}
List<CloudId> localIds = localIdDao.searchActive(providerId, recordId);
if (!localIds.isEmpty()) {
LOGGER.warn("IdHasBeenMappedException for cloudId='{}', providerId='{}', recordId='{}'", cloudId,
providerId, recordId);
throw new IdHasBeenMappedException(new IdentifierErrorInfo(
IdentifierErrorTemplate.ID_HAS_BEEN_MAPPED.getHttpCode(),
IdentifierErrorTemplate.ID_HAS_BEEN_MAPPED.getErrorInfo(providerId, recordId, cloudId)));
}
localIdDao.insert(providerId, recordId, cloudId);
cloudIdDao.insert(false, cloudId, providerId, recordId);
CloudId newCloudId = new CloudId();
newCloudId.setId(cloudId);
LocalId lid = new LocalId();
lid.setProviderId(providerId);
lid.setRecordId(recordId);
newCloudId.setLocalId(lid);
LOGGER.info("createIdMapping() new mapping created! new cloudId='{}' for already "
+ "existing cloudId='{}', providerId='{}', providerId='{}' ...", newCloudId, cloudId, providerId,
providerId);
return newCloudId;
}
@Override
public void removeIdMapping(String providerId, String recordId)
throws DatabaseConnectionException, ProviderDoesNotExistException, RecordIdDoesNotExistException {
LOGGER.info("removeIdMapping() removing Id mapping for providerId='{}', recordId='{}' ...", providerId,
recordId);
if (dataProviderDao.getProvider(providerId) == null) {
LOGGER.warn("ProviderDoesNotExistException for providerId='{}', recordId='{}'", providerId, recordId);
throw new ProviderDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.PROVIDER_DOES_NOT_EXIST.getErrorInfo(providerId)));
}
localIdDao.delete(providerId, recordId);
LOGGER.info("Id mapping removed for providerId='{}', recordId='{}'", providerId, recordId);
}
@Override
public List<CloudId> deleteCloudId(String cloudId)
throws DatabaseConnectionException, CloudIdDoesNotExistException {
LOGGER.info("deleteCloudId() deleting cloudId='{}' ...", cloudId);
if (cloudIdDao.searchActive(cloudId).isEmpty()) {
LOGGER.warn("CloudIdDoesNotExistException for cloudId='{}'", cloudId);
throw new CloudIdDoesNotExistException(new IdentifierErrorInfo(
IdentifierErrorTemplate.CLOUDID_DOES_NOT_EXIST.getHttpCode(),
IdentifierErrorTemplate.CLOUDID_DOES_NOT_EXIST.getErrorInfo(cloudId)));
}
List<CloudId> localIds = cloudIdDao.searchAll(cloudId);
for (CloudId cId : localIds) {
localIdDao.delete(cId.getLocalId().getProviderId(), cId.getLocalId().getRecordId());
cloudIdDao.delete(cloudId, cId.getLocalId().getProviderId(), cId.getLocalId().getRecordId());
}
LOGGER.info("CloudId deleted for cloudId='{}'", cloudId);
return localIds;
}
@Override
public String getHostList() {
return this.hostList;
}
@Override
public String getKeyspace() {
return this.keyspace;
}
@Override
public String getPort() {
return this.port;
}
@Override
public CloudId createIdMapping(String cloudId, String providerId)
throws DatabaseConnectionException, CloudIdDoesNotExistException, IdHasBeenMappedException,
ProviderDoesNotExistException, RecordDatasetEmptyException, CloudIdAlreadyExistException {
LOGGER.info("createIdMapping() cloudId='{}', providerId='{}'", providerId);
return createIdMapping(cloudId, providerId, IdGenerator.timeEncode(providerId));
}
}