| /* |
| * 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; |
| } |
| } |
| |
| } |