blob: 72eac456da530cb795f85d53d3d38c01b3e4f895 [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;
/**
* 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-schema aware resource resolver. Temporary resource URIs are
* created by {@link TempResourceURIGenerator}.
*
* @param tempResourceResolver the temporary-resource-schema 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 schemas to implementations of
* {@link ResourceResolver}. This allows users to define their own URI schemas 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 schema
* @return the schema aware {@link ResourceResolver} builder
*/
public static SchemaAwareResourceResolverBuilder createSchemaAwareResourceResolverBuilder(
ResourceResolver defaultResolver) {
return new SchemaAwareResourceResolverBuilderImpl(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 SchemaAwareResourceResolver implements ResourceResolver {
private final Map<String, ResourceResolver> schemaHandlingResourceResolvers;
private final ResourceResolver defaultResolver;
private SchemaAwareResourceResolver(
Map<String, ResourceResolver> schemaHandlingResourceResolvers,
ResourceResolver defaultResolver) {
this.schemaHandlingResourceResolvers = schemaHandlingResourceResolvers;
this.defaultResolver = defaultResolver;
}
private ResourceResolver getResourceResolverForSchema(URI uri) {
String schema = uri.getScheme();
if (schemaHandlingResourceResolvers.containsKey(schema)) {
return schemaHandlingResourceResolvers.get(schema);
} else {
return defaultResolver;
}
}
/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException {
return getResourceResolverForSchema(uri).getResource(uri);
}
/** {@inheritDoc} */
public OutputStream getOutputStream(URI uri) throws IOException {
return getResourceResolverForSchema(uri).getOutputStream(uri);
}
}
/**
* Implementations of this interface will be builders for {@link ResourceResolver}, they bind
* URI schemas 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>
* SchemaAwareResourceResolverBuilder builder
* = ResourceResolverFactory.createSchemaAwareResourceResolverBuilder(defaultResolver);
* builder.registerResourceResolverForSchema("test", testResolver);
* builder.registerResourceResolverForSchema("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 SchemaAwareResourceResolverBuilder {
/**
* Register a schema with its respective {@link ResourceResolver}. This resolver will be
* used as the only resolver for the specified schema.
*
* @param schema the schema to be used with the given resolver
* @param resourceResolver the resource resolver
*/
void registerResourceResolverForSchema(String schema, ResourceResolver resourceResolver);
/**
* Builds a {@link ResourceResolver} that will delegate to the respective resource resolver
* when a registered URI schema is given
*
* @return a resolver that delegates to the appropriate schema resolver
*/
ResourceResolver build();
}
private static final class CompletedSchemaAwareResourceResolverBuilder
implements SchemaAwareResourceResolverBuilder {
private static final SchemaAwareResourceResolverBuilder INSTANCE
= new CompletedSchemaAwareResourceResolverBuilder();
/** {@inheritDoc} */
public ResourceResolver build() {
throw new IllegalStateException("Resource resolver already built");
}
/** {@inheritDoc} */
public void registerResourceResolverForSchema(String schema,
ResourceResolver resourceResolver) {
throw new IllegalStateException("Resource resolver already built");
}
}
private static final class ActiveSchemaAwareResourceResolverBuilder
implements SchemaAwareResourceResolverBuilder {
private final Map<String, ResourceResolver> schemaHandlingResourceResolvers
= new HashMap<String, ResourceResolver>();
private final ResourceResolver defaultResolver;
private ActiveSchemaAwareResourceResolverBuilder(ResourceResolver defaultResolver) {
this.defaultResolver = defaultResolver;
}
/** {@inheritDoc} */
public void registerResourceResolverForSchema(String schema,
ResourceResolver resourceResolver) {
schemaHandlingResourceResolvers.put(schema, resourceResolver);
}
/** {@inheritDoc} */
public ResourceResolver build() {
return new SchemaAwareResourceResolver(
Collections.unmodifiableMap(schemaHandlingResourceResolvers), defaultResolver);
}
}
private static final class SchemaAwareResourceResolverBuilderImpl
implements SchemaAwareResourceResolverBuilder {
private SchemaAwareResourceResolverBuilder delegate;
private SchemaAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) {
this.delegate = new ActiveSchemaAwareResourceResolverBuilder(defaultResolver);
}
/** {@inheritDoc} */
public void registerResourceResolverForSchema(String schema,
ResourceResolver resourceResolver) {
delegate.registerResourceResolverForSchema(schema, resourceResolver);
}
/** {@inheritDoc} */
public ResourceResolver build() {
ResourceResolver resourceResolver = delegate.build();
delegate = CompletedSchemaAwareResourceResolverBuilder.INSTANCE;
return resourceResolver;
}
}
}