package eu.europeana.cloud.service.mcs.inmemory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import eu.europeana.cloud.common.model.File;
import eu.europeana.cloud.common.model.Record;
import eu.europeana.cloud.common.model.Representation;
import eu.europeana.cloud.common.response.ResultSlice;
import eu.europeana.cloud.service.mcs.RecordService;
import eu.europeana.cloud.service.mcs.RepresentationSearchParams;
import eu.europeana.cloud.service.mcs.UISClientHandler;
import eu.europeana.cloud.service.mcs.exception.CannotModifyPersistentRepresentationException;
import eu.europeana.cloud.service.mcs.exception.DataSetNotExistsException;
import eu.europeana.cloud.service.mcs.exception.FileNotExistsException;
import eu.europeana.cloud.service.mcs.exception.ProviderNotExistsException;
import eu.europeana.cloud.service.mcs.exception.RecordNotExistsException;
import eu.europeana.cloud.service.mcs.exception.RepresentationNotExistsException;
import eu.europeana.cloud.service.mcs.exception.VersionNotExistsException;
import eu.europeana.cloud.service.mcs.exception.WrongContentRangeException;
/**
* InMemoryContentServiceImpl
*/
@Service
public class InMemoryRecordService implements RecordService {
@Autowired
private InMemoryRecordDAO recordDAO;
@Autowired
private InMemoryContentDAO contentDAO;
@Autowired
private InMemoryDataSetDAO dataSetDAO;
@Autowired
private UISClientHandler uisHandler;
/**
* Constuctor.
*/
public InMemoryRecordService() {
super();
}
/**
* Constructs service instance using given DAOs.
*
* @param recordDAO
* @param contentDAO
* @param dataSetDAO
* @param uisHandler
*/
public InMemoryRecordService(InMemoryRecordDAO recordDAO, InMemoryContentDAO contentDAO,
InMemoryDataSetDAO dataSetDAO, UISClientHandler uisHandler) {
super();
this.recordDAO = recordDAO;
this.contentDAO = contentDAO;
this.dataSetDAO = dataSetDAO;
this.uisHandler = uisHandler;
}
@Override
public Record getRecord(String globalId)
throws RecordNotExistsException {
return recordDAO.getRecord(globalId);
}
@Override
public void deleteRecord(String globalId)
throws RecordNotExistsException {
Record r = recordDAO.getRecord(globalId);
for (Representation rep : r.getRepresentations()) {
try {
for (Representation repVersion : recordDAO.listRepresentationVersions(globalId,
rep.getRepresentationName())) {
for (File f : repVersion.getFiles()) {
contentDAO.deleteContent(globalId, repVersion.getRepresentationName(), repVersion.getVersion(),
f.getFileName());
}
}
} catch (RepresentationNotExistsException | FileNotExistsException ex) {
// should not happen
}
}
recordDAO.deleteRecord(globalId);
}
@Override
public void deleteRepresentation(String globalId, String schema)
throws RepresentationNotExistsException {
for (Representation rep : recordDAO.listRepresentationVersions(globalId, schema)) {
for (File f : rep.getFiles()) {
try {
contentDAO.deleteContent(globalId, schema, rep.getVersion(), f.getFileName());
} catch (FileNotExistsException ex) {
// should not happen
}
}
}
recordDAO.deleteRepresentation(globalId, schema);
}
@Override
public Representation createRepresentation(String globalId, String representationName, String providerId)
throws RecordNotExistsException, ProviderNotExistsException {
if (!uisHandler.existsProvider(providerId)) {
throw new ProviderNotExistsException((String.format("Provider %s does not exist.", providerId)));
}
return recordDAO.createRepresentation(globalId, representationName, providerId);
}
@Override
public Representation getRepresentation(String globalId, String schema)
throws RepresentationNotExistsException {
return recordDAO.getRepresentation(globalId, schema, null);
}
@Override
public Representation getRepresentation(String globalId, String schema, String version)
throws RepresentationNotExistsException {
return recordDAO.getRepresentation(globalId, schema, version);
}
@Override
public void deleteRepresentation(String globalId, String schema, String version)
throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException {
Representation rep = recordDAO.getRepresentation(globalId, schema, version);
for (File f : rep.getFiles()) {
try {
contentDAO.deleteContent(globalId, schema, version, f.getFileName());
} catch (FileNotExistsException ex) {
// should not happen
}
}
recordDAO.deleteRepresentation(globalId, schema, version);
}
@Override
public Representation persistRepresentation(String globalId, String schema, String version)
throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException {
Representation representation = recordDAO.persistRepresentation(globalId, schema, version);
for (File file : representation.getFiles()) {
try {
contentDAO.copyContent(globalId, schema, version, file.getFileName(), globalId, schema,
representation.getVersion(), file.getFileName());
} catch (FileNotExistsException e) {
throw new CannotModifyPersistentRepresentationException("Could not persist representation!", e);
}
}
return representation;
}
@Override
public List<Representation> listRepresentationVersions(String globalId, String schema)
throws RepresentationNotExistsException {
return recordDAO.listRepresentationVersions(globalId, schema);
}
@Override
public boolean putContent(String globalId, String schema, String version, File file, InputStream content)
throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException {
Representation representation = recordDAO.getRepresentation(globalId, schema, version);
if (representation.isPersistent()) {
throw new CannotModifyPersistentRepresentationException();
}
boolean isCreate = true; // if it is create file operation or update content
if (file.getFileName() == null) {
file.setFileName(UUID.randomUUID().toString());
} else {
for (File f : representation.getFiles()) {
if (f.getFileName().equals(file.getFileName())) {
isCreate = false;
break;
}
}
}
try {
contentDAO.putContent(globalId, schema, version, file, content);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
recordDAO.addOrReplaceFileInRepresentation(globalId, schema, version, file);
return isCreate;
}
@Override
public void getContent(String globalId, String schema, String version, String fileName, long rangeStart,
long rangeEnd, OutputStream os)
throws FileNotExistsException, WrongContentRangeException {
try {
contentDAO.getContent(globalId, schema, version, fileName, rangeStart, rangeEnd, os);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
@Override
public String getContent(String globalId, String schema, String version, String fileName, OutputStream os)
throws FileNotExistsException, RepresentationNotExistsException {
Representation rep = getRepresentation(globalId, schema, version);
String md5 = null;
for (File f : rep.getFiles()) {
if (fileName.equals(f.getFileName())) {
md5 = f.getMd5();
}
}
if (md5 == null) {
throw new FileNotExistsException();
}
try {
contentDAO.getContent(globalId, schema, version, fileName, -1, -1, os);
} catch (IOException | WrongContentRangeException ex) {
throw new RuntimeException(ex);
}
return md5;
}
@Override
public void deleteContent(String globalId, String schema, String version, String fileName)
throws FileNotExistsException, RepresentationNotExistsException,
CannotModifyPersistentRepresentationException {
recordDAO.removeFileFromRepresentation(globalId, schema, version, fileName);
contentDAO.deleteContent(globalId, schema, version, fileName);
}
@Override
public Representation copyRepresentation(String globalId, String schema, String version)
throws RepresentationNotExistsException, VersionNotExistsException {
Representation srcRep = recordDAO.getRepresentation(globalId, schema, version);
Representation copiedRep = recordDAO.createRepresentation(globalId, schema, srcRep.getDataProvider());
for (File srcFile : srcRep.getFiles()) {
File copiedFile = new File(srcFile);
try {
contentDAO.copyContent(globalId, schema, version, srcFile.getFileName(), globalId, schema,
copiedRep.getVersion(), copiedFile.getFileName());
recordDAO.addOrReplaceFileInRepresentation(globalId, schema, copiedRep.getVersion(), copiedFile);
} catch (FileNotExistsException | CannotModifyPersistentRepresentationException ex) {
// should not happen
}
}
// get version after all modifications
return recordDAO.getRepresentation(globalId, schema, copiedRep.getVersion());
}
// @Override
public ResultSlice<Representation> search(RepresentationSearchParams searchParams, String thresholdParam, int limit) {
int threshold = 0;
if (thresholdParam != null) {
threshold = parseInteger(thresholdParam);
}
String providerId = searchParams.getDataProvider();
String schema = searchParams.getSchema();
String dataSetId = searchParams.getDataSetId();
List<Representation> allRecords;
if (providerId != null && dataSetId != null) {
// get all for dataset then filter for schema
List<Representation> toReturn = new ArrayList<>();
try {
List<Representation> representationStubs = dataSetDAO.listDataSet(providerId, dataSetId);
for (Representation stub : representationStubs) {
if (schema == null || schema.equals(stub.getRepresentationName())) {
Representation realContent;
try {
realContent = recordDAO.getRepresentation(stub.getCloudId(), stub.getRepresentationName(),
stub.getVersion());
toReturn.add(realContent);
} catch (RepresentationNotExistsException ex) {
// ignore
}
}
}
} catch (DataSetNotExistsException ex) {
allRecords = Collections.emptyList();
}
allRecords = toReturn;
} else {
allRecords = recordDAO.findRepresentations(providerId, schema);
}
if (allRecords.size() != 0 && threshold >= allRecords.size()) {
throw new IllegalArgumentException("Illegal threshold param value: '" + thresholdParam + "'.");
}
return prepareResultSlice(limit, threshold, allRecords);
}
private ResultSlice<Representation> prepareResultSlice(int limit, int threshold, List<Representation> allRecords) {
List<Representation> result = allRecords;
String nextSlice = null;
if (limit > 0) {
int offset = threshold + limit;
result = allRecords.subList(threshold, Math.min(offset, allRecords.size()));
if (offset < allRecords.size()) {
nextSlice = Integer.toString(offset);
}
}
return new ResultSlice<>(nextSlice, result);
}
private int parseInteger(String thresholdParam) {
int offset = 0;
try {
offset = Integer.parseInt(thresholdParam);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Illegal value of threshold. It should be integer, but was '"
+ thresholdParam + "'. ");
}
return offset;
}
@Override
public File getFile(String globalId, String schema, String version, String fileName)
throws RepresentationNotExistsException, FileNotExistsException {
final Representation rep = getRepresentation(globalId, schema, version);
for (File f : rep.getFiles()) {
if (f.getFileName().equals(fileName)) {
return f;
}
}
throw new FileNotExistsException();
}
}