package com.constellio.data.dao.services.contents;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileExistsException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import com.constellio.data.conf.DataLayerConfiguration;
import com.constellio.data.conf.DigitSeparatorMode;
import com.constellio.data.dao.managers.StatefulService;
import com.constellio.data.dao.services.contents.ContentDaoException.ContentDaoException_NoSuchContent;
import com.constellio.data.dao.services.contents.ContentDaoRuntimeException.ContentDaoRuntimeException_CannotDeleteFolder;
import com.constellio.data.dao.services.contents.ContentDaoRuntimeException.ContentDaoRuntimeException_CannotMoveFolderTo;
import com.constellio.data.dao.services.contents.ContentDaoRuntimeException.ContentDaoRuntimeException_NoSuchFolder;
import com.constellio.data.dao.services.contents.FileSystemContentDaoRuntimeException.FileSystemContentDaoRuntimeException_DatastoreFailure;
import com.constellio.data.io.services.facades.IOServices;
import com.constellio.data.io.streamFactories.CloseableStreamFactory;
import com.constellio.data.utils.ImpossibleRuntimeException;
public class FileSystemContentDao implements StatefulService, ContentDao {
private static final String COPY_RECEIVED_STREAM_TO_FILE = "FileSystemContentDao-CopyReceivedStreamToFile";
IOServices ioServices;
File rootFolder;
DataLayerConfiguration configuration;
public FileSystemContentDao(File rootFolder, IOServices ioServices, DataLayerConfiguration configuration) {
this.rootFolder = rootFolder;
this.ioServices = ioServices;
this.configuration = configuration;
}
@Override
public void initialize() {
}
@Override
public void moveFileToVault(File file, String newContentId) {
File content = getFileOf(newContentId);
if (!content.exists()) {
try {
FileUtils.moveFile(file, content);
} catch (FileExistsException e) {
//OK
} catch (IOException e) {
throw new FileSystemContentDaoRuntimeException_DatastoreFailure(e);
}
}
}
@Override
public void add(String newContentId, InputStream newInputStream) {
File content = getFileOf(newContentId);
content.getParentFile().mkdirs();
OutputStream out = null;
try {
out = ioServices.newFileOutputStream(content, COPY_RECEIVED_STREAM_TO_FILE);
IOUtils.copy(newInputStream, out);
} catch (IOException e) {
throw new FileSystemContentDaoRuntimeException_DatastoreFailure(e);
} finally {
ioServices.closeQuietly(out);
}
}
@Override
public void delete(List<String> contentIds) {
for (String contentId : contentIds) {
File file = getFileOf(contentId);
file.delete();
}
}
@Override
public InputStream getContentInputStream(String contentId, String streamName)
throws ContentDaoException_NoSuchContent {
try {
return new BufferedInputStream(ioServices.newFileInputStream(getFileOf(contentId), streamName));
} catch (FileNotFoundException e) {
throw new ContentDaoException_NoSuchContent(contentId);
}
}
@Override
public CloseableStreamFactory<InputStream> getContentInputStreamFactory(final String id)
throws ContentDaoException_NoSuchContent {
final File file = getFileOf(id);
if (!file.exists()) {
throw new ContentDaoException_NoSuchContent(id);
}
return new CloseableStreamFactory<InputStream>() {
@Override
public void close()
throws IOException {
}
@Override
public long length() {
return file.length();
}
@Override
public InputStream create(String name)
throws IOException {
try {
return getContentInputStream(id, name);
} catch (ContentDaoException_NoSuchContent contentDaoException_noSuchContent) {
throw new ImpossibleRuntimeException(contentDaoException_noSuchContent);
}
}
};
}
@Override
public boolean isFolderExisting(String folderId) {
File folder = new File(rootFolder, folderId.replace("/", File.separator));
return folder.exists();
}
@Override
public boolean isDocumentExisting(String documentId) {
return getFileOf(documentId).exists();
}
@Override
public List<String> getFolderContents(String folderId) {
File folder = new File(rootFolder, folderId.replace("/", File.separator));
String[] fileArray = folder.list();
List<String> files = new ArrayList<>();
if (fileArray != null) {
for (String file : fileArray) {
files.add(folderId + "/" + file);
}
}
return files;
}
@Override
public long getContentLength(String vaultContentId) {
return getFileOf(vaultContentId).length();
}
@Override
public void moveFolder(String folderId, String newFolderId) {
File folder = getFolder(folderId);
if (!folder.exists()) {
throw new ContentDaoRuntimeException_NoSuchFolder(folderId);
}
File newfolder = getFolder(newFolderId);
newfolder.mkdirs();
newfolder.delete();
try {
FileUtils.moveDirectory(folder, newfolder);
} catch (IOException e) {
throw new ContentDaoRuntimeException_CannotMoveFolderTo(folderId, newFolderId, e);
}
}
public File getFolder(String folderId) {
return new File(rootFolder, folderId.replace("/", File.separator));
}
@Override
public void deleteFolder(String folderId) {
File folder = getFolder(folderId);
if (folder.exists()) {
try {
ioServices.deleteDirectory(getFolder(folderId));
} catch (IOException e) {
throw new ContentDaoRuntimeException_CannotDeleteFolder(folderId, e);
}
}
}
private File getFileOf(String contentId) {
if (contentId.contains("/")) {
return new File(rootFolder, contentId.replace("/", File.separator));
} else {
if (configuration.getContentDaoFileSystemDigitsSeparatorMode() == DigitSeparatorMode.THREE_LEVELS_OF_ONE_DIGITS) {
StringBuilder name = new StringBuilder();
String level1 = toCaseInsensitive(contentId.charAt(0));
name.append(level1).append(File.separator);
if (contentId.length() > 1) {
String level2 = toCaseInsensitive(contentId.charAt(1));
name.append(level1).append(level2).append(File.separator);
if (contentId.length() > 2) {
String level3 = toCaseInsensitive(contentId.charAt(2));
name.append(level1).append(level2).append(level3).append(File.separator);
}
}
name.append(toCaseInsensitive(contentId));
return new File(rootFolder, name.toString());
} else {
String folderName = contentId.substring(0, 2);
File folder = new File(rootFolder, folderName);
return new File(folder, contentId);
}
}
}
private String toCaseInsensitive(char character) {
String str = "" + character;
return str;
}
private String toCaseInsensitive(String str) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
stringBuilder.append(toCaseInsensitive(str.charAt(i)));
}
return stringBuilder.toString();
}
@Override
public void close() {
}
}