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

com.github.sdorra.webresources.WebResources Maven / Gradle / Ivy

/**
 * The MIT License
 * Copyright (c) 2018 Sebastian Sdorra
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.github.sdorra.webresources;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Optional;

/**
 * {@link WebResources} provides util methods to create {@link WebResource}.
 */
public final class WebResources {

    private WebResources(){}

    /**
     * Creates a {@link WebResource} from a {@link URL}, if the url is a file url {@link #of(Path)} is internally used.
     * Warning: This method should not be used with an external url.
     *
     * @param url source url
     *
     * @return web resource
     *
     * @throws IOException if web resource could not be created
     */
    public static WebResource of(URL url) throws IOException {
        if ("file".equals(url.getProtocol())) {
            try {
                return of(Paths.get(url.toURI()));
            } catch (URISyntaxException ex) {
                throw new IOException("failed to get path from uri", ex);
            }
        }

        URLConnection connection = url.openConnection();
        String name = name(url);
        long size = connection.getContentLengthLong();
        long lastModified = connection.getLastModified();

        return builder(name, () -> url.openConnection().getInputStream())
                .withContentLength(size)
                .withLastModifiedDate(lastModified)
                .withContentType(ContentTypeResolver.resolve(url.getPath()))
                .withETag(etag(name, size, lastModified))
                .build();
    }

    private static String name(URL url) {
        String path = url.getPath();
        int index = path.lastIndexOf('/');
        if (index > 0) {
            return path.substring(index + 1);
        }
        return path;
    }

    /**
     * Creates a {@link WebResource} from a file.
     *
     * @param file source file
     *
     * @return web resource
     *
     * @throws IOException if web resource could not be created
     */
    public static WebResource of(File file) throws IOException {
        return of(file.toPath());
    }

    /**
     * Creates a {@link WebResource} from a path.
     *
     * @param path source path
     *
     * @return web resource
     *
     * @throws IOException if web resource could not be created
     */
    public static WebResource of(Path path) throws IOException {
        String name = path.getFileName().toString();
        return builder(name, () -> Files.newInputStream(path))
                .withContentLength(Files.size(path))
                .withLastModifiedDate(Files.getLastModifiedTime(path).toInstant())
                .withContentType(ContentTypeResolver.resolve(path.toString()))
                .withETag(etag(path))
                .build();
    }

    /**
     * Creates builder for a {@link WebResource}.
     *
     * @param name name of the resource
     * @param contentThrowingSupplier content provider
     *
     * @return web resource builder
     */
    public static Builder builder(String name, ThrowingSupplier contentThrowingSupplier) {
        return new Builder(name, contentThrowingSupplier);
    }

    /**
     * Creates an etag from the given file path.
     * Note: This method is only visible for testing
     *
     * @param path file path
     *
     * @return etag
     *
     * @throws IOException If an input or output exception occurs
     */
    static String etag(Path path) throws IOException {
        String name = path.getFileName().toString();
        long size = Files.size(path);
        long lastModified = Files.getLastModifiedTime(path).toMillis();
        return etag(name, size, lastModified);
    }

    private static String etag(String name, long size, long lastModifid) {
        return String.format("%s_%s_%s", name, size, lastModifid);
    }

    /**
     * Web resource builder.
     */
    public static class Builder {

        private final WebResourceImpl resource;

        private Builder(String name, ThrowingSupplier contentSupplier) {
            this.resource = new WebResourceImpl(name, contentSupplier);
        }

        /**
         * Sets length of web resource content.
         *
         * @param length content length
         *
         * @return {@code this}
         */
        public Builder withContentLength(Long length) {
            if (length != null && length >= 0) {
                resource.contentLength = length;
            }
            return this;
        }

        /**
         * Sets the content type of the web resource.
         *
         * @param contentType content type
         *
         * @return {@code this}
         */
        public Builder withContentType(String contentType) {
            resource.contentType = contentType;
            return this;
        }

        /**
         * Sets the etag of the web resource.
         *
         * @param etag etag of resource
         *
         * @return {@code this}
         */
        public Builder withETag(String etag) {
            resource.etag = etag;
            return this;
        }

        /**
         * Sets the last modified date of the web resource.
         *
         * @param lastModifiedDate in milliseconds
         *
         * @return {@code this}
         */
        public Builder withLastModifiedDate(long lastModifiedDate) {
            if (lastModifiedDate != -1) {
                resource.lastModifiedDate = Instant.ofEpochMilli(lastModifiedDate);
            }
            return this;
        }

        /**
         * Sets the last modified date of the web resource.
         *
         * @param lastModifiedDate last modified date
         *
         * @return {@code this}
         */
        public Builder withLastModifiedDate(Instant lastModifiedDate) {
            resource.lastModifiedDate = lastModifiedDate;
            return this;
        }

        /**
         * Creates web resource.
         *
         * @return web resource
         */
        public WebResource build() {
            return resource;
        }

    }

    private static class WebResourceImpl implements WebResource {

        private final String name;
        private final ThrowingSupplier contentSupplier;
        private Long contentLength;
        private String contentType;
        private String etag;
        private Instant lastModifiedDate;

        private WebResourceImpl(String name, ThrowingSupplier contentSupplier) {
            this.name = name;
            this.contentSupplier = contentSupplier;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public InputStream getContent() throws IOException {
            return contentSupplier.get();
        }

        @Override
        public Optional getContentLength() {
            return Optional.ofNullable(contentLength);
        }

        @Override
        public Optional getContentType() {
            return Optional.ofNullable(contentType);
        }

        @Override
        public Optional getETag() {
            return Optional.ofNullable(etag);
        }

        @Override
        public Optional getLastModifiedDate() {
            return Optional.ofNullable(lastModifiedDate);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy