com.sap.cloud.lm.sl.cf.persistence.services.FileService Maven / Gradle / Ivy
package com.sap.cloud.lm.sl.cf.persistence.services;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sap.cloud.lm.sl.cf.persistence.DataSourceWithDialect;
import com.sap.cloud.lm.sl.cf.persistence.executors.SqlQueryExecutor;
import com.sap.cloud.lm.sl.cf.persistence.message.Messages;
import com.sap.cloud.lm.sl.cf.persistence.model.FileEntry;
import com.sap.cloud.lm.sl.cf.persistence.model.FileInfo;
import com.sap.cloud.lm.sl.cf.persistence.processors.FileDownloadProcessor;
import com.sap.cloud.lm.sl.cf.persistence.processors.FileUploadProcessor;
import com.sap.cloud.lm.sl.cf.persistence.query.providers.SqlFileQueryProvider;
import com.sap.cloud.lm.sl.cf.persistence.security.VirusScanner;
import com.sap.cloud.lm.sl.cf.persistence.security.VirusScannerException;
import com.sap.cloud.lm.sl.common.SLException;
import com.sap.cloud.lm.sl.common.util.DigestHelper;
public class FileService {
protected static final String DEFAULT_TABLE_NAME = "LM_SL_PERSISTENCE_FILE";
protected final Logger logger = LoggerFactory.getLogger(getClass());
private final FileStorage fileStorage;
private final SqlQueryExecutor sqlQueryExecutor;
private final SqlFileQueryProvider sqlFileQueryProvider;
private VirusScanner virusScanner;
public FileService(DataSourceWithDialect dataSourceWithDialect, FileStorage fileStorage) {
this(DEFAULT_TABLE_NAME, dataSourceWithDialect, fileStorage);
}
public FileService(String tableName, DataSourceWithDialect dataSourceWithDialect, FileStorage fileStorage) {
this.sqlQueryExecutor = new SqlQueryExecutor(dataSourceWithDialect.getDataSource());
this.sqlFileQueryProvider = new SqlFileQueryProvider(tableName, dataSourceWithDialect.getDataSourceDialect(), logger);
this.fileStorage = fileStorage;
}
public void setVirusScanner(VirusScanner virusScanner) {
this.virusScanner = virusScanner;
}
public FileEntry addFile(String space, String name,
FileUploadProcessor extends OutputStream, ? extends OutputStream> fileInfoProcessor, InputStream is)
throws FileStorageException {
return addFile(space, null, name, fileInfoProcessor, is);
}
/**
* Uploads a new file.
*
* @param space
* @param namespace namespace where the file will be uploaded
* @param name name of the uploaded file
* @param fileProcessor file processor
* @param is input stream to read the content from
* @return an object representing the file upload
* @throws FileStorageException
*/
public FileEntry addFile(String space, String namespace, String name,
FileUploadProcessor extends OutputStream, ? extends OutputStream> fileInfoProcessor, InputStream is)
throws FileStorageException {
// Stream the file to a temp location and get the size and MD5 digest
// as an alternative we can pass the original stream to the database,
// and decorate the blob stream to calculate digest and size, but this will still require
// two roundtrips to the database (insert of the content and then update with the digest and
// size), which is probably inefficient
FileInfo fileInfo = null;
FileEntry fileEntry = null;
try (InputStream inputStream = is) {
fileInfo = FileUploader.uploadFile(inputStream, fileInfoProcessor);
fileEntry = addFile(space, namespace, name, fileInfoProcessor, fileInfo);
} catch (IOException e) {
logger.debug(e.getMessage(), e);
} finally {
if (fileInfo != null) {
FileUploader.removeFile(fileInfo);
}
}
return fileEntry;
}
public FileEntry addFile(String space, String namespace, String name,
FileUploadProcessor extends OutputStream, ? extends OutputStream> fileInfoProcessor, File existingFile)
throws FileStorageException {
try {
FileInfo fileInfo = createFileInfo(existingFile);
return addFile(space, namespace, name, fileInfoProcessor, fileInfo);
} catch (NoSuchAlgorithmException e) {
throw new SLException(Messages.ERROR_CALCULATING_FILE_DIGEST, existingFile.getName(), e);
} catch (FileNotFoundException e) {
throw new FileStorageException(MessageFormat.format(Messages.ERROR_FINDING_FILE_TO_UPLOAD, existingFile.getName()), e);
} catch (IOException e) {
throw new FileStorageException(MessageFormat.format(Messages.ERROR_READING_FILE_CONTENT, existingFile.getName()), e);
}
}
public List listFiles(final String space, final String namespace) throws FileStorageException {
try {
return getSqlQueryExecutor().execute(getSqlFileQueryProvider().getListFilesQuery(space, namespace));
} catch (SQLException e) {
throw new FileStorageException(MessageFormat.format(Messages.ERROR_GETTING_FILES_WITH_SPACE_AND_NAMESPACE, space, namespace),
e);
}
}
public FileEntry getFile(final String space, final String id) throws FileStorageException {
try {
return getSqlQueryExecutor().execute(getSqlFileQueryProvider().getRetrieveFileQuery(space, id));
} catch (SQLException e) {
throw new FileStorageException(e.getMessage(), e);
}
}
/**
* Reads file from the storage.
*
* @param space
* @param fileProcessor file processor
* @throws FileStorageException
*/
public void processFileContent(final FileDownloadProcessor fileDownloadProcessor) throws FileStorageException {
fileStorage.processFileContent(fileDownloadProcessor);
}
public int deleteBySpaceAndNamespace(final String space, final String namespace) throws FileStorageException {
fileStorage.deleteFilesBySpaceAndNamespace(space, namespace);
return deleteFileAttributesBySpaceAndNamespace(space, namespace);
}
public int deleteBySpace(final String space) throws FileStorageException {
fileStorage.deleteFilesBySpace(space);
return deleteFileAttributesBySpace(space);
}
public int deleteModifiedBefore(Date modificationTime) throws FileStorageException {
int deletedItems = fileStorage.deleteFilesModifiedBefore(modificationTime);
return deleteFileAttributesModifiedBefore(modificationTime) + deletedItems;
}
public boolean deleteFile(final String space, final String id) throws FileStorageException {
fileStorage.deleteFile(id, space);
return deleteFileAttribute(space, id);
}
public int deleteFilesEntriesWithoutContent() throws FileStorageException {
try {
List entries = getSqlQueryExecutor().execute(getSqlFileQueryProvider().getListAllFilesQuery());
List missing = fileStorage.getFileEntriesWithoutContent(entries);
return deleteFileEntries(missing);
} catch (SQLException e) {
throw new FileStorageException(Messages.ERROR_GETTING_ALL_FILES, e);
}
}
protected void storeFile(FileEntry fileEntry, FileInfo fileInfo) throws FileStorageException {
try (InputStream fileStream = fileInfo.getInputStream()) {
fileStorage.addFile(fileEntry, fileStream);
storeFileAttributes(fileEntry);
} catch (IOException e) {
logger.debug(e.getMessage(), e);
}
}
protected boolean deleteFileAttribute(final String space, final String id) throws FileStorageException {
try {
return getSqlQueryExecutor().execute(getSqlFileQueryProvider().getDeleteFileEntryQuery(space, id));
} catch (SQLException e) {
throw new FileStorageException(e.getMessage(), e);
}
}
protected int deleteFileAttributesModifiedBefore(Date modificationTime) throws FileStorageException {
try {
return getSqlQueryExecutor().execute(getSqlFileQueryProvider().getDeleteModifiedBeforeQuery(modificationTime));
} catch (SQLException e) {
throw new FileStorageException(e.getMessage(), e);
}
}
protected int deleteFileAttributesBySpaceAndNamespace(final String space, final String namespace) throws FileStorageException {
try {
return getSqlQueryExecutor().execute(getSqlFileQueryProvider().getDeleteBySpaceAndNamespaceQuery(space, namespace));
} catch (SQLException e) {
throw new FileStorageException(e.getMessage(), e);
}
}
protected int deleteFileAttributesBySpace(String space) throws FileStorageException {
try {
return getSqlQueryExecutor().execute(getSqlFileQueryProvider().getDeleteBySpaceQuery(space));
} catch (SQLException e) {
throw new FileStorageException(e.getMessage(), e);
}
}
protected FileEntry createFileEntry(String space, String namespace, String name, FileInfo localFile) {
FileEntry fileEntry = new FileEntry();
fileEntry.setId(generateRandomId());
fileEntry.setSpace(space);
fileEntry.setName(name);
fileEntry.setNamespace(namespace);
fileEntry.setSize(localFile.getSize());
fileEntry.setDigest(localFile.getDigest());
fileEntry.setDigestAlgorithm(localFile.getDigestAlgorithm());
fileEntry.setModified(new Timestamp(System.currentTimeMillis()));
return fileEntry;
}
protected SqlQueryExecutor getSqlQueryExecutor() {
return sqlQueryExecutor;
}
protected SqlFileQueryProvider getSqlFileQueryProvider() {
return sqlFileQueryProvider;
}
private FileInfo createFileInfo(File existingFile) throws NoSuchAlgorithmException, IOException {
return new FileInfo(existingFile,
BigInteger.valueOf(existingFile.length()),
DigestHelper.computeFileChecksum(existingFile.toPath(), FileUploader.DIGEST_METHOD),
FileUploader.DIGEST_METHOD);
}
private FileEntry addFile(String space, String namespace, String name,
FileUploadProcessor extends OutputStream, ? extends OutputStream> fileInfoProcessor, FileInfo fileInfo)
throws FileStorageException {
if (fileInfoProcessor.shouldScanFile()) {
scanUpload(fileInfo);
}
FileEntry fileEntry = createFileEntry(space, namespace, name, fileInfo);
storeFile(fileEntry, fileInfo);
logger.debug(MessageFormat.format(Messages.STORED_FILE_0, fileEntry));
return fileEntry;
}
private void scanUpload(FileInfo file) throws FileStorageException {
if (virusScanner == null) {
throw new FileStorageException(Messages.NO_VIRUS_SCANNER_CONFIGURED);
}
try {
logger.info(MessageFormat.format(Messages.SCANNING_FILE, file.getFile()));
virusScanner.scanFile(file.getFile());
logger.info(MessageFormat.format(Messages.SCANNING_FILE_SUCCESS, file.getFile()));
} catch (VirusScannerException e) {
logger.error(MessageFormat.format(Messages.DELETING_LOCAL_FILE_BECAUSE_OF_INFECTION, file.getFile()));
FileUploader.removeFile(file);
throw e;
}
}
private String generateRandomId() {
return UUID.randomUUID()
.toString();
}
private boolean storeFileAttributes(final FileEntry fileEntry) throws FileStorageException {
try {
return getSqlQueryExecutor().execute(getSqlFileQueryProvider().getStoreFileAttributesQuery(fileEntry));
} catch (SQLException e) {
throw new FileStorageException(e.getMessage(), e);
}
}
private int deleteFileEntries(List fileEntries) throws FileStorageException {
try {
return getSqlQueryExecutor().execute(getSqlFileQueryProvider().getDeleteFileEntriesQuery(fileEntries));
} catch (SQLException e) {
throw new FileStorageException(e.getMessage(), e);
}
}
public static class FileServiceColumnNames {
public static final String CONTENT = "CONTENT";
public static final String MODIFIED = "MODIFIED";
public static final String DIGEST_ALGORITHM = "DIGEST_ALGORITHM";
public static final String FILE_SIZE = "FILE_SIZE";
public static final String NAMESPACE = "NAMESPACE";
public static final String SPACE = "SPACE";
public static final String FILE_NAME = "FILE_NAME";
public static final String DIGEST = "DIGEST";
public static final String FILE_ID = "FILE_ID";
protected FileServiceColumnNames() {
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy