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

org.datavec.api.util.ClassPathResource Maven / Gradle / Ivy

There is a newer version: 1.0.0-M2.1
Show newest version
/*-
 *  * Copyright 2016 Skymind, Inc.
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 */

package org.datavec.api.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * Simple utility class used to get access to files at the classpath, or packed into jar.
 * Based on Spring ClassPathResource implementation + jar internals access implemented.
 *
 *
 * @author [email protected]
 */
public class ClassPathResource {

    private String resourceName;

    private static Logger log = LoggerFactory.getLogger(ClassPathResource.class);

    /**
     * Builds new ClassPathResource object
     *
     * @param resourceName String name of resource, to be retrieved
     */
    public ClassPathResource(String resourceName) {
        if (resourceName == null)
            throw new IllegalStateException("Resource name can't be null");
        this.resourceName = resourceName;
    }

    /**
     *  Returns URL of the requested resource
     *
     * @return URL of the resource, if it's available in current Jar
     */
    private URL getUrl() {
        ClassLoader loader = null;
        try {
            loader = Thread.currentThread().getContextClassLoader();
        } catch (Exception e) {
            // do nothing
        }

        if (loader == null) {
            loader = ClassPathResource.class.getClassLoader();
        }

        URL url = loader.getResource(this.resourceName);
        if (url == null) {
            // try to check for mis-used starting slash
            // TODO: see TODO below
            if (this.resourceName.startsWith("/")) {
                url = loader.getResource(this.resourceName.replaceFirst("[\\\\/]", ""));
                if (url != null)
                    return url;
            } else {
                // try to add slash, to make clear it's not an issue
                // TODO: change this mechanic to actual path purifier
                url = loader.getResource("/" + this.resourceName);
                if (url != null)
                    return url;
            }
            throw new IllegalStateException("Resource '" + this.resourceName + "' cannot be found.");
        }
        return url;
    }

    /**
     * Returns requested ClassPathResource as File object
     *
     * Please note: if this method called from compiled jar, temporary file or dir will be created to provide File access
     *
     * @return File requested at constructor call
     * @throws FileNotFoundException
     */
    public File getFile() throws FileNotFoundException {
        return getFile(null);
    }

    /**
     * Returns requested ClassPathResource as File object
     *
     * Please note: if this method called from compiled jar, temporary file or dir will be created to provide File access
     *
     * @param suffix suffix of temporary file (if null suffix == "file" or "dir")
     * @return File requested at constructor call
     * @throws FileNotFoundException
     */
    public File getFile(String suffix) throws FileNotFoundException {
        URL url = this.getUrl();

        if (isJarURL(url)) {
            /*
                This is actually request for file, that's packed into jar. Probably the current one, but that doesn't matters.
             */
            try {
                GetStreamFromZip getStreamFromZip = new GetStreamFromZip(url, resourceName).invoke();
                ZipEntry entry = getStreamFromZip.getEntry();
                InputStream stream = getStreamFromZip.getStream();
                ZipFile zipFile = getStreamFromZip.getZipFile();
                url = getStreamFromZip.getUrl();

                if (entry.isDirectory() || stream == null) {
                    zipFile.close();

                    File dir = new File(System.getProperty("java.io.tmpdir"),
                                    "datavec_temp" + System.nanoTime() + (suffix != null ? suffix : "dir"));
                    if (dir.mkdir()) {
                        dir.deleteOnExit();
                    }
                    ArchiveUtils.unzipFileTo(url.getFile(), dir.getAbsolutePath());
                    return new File(dir, this.resourceName);
                }

                long size = entry.getSize();
                File file = File.createTempFile("datavec_temp", (suffix != null ? suffix : "file"));
                file.deleteOnExit();

                FileOutputStream outputStream = new FileOutputStream(file);
                byte[] array = new byte[1024];
                int rd = 0;
                long bytesRead = 0;
                do {
                    rd = stream.read(array);
                    outputStream.write(array, 0, rd);
                    bytesRead += rd;
                } while (bytesRead < size);

                outputStream.flush();
                outputStream.close();

                stream.close();
                zipFile.close();

                return file;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        } else {
            /*
                It's something in the actual underlying filesystem, so we can just go for it
             */

            try {
                URI uri = new URI(url.toString().replaceAll(" ", "%20"));
                return new File(uri.getSchemeSpecificPart());
            } catch (URISyntaxException e) {
                return new File(url.getFile());
            }
        }
    }

    /**
     * Checks, if proposed URL is packed into archive.
     *
     * @param url URL to be checked
     * @return True, if URL is archive entry, False otherwise
     */
    private boolean isJarURL(URL url) {
        String protocol = url.getProtocol();
        return "jar".equals(protocol) || "zip".equals(protocol) || "wsjar".equals(protocol)
                        || "code-source".equals(protocol) && url.getPath().contains("!/");
    }

    /**
     * Extracts parent Jar URL from original ClassPath entry URL.
     *
     * @param jarUrl Original URL of the resource
     * @return URL of the Jar file, containing requested resource
     * @throws MalformedURLException
     */
    private URL extractActualUrl(URL jarUrl) throws MalformedURLException {
        String urlFile = jarUrl.getFile();
        int separatorIndex = urlFile.indexOf("!/");
        if (separatorIndex != -1) {
            String jarFile = urlFile.substring(0, separatorIndex);

            try {
                return new URL(jarFile);
            } catch (MalformedURLException var5) {
                if (!jarFile.startsWith("/")) {
                    jarFile = "/" + jarFile;
                }

                return new URL("file:" + jarFile);
            }
        } else {
            return jarUrl;
        }
    }

    /**
     * Returns requested ClassPathResource as InputStream object
     *
     * @return File requested at constructor call
     * @throws FileNotFoundException
     */
    public InputStream getInputStream() throws FileNotFoundException {
        URL url = this.getUrl();
        if (isJarURL(url)) {
            try {
                GetStreamFromZip getStreamFromZip = new GetStreamFromZip(url, resourceName).invoke();
                InputStream stream = getStreamFromZip.getStream();

                return stream;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            File srcFile = this.getFile();
            return new FileInputStream(srcFile);
        }
    }

    private class GetStreamFromZip {
        private URL url;
        private ZipFile zipFile;
        private ZipEntry entry;
        private InputStream stream;
        private String resourceName;

        public GetStreamFromZip(URL url, String resourceName) {
            this.url = url;
            this.resourceName = resourceName;
        }

        public URL getUrl() {
            return url;
        }

        public ZipFile getZipFile() {
            return zipFile;
        }

        public ZipEntry getEntry() {
            return entry;
        }

        public InputStream getStream() {
            return stream;
        }

        public GetStreamFromZip invoke() throws IOException {
            url = extractActualUrl(url);

            zipFile = new ZipFile(url.getFile());
            entry = zipFile.getEntry(this.resourceName);
            if (entry == null) {
                if (this.resourceName.startsWith("/")) {
                    entry = zipFile.getEntry(this.resourceName.replaceFirst("/", ""));
                    if (entry == null) {
                        throw new FileNotFoundException("Resource " + this.resourceName + " not found");
                    }
                } else
                    throw new FileNotFoundException("Resource " + this.resourceName + " not found");
            }

            stream = zipFile.getInputStream(entry);
            return this;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy