blob: cdc9438b94d0f4cf3248889dd56bbeaa28a4ffb4 [file] [log] [blame]
/*
* 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.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
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 static File getTempFile(String path) throws IOException {
File file = new File(System.getProperty("java.io.tmpdir"), path);
file.deleteOnExit();
return file;
}
/** {@inheritDoc} */
public Resource getResource(String id) throws IOException {
return new Resource(getTempFile(id).toURI().toURL().openStream());
}
/** {@inheritDoc} */
public OutputStream getOutputStream(String id) throws IOException {
File file = getTempFile(id);
if (file.createNewFile()) {
return new FileOutputStream(file);
} else {
throw new IOException("Filed to create temporary file: " + id);
}
}
}
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} */
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.
* <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 {@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<String, ResourceResolver> schemeHandlingResourceResolvers
= new HashMap<String, ResourceResolver>();
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;
}
}
}