All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rawhttp.cli.FileLocator Maven / Gradle / Ivy

package rawhttp.cli;

import rawhttp.cli.util.MediaTypeUtil;
import rawhttp.core.RawHttpHeaders;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static java.util.Collections.singletonList;

final class FileLocator {

    private static final List ANY_CONTENT_TYPE = singletonList("*/*");

    static final class FileResult {
        final File file;
        final RawHttpHeaders contentTypeHeader;

        private FileResult(File file, RawHttpHeaders contentTypeHeader) {
            this.file = file;
            this.contentTypeHeader = contentTypeHeader;
        }
    }

    private static final class PathData {
        final File dir;
        final String resourceName;

        PathData(File dir, String resourceName) {
            this.dir = dir;
            this.resourceName = resourceName;
        }
    }

    private final File rootDir;
    private final Map mimeByFileExtension;

    FileLocator(File rootDir, Map mimeByFileExtension) {
        this.rootDir = rootDir;
        this.mimeByFileExtension = mimeByFileExtension;
    }

    Optional find(String path, List accept) {
        Optional result = findExactMatch(path);
        if (!result.isPresent()) {
            result = findWithExtension(path, accept);
        }
        return result;
    }

    // check if there's a resource with the same name, but an additional extension
    private Optional findWithExtension(String path, List accept) {
        PathData pathData = getPathData(path);

        if (!pathData.dir.isDirectory()) {
            return Optional.empty();
        }

        // find files whose names start with the resource name + '.'
        String resourceNameDot = pathData.resourceName + '.';
        File[] candidateFiles = pathData.dir.listFiles(f -> f.getName().startsWith(resourceNameDot));

        if (candidateFiles == null || candidateFiles.length == 0) {
            return Optional.empty();
        }

        // if anything is acceptable, return the first possible match
        if (accept.isEmpty() || accept.equals(ANY_CONTENT_TYPE)) {
            return Optional.of(new FileResult(candidateFiles[0], contentTypeHeaderFor(candidateFiles[0].getName())));
        }

        // try to match resources with the best possible accepted content-type
        Map fileByContentType = groupCandidatesByMediaType(resourceNameDot, candidateFiles);

        // return the best matching content-type file
        List acceptableMediaTypes = MediaTypeUtil.getSortedAcceptableMediaTypes(accept);
        for (String acceptableMediaType : acceptableMediaTypes) {
            File bestCandidate = fileByContentType.get(acceptableMediaType);
            if (bestCandidate != null) {
                return Optional.of(new FileResult(bestCandidate, contentTypeHeaderWithValue(acceptableMediaType)));
            }
        }

        // no matching content-type found, return the first one
        return Optional.of(new FileResult(candidateFiles[0], contentTypeHeaderFor(candidateFiles[0].getName())));
    }

    private Map groupCandidatesByMediaType(String resourceNameDot, File[] candidateFiles) {
        int extensionStartIndex = resourceNameDot.length();
        Map fileByContentType = new HashMap<>(candidateFiles.length);

        for (File candidateFile : candidateFiles) {
            String extension = candidateFile.getName().substring(extensionStartIndex);
            String mime = mimeByFileExtension.get(extension);
            if (mime != null) {
                fileByContentType.put(mime, candidateFile);
            }
        }
        return fileByContentType;
    }

    private Optional findExactMatch(String path) {
        File exactMatch = new File(rootDir, path);
        if (exactMatch.isFile()) {
            return Optional.of(new FileResult(exactMatch, contentTypeHeaderFor(path)));
        }
        return Optional.empty();
    }

    private RawHttpHeaders contentTypeHeaderFor(String resourceName) {
        return contentTypeHeaderWithValue(mimeTypeOf(resourceName));
    }

    private static RawHttpHeaders contentTypeHeaderWithValue(String value) {
        return RawHttpHeaders.newBuilder()
                .with("Content-Type", value)
                .build();
    }

    String mimeTypeOf(String resourceName) {
        int idx = resourceName.lastIndexOf('.');
        if (idx < 0 || idx == resourceName.length() - 1) {
            return "application/octet-stream";
        }
        String extension = resourceName.substring(idx + 1);
        return mimeByFileExtension.getOrDefault(extension, "application/octet-stream");
    }

    private PathData getPathData(String path) {
        int pathSeparatorIndex = path.lastIndexOf('/');
        String subDirName;
        String resourceName;
        if (pathSeparatorIndex >= 0 && pathSeparatorIndex < path.length() - 1) {
            subDirName = path.substring(0, pathSeparatorIndex);
            resourceName = path.substring(pathSeparatorIndex + 1);
        } else {
            subDirName = ".";
            resourceName = path;
        }

        return new PathData(new File(rootDir, subDirName), resourceName);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy