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

org.apache.fop.apps.io.ResourceResolverFactory Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/* $Id$ */

package org.apache.fop.apps.io;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.xmlgraphics.io.Resource;
import org.apache.xmlgraphics.io.ResourceResolver;
import org.apache.xmlgraphics.io.TempResourceResolver;
import org.apache.xmlgraphics.io.TempResourceURIGenerator;

/**
 * A factory class for {@link ResourceResolver}s.
 */
public final class ResourceResolverFactory {

    private ResourceResolverFactory() {
    }

    /**
     * Returns the default resource resolver, this is most basic resolver which can be used when
     * no there are no I/O or file access restrictions.
     *
     * @return the default resource resolver
     */
    public static ResourceResolver createDefaultResourceResolver() {
        return DefaultResourceResolver.INSTANCE;
    }

    /**
     * A helper merthod that creates an internal resource resolver using the default resover:
     * {@link ResourceResolverFactory#createDefaultResourceResolver()}.
     *
     * @param baseURI the base URI from which to resolve URIs
     * @return the default internal resource resolver
     */
    public static InternalResourceResolver createDefaultInternalResourceResolver(URI baseURI) {
        return new InternalResourceResolver(baseURI, createDefaultResourceResolver());
    }

    /**
     * Creates an interal resource resolver given a base URI and a resource resolver.
     *
     * @param baseURI the base URI from which to resolve URIs
     * @param resolver the resource resolver
     * @return the internal resource resolver
     */
    public static InternalResourceResolver createInternalResourceResolver(URI baseURI,
            ResourceResolver resolver) {
        return new InternalResourceResolver(baseURI, resolver);
    }

    /**
     * Creates a temporary-resource-scheme aware resource resolver. Temporary resource URIs are
     * created by {@link TempResourceURIGenerator}.
     *
     * @param tempResourceResolver the temporary-resource-scheme resolver to use
     * @param defaultResourceResolver the default resource resolver to use
     * @return the ressource resolver
     */
    public static ResourceResolver createTempAwareResourceResolver(
            TempResourceResolver tempResourceResolver,
            ResourceResolver defaultResourceResolver) {
        return new TempAwareResourceResolver(tempResourceResolver, defaultResourceResolver);
    }

    /**
     * This creates the builder class for binding URI schemes to implementations of
     * {@link ResourceResolver}. This allows users to define their own URI schemes such that they
     * have finer control over the acquisition of resources.
     *
     * @param defaultResolver the default resource resolver that should be used in the event that
     * none of the other registered resolvers match the scheme
     * @return the scheme aware {@link ResourceResolver} builder
     */
    public static SchemeAwareResourceResolverBuilder createSchemeAwareResourceResolverBuilder(
            ResourceResolver defaultResolver) {
        return new SchemeAwareResourceResolverBuilderImpl(defaultResolver);
    }

    private static final class DefaultResourceResolver implements ResourceResolver {

        private static final ResourceResolver INSTANCE = new DefaultResourceResolver();

        private final TempAwareResourceResolver delegate;

        private DefaultResourceResolver() {
            delegate = new TempAwareResourceResolver(new DefaultTempResourceResolver(),
                    new NormalResourceResolver());
        }

        /** {@inheritDoc} */
        public Resource getResource(URI uri) throws IOException {
            return delegate.getResource(uri);
        }

        /** {@inheritDoc} */
        public OutputStream getOutputStream(URI uri) throws IOException {
            return delegate.getOutputStream(uri);
        }

    }

    private static final class TempAwareResourceResolver implements ResourceResolver {

        private final TempResourceResolver tempResourceResolver;

        private final ResourceResolver defaultResourceResolver;

        public TempAwareResourceResolver(TempResourceResolver tempResourceHandler,
                ResourceResolver defaultResourceResolver) {
            this.tempResourceResolver = tempResourceHandler;
            this.defaultResourceResolver = defaultResourceResolver;
        }

        private static boolean isTempURI(URI uri) {
            return TempResourceURIGenerator.isTempURI(uri);
        }

        /** {@inheritDoc} */
        public Resource getResource(URI uri) throws IOException {
            if (isTempURI(uri)) {
                return tempResourceResolver.getResource(uri.getPath());
            } else {
                return defaultResourceResolver.getResource(uri);
            }
        }

        /** {@inheritDoc} */
        public OutputStream getOutputStream(URI uri) throws IOException {
            if (isTempURI(uri)) {
                return tempResourceResolver.getOutputStream(uri.getPath());
            } else {
                return defaultResourceResolver.getOutputStream(uri);
            }
        }
    }

    private static class DefaultTempResourceResolver implements TempResourceResolver {

        private final ConcurrentHashMap tempFiles = new ConcurrentHashMap();

        private File getTempFile(String uri) throws IllegalStateException {
            File tempFile = tempFiles.remove(uri);
            if (tempFile == null) {
                throw new IllegalStateException(uri + " was never created or has been deleted");
            }
            return tempFile;
        }

        private File createTempFile(String path) throws IOException {
            File tempFile = File.createTempFile(path, ".fop.tmp");
            File oldFile = tempFiles.put(path, tempFile);
            if (oldFile != null) {
                String errorMsg = oldFile.getAbsolutePath() + " has been already created for " + path;
                boolean newTempDeleted = tempFile.delete();
                if (!newTempDeleted) {
                    errorMsg += ". " + tempFile.getAbsolutePath() + " was not deleted.";
                }
                throw new IOException(errorMsg);
            }
            return tempFile;
        }

        /** {@inheritDoc} */
        public Resource getResource(String id) throws IOException {
            return new Resource(new FileDeletingInputStream(getTempFile(id)));
        }

        /** {@inheritDoc} */
        public OutputStream getOutputStream(String id) throws IOException {
            return new FileOutputStream(createTempFile(id));
        }
    }

    private static class FileDeletingInputStream extends FilterInputStream {

        private final File file;

        protected FileDeletingInputStream(File file) throws MalformedURLException, IOException {
            super(file.toURI().toURL().openStream());
            this.file = file;
        }

        @Override
        public void close() throws IOException {
            try {
                super.close();
            } finally {
                file.delete();
            }
        }
    }

    private static class NormalResourceResolver implements ResourceResolver {
        public Resource getResource(URI uri) throws IOException {
            return new Resource(uri.toURL().openStream());
        }

        public OutputStream getOutputStream(URI uri) throws IOException {
            return new FileOutputStream(new File(uri));
        }
    }

    private static final class SchemeAwareResourceResolver implements ResourceResolver {

        private final Map schemeHandlingResourceResolvers;

        private final ResourceResolver defaultResolver;

        private SchemeAwareResourceResolver(
                Map schemEHandlingResourceResolvers,
                ResourceResolver defaultResolver) {
            this.schemeHandlingResourceResolvers = schemEHandlingResourceResolvers;
            this.defaultResolver = defaultResolver;
        }

        private ResourceResolver getResourceResolverForScheme(URI uri) {
            String scheme = uri.getScheme();
            if (schemeHandlingResourceResolvers.containsKey(scheme)) {
                return schemeHandlingResourceResolvers.get(scheme);
            } else {
                return defaultResolver;
            }
        }

        /** {@inheritDoc} */
        public Resource getResource(URI uri) throws IOException {
            return getResourceResolverForScheme(uri).getResource(uri);
        }

        /** {@inheritDoc} */
        public OutputStream getOutputStream(URI uri) throws IOException {
            return getResourceResolverForScheme(uri).getOutputStream(uri);
        }
    }

    /**
     * Implementations of this interface will be builders for {@link ResourceResolver}, they bind
     * URI schemes to their respective resolver. This gives users more control over the mechanisms
     * by which URIs are resolved.
     * 

* Here is an example of how this could be used: *

*

* SchemeAwareResourceResolverBuilder builder * = ResourceResolverFactory.createSchemeAwareResourceResolverBuilder(defaultResolver); * builder.registerResourceResolverForScheme("test", testResolver); * builder.registerResourceResolverForScheme("anotherTest", test2Resolver); * ResourceResolver resolver = builder.build(); *

* This will result in all URIs for the form "test:///..." will be resolved using the * testResolver object; URIs of the form "anotherTest:///..." will be resolved * using test2Resolver; all other URIs will be resolved from the defaultResolver. */ public interface SchemeAwareResourceResolverBuilder { /** * Register a scheme with its respective {@link ResourceResolver}. This resolver will be * used as the only resolver for the specified scheme. * * @param scheme the scheme to be used with the given resolver * @param resourceResolver the resource resolver */ void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver); /** * Builds a {@link ResourceResolver} that will delegate to the respective resource resolver * when a registered URI scheme is given * * @return a resolver that delegates to the appropriate scheme resolver */ ResourceResolver build(); } private static final class CompletedSchemeAwareResourceResolverBuilder implements SchemeAwareResourceResolverBuilder { private static final SchemeAwareResourceResolverBuilder INSTANCE = new CompletedSchemeAwareResourceResolverBuilder(); /** {@inheritDoc} */ public ResourceResolver build() { throw new IllegalStateException("Resource resolver already built"); } /** {@inheritDoc} */ public void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver) { throw new IllegalStateException("Resource resolver already built"); } } private static final class ActiveSchemeAwareResourceResolverBuilder implements SchemeAwareResourceResolverBuilder { private final Map schemeHandlingResourceResolvers = new HashMap(); private final ResourceResolver defaultResolver; private ActiveSchemeAwareResourceResolverBuilder(ResourceResolver defaultResolver) { this.defaultResolver = defaultResolver; } /** {@inheritDoc} */ public void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver) { schemeHandlingResourceResolvers.put(scheme, resourceResolver); } /** {@inheritDoc} */ public ResourceResolver build() { return new SchemeAwareResourceResolver( Collections.unmodifiableMap(schemeHandlingResourceResolvers), defaultResolver); } } private static final class SchemeAwareResourceResolverBuilderImpl implements SchemeAwareResourceResolverBuilder { private SchemeAwareResourceResolverBuilder delegate; private SchemeAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) { this.delegate = new ActiveSchemeAwareResourceResolverBuilder(defaultResolver); } /** {@inheritDoc} */ public void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver) { delegate.registerResourceResolverForScheme(scheme, resourceResolver); } /** {@inheritDoc} */ public ResourceResolver build() { ResourceResolver resourceResolver = delegate.build(); delegate = CompletedSchemeAwareResourceResolverBuilder.INSTANCE; return resourceResolver; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy