org.cloudfoundry.tools.io.ResourceURL.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.tools.io.ResourceURL.java

Source

/*
 * Copyright 2010-2012 the original author or authors.
 *
 * 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.cloudfoundry.tools.io;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.cloudfoundry.tools.io.exception.ResourceTypeMismatchException;
import org.cloudfoundry.tools.io.zip.ZipArchive;
import org.springframework.util.ObjectUtils;

/**
 * Factory class that can be used to construct a {@link URL} for a given {@link Resource}. The {@link URL}s returned
 * from this class can be used to access file content using the {@link URL#openStream()} method, however, the URL cannot
 * be serialized. URLs can be used with a {@link URLClassLoader}.
 * 
 * @author Phillip Webb
 */
public abstract class ResourceURL {

    private static final ResourceFilter ZIPPED_RESOURCES = FilterOn.names().ending(".jar", ".zip");

    public static final String PROTOCOL = "rfs";

    /**
     * Get a URL for the given {@link Resource}.
     * 
     * @param resource the resource
     * @return a URL for the resource
     * @throws MalformedURLException
     */
    public static URL get(Resource resource) throws MalformedURLException {
        return get(resource, false);
    }

    /**
     * Get a URL for the given {@link Resource}.
     * 
     * @param resource the resource
     * @param nonLocking if the URL should protect against file locking
     * @return a URL for the resource
     * @throws MalformedURLException
     */
    public static URL get(Resource resource, boolean nonLocking) throws MalformedURLException {
        // zipped resource cannot be handled by URLClassLoader, make it look like a folder
        if (resource instanceof File && ZIPPED_RESOURCES.match(null, resource)) {
            resource = new ZipArchive((File) resource);
        }
        ResourceURLStreamHandler handler = new ResourceURLStreamHandler(resource, nonLocking);
        return new URL(PROTOCOL, resource.getClass().getName() + "@" + ObjectUtils.getIdentityHexString(resource),
                0, resource.toString(), handler);
    }

    /**
     * Get a {@link List} of {@link URL}s for the given {@link Resource}s.
     * 
     * @param resources
     * @return a list of URLs for the resource
     * @throws MalformedURLException
     */
    public static List<URL> getForResources(Iterable<? extends Resource> resources) throws MalformedURLException {
        return getForResources(resources, false);
    }

    /**
     * Get a {@link List} of {@link URL}s for the given {@link Resource}s.
     * 
     * @param resources
     * @param nonLocking if the URL should protect against file locking
     * @return a list of URLs for the resource
     * @throws MalformedURLException
     */
    public static List<URL> getForResources(Iterable<? extends Resource> resources, boolean nonLocking)
            throws MalformedURLException {
        List<URL> urls = new ArrayList<URL>();
        for (Resource resource : resources) {
            urls.add(get(resource, nonLocking));
        }
        return Collections.unmodifiableList(urls);
    }

    /**
     * Internal {@link URLStreamHandler} used with {@link Resource} URLs.
     */
    private static class ResourceURLStreamHandler extends URLStreamHandler {

        private final Folder root;

        private final boolean nonLocking;

        public ResourceURLStreamHandler(Resource resource, boolean nonLocking) {
            this.root = findRoot(resource);
            this.nonLocking = nonLocking;
        }

        @Override
        protected void parseURL(URL u, String spec, int start, int limit) {
            super.parseURL(u, spec, start, limit);
        }

        private Folder findRoot(Resource resource) {
            Resource root = resource;
            while (root.getParent() != null) {
                root = root.getParent();
            }
            return (Folder) root;
        }

        @Override
        protected URLConnection openConnection(URL url) throws IOException {
            String path = url.getPath();
            if ("/".equals(path)) {
                throw new IOException("Unable to open root folder");
            }
            try {
                File file = this.root.getFile(path);
                if (!file.exists()) {
                    throw new IOException("File '" + file + "' does not exist");
                }
                return new FileURLConnection(url, file, this.nonLocking);
            } catch (ResourceTypeMismatchException e) {
                throw new IOException("Unable to open URL connection to folder '" + path + "'", e);
            }
        }
    }

    /**
     * Internal {@link URLConnection} used with {@link Resource} URLs.
     */
    private static class FileURLConnection extends URLConnection {

        private final File file;

        private final boolean nonLocking;

        public FileURLConnection(URL url, File file, boolean nonLocking) {
            super(url);
            this.file = file;
            this.nonLocking = nonLocking;
        }

        @Override
        public void connect() throws IOException {
        }

        @Override
        public InputStream getInputStream() throws IOException {
            if (this.nonLocking) {
                return new ByteArrayInputStream(this.file.getContent().asBytes());
            }
            return this.file.getContent().asInputStream();
        }
    }
}