/*
 * 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 ResourceResolvers.
/** * 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.
Returns:the default resource resolver
/** * 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: createDefaultResourceResolver().
Params:
  • baseURI – the base URI from which to resolve URIs
Returns:the default internal resource resolver
/** * 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.
Params:
  • baseURI – the base URI from which to resolve URIs
  • resolver – the resource resolver
Returns:the internal resource resolver
/** * 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 TempResourceURIGenerator.
Params:
  • tempResourceResolver – the temporary-resource-scheme resolver to use
  • defaultResourceResolver – the default resource resolver to use
Returns:the ressource 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 ResourceResolver. This allows users to define their own URI schemes such that they have finer control over the acquisition of resources.
Params:
  • defaultResolver – the default resource resolver that should be used in the event that none of the other registered resolvers match the scheme
Returns:the scheme aware ResourceResolver builder
/** * 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}
/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException { return delegate.getResource(uri); }
{@inheritDoc}
/** {@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}
/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException { if (isTempURI(uri)) { return tempResourceResolver.getResource(uri.getPath()); } else { return defaultResourceResolver.getResource(uri); } }
{@inheritDoc}
/** {@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<String, File> tempFiles = new ConcurrentHashMap<String, File>(); 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}
/** {@inheritDoc} */
public Resource getResource(String id) throws IOException { return new Resource(new FileDeletingInputStream(getTempFile(id))); }
{@inheritDoc}
/** {@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<String, ResourceResolver> schemeHandlingResourceResolvers; private final ResourceResolver defaultResolver; private SchemeAwareResourceResolver( Map<String, ResourceResolver> 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}
/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException { return getResourceResolverForScheme(uri).getResource(uri); }
{@inheritDoc}
/** {@inheritDoc} */
public OutputStream getOutputStream(URI uri) throws IOException { return getResourceResolverForScheme(uri).getOutputStream(uri); } }
Implementations of this interface will be builders for 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.
/** * 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. * <p> * Here is an example of how this could be used: * </p> * <p><code> * SchemeAwareResourceResolverBuilder builder * = ResourceResolverFactory.createSchemeAwareResourceResolverBuilder(defaultResolver); * builder.registerResourceResolverForScheme("test", testResolver); * builder.registerResourceResolverForScheme("anotherTest", test2Resolver); * ResourceResolver resolver = builder.build(); * </code></p> * This will result in all URIs for the form "test:///..." will be resolved using the * <code>testResolver</code> object; URIs of the form "anotherTest:///..." will be resolved * using <code>test2Resolver</code>; all other URIs will be resolved from the defaultResolver. */
public interface SchemeAwareResourceResolverBuilder {
Register a scheme with its respective ResourceResolver. This resolver will be used as the only resolver for the specified scheme.
Params:
  • scheme – the scheme to be used with the given resolver
  • resourceResolver – the resource resolver
/** * 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 ResourceResolver that will delegate to the respective resource resolver when a registered URI scheme is given
Returns:a resolver that delegates to the appropriate scheme resolver
/** * 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}
/** {@inheritDoc} */
public ResourceResolver build() { throw new IllegalStateException("Resource resolver already built"); }
{@inheritDoc}
/** {@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<String, ResourceResolver> schemeHandlingResourceResolvers = new HashMap<String, ResourceResolver>(); private final ResourceResolver defaultResolver; private ActiveSchemeAwareResourceResolverBuilder(ResourceResolver defaultResolver) { this.defaultResolver = defaultResolver; }
{@inheritDoc}
/** {@inheritDoc} */
public void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver) { schemeHandlingResourceResolvers.put(scheme, resourceResolver); }
{@inheritDoc}
/** {@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}
/** {@inheritDoc} */
public void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver) { delegate.registerResourceResolverForScheme(scheme, resourceResolver); }
{@inheritDoc}
/** {@inheritDoc} */
public ResourceResolver build() { ResourceResolver resourceResolver = delegate.build(); delegate = CompletedSchemeAwareResourceResolverBuilder.INSTANCE; return resourceResolver; } } }