001package co.codewizards.cloudstore.local.dto;
002
003import static co.codewizards.cloudstore.core.objectfactory.ObjectFactoryUtil.*;
004import static java.util.Objects.*;
005
006import java.util.ArrayList;
007import java.util.Collections;
008import java.util.List;
009
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013import co.codewizards.cloudstore.core.dto.DirectoryDto;
014import co.codewizards.cloudstore.core.dto.NormalFileDto;
015import co.codewizards.cloudstore.core.dto.RepoFileDto;
016import co.codewizards.cloudstore.core.dto.SymlinkDto;
017import co.codewizards.cloudstore.core.dto.TempChunkFileDto;
018import co.codewizards.cloudstore.core.dto.jaxb.TempChunkFileDtoIo;
019import co.codewizards.cloudstore.core.oio.File;
020import co.codewizards.cloudstore.core.repo.local.LocalRepoManager;
021import co.codewizards.cloudstore.core.repo.local.LocalRepoTransaction;
022import co.codewizards.cloudstore.local.persistence.Directory;
023import co.codewizards.cloudstore.local.persistence.FileChunk;
024import co.codewizards.cloudstore.local.persistence.NormalFile;
025import co.codewizards.cloudstore.local.persistence.RepoFile;
026import co.codewizards.cloudstore.local.persistence.RepoFileDao;
027import co.codewizards.cloudstore.local.persistence.Symlink;
028import co.codewizards.cloudstore.local.transport.TempChunkFileManager;
029import co.codewizards.cloudstore.local.transport.TempChunkFileWithDtoFile;
030
031public class RepoFileDtoConverter {
032
033        private static final Logger logger = LoggerFactory.getLogger(RepoFileDtoConverter.class);
034
035        private final TempChunkFileManager tempChunkFileManager = TempChunkFileManager.getInstance();
036        private final FileChunkDtoConverter fileChunkDtoConverter = FileChunkDtoConverter.create();
037        private final LocalRepoManager localRepoManager;
038        private final LocalRepoTransaction transaction;
039        private final RepoFileDao repoFileDao;
040        private boolean excludeLocalIds;
041        private boolean excludeMutableData;
042
043        public static RepoFileDtoConverter create(final LocalRepoTransaction transaction) {
044                return createObject(RepoFileDtoConverter.class, transaction);
045        }
046
047        protected RepoFileDtoConverter(final LocalRepoTransaction transaction) {
048                this.transaction = requireNonNull(transaction, "transaction");
049                this.localRepoManager = requireNonNull(transaction.getLocalRepoManager(), "transaction.localRepoManager");
050                this.repoFileDao = this.transaction.getDao(RepoFileDao.class);
051        }
052
053        public RepoFileDto toRepoFileDto(final RepoFile repoFile, final int depth) {
054                requireNonNull(repoFileDao, "repoFileDao");
055                requireNonNull(repoFile, "repoFile");
056                final RepoFileDto repoFileDto;
057                if (repoFile instanceof NormalFile) {
058                        final NormalFile normalFile = (NormalFile) repoFile;
059                        final NormalFileDto normalFileDto;
060                        repoFileDto = normalFileDto = createObject(NormalFileDto.class);
061                        if (isExcludeMutableData())
062                                normalFileDto.setLength(-1);
063                        else {
064                                normalFileDto.setLength(normalFile.getLength());
065                                normalFileDto.setSha1(normalFile.getSha1());
066                        }
067                        if (depth > 0) {
068                                // TODO this should actually be a SortedSet, but for whatever reason, I started
069                                // getting ClassCastExceptions and had to switch to a normal Set :-(
070                                final List<FileChunk> fileChunks = new ArrayList<>(normalFile.getFileChunks());
071                                Collections.sort(fileChunks);
072                                for (final FileChunk fileChunk : fileChunks) {
073                                        normalFileDto.getFileChunkDtos().add(fileChunkDtoConverter.toFileChunkDto(fileChunk));
074                                }
075                        }
076                        if (depth > 1) {
077                                final TempChunkFileDtoIo tempChunkFileDtoIo = new TempChunkFileDtoIo();
078                                final File file = repoFile.getFile(localRepoManager.getLocalRoot());
079                                for (final TempChunkFileWithDtoFile tempChunkFileWithDtoFile : tempChunkFileManager.getOffset2TempChunkFileWithDtoFile(file).values()) {
080                                        final File tempChunkFileDtoFile = tempChunkFileWithDtoFile.getTempChunkFileDtoFile();
081                                        if (tempChunkFileDtoFile == null)
082                                                continue; // incomplete: meta-data not yet written => ignore
083
084                                        final TempChunkFileDto tempChunkFileDto;
085                                        try {
086                                                tempChunkFileDto = tempChunkFileDtoIo.deserialize(tempChunkFileDtoFile);
087                                        } catch (final Exception x) {
088                                                logger.warn("toRepoFileDto: Ignoring corrupt tempChunkFileDtoFile '" + tempChunkFileDtoFile.getAbsolutePath() + "': " + x, x);
089                                                continue;
090                                        }
091                                        normalFileDto.getTempFileChunkDtos().add(requireNonNull(tempChunkFileDto.getFileChunkDto(), "tempChunkFileDto.fileChunkDto"));
092                                }
093                        }
094                }
095                else if (repoFile instanceof Directory) {
096                        repoFileDto = createObject(DirectoryDto.class);
097                }
098                else if (repoFile instanceof Symlink) {
099                        final Symlink symlink = (Symlink) repoFile;
100                        final SymlinkDto symlinkDto;
101                        repoFileDto = symlinkDto = createObject(SymlinkDto.class);
102                        if (! isExcludeMutableData())
103                                symlinkDto.setTarget(symlink.getTarget());
104                }
105                else
106                        throw new UnsupportedOperationException("RepoFile type not yet supported: " + repoFile);
107
108                if (! isExcludeLocalIds()) {
109                        repoFileDto.setId(repoFile.getId());
110                        repoFileDto.setParentId(repoFile.getParent() == null ? null : repoFile.getParent().getId());
111                        repoFileDto.setLocalRevision(repoFile.getLocalRevision());
112                }
113                repoFileDto.setName(repoFile.getName());
114                repoFileDto.setLastModified(repoFile.getLastModified());
115
116                return repoFileDto;
117        }
118
119        public boolean isExcludeLocalIds() {
120                return excludeLocalIds;
121        }
122        public void setExcludeLocalIds(final boolean excludeLocalIds) {
123                this.excludeLocalIds = excludeLocalIds;
124        }
125
126        public boolean isExcludeMutableData() {
127                return excludeMutableData;
128        }
129        public void setExcludeMutableData(boolean excludeMutableData) {
130                this.excludeMutableData = excludeMutableData;
131        }
132}