com.bigfatgun.fixjures.Strategies.java Source code

Java tutorial

Introduction

Here is the source code for com.bigfatgun.fixjures.Strategies.java

Source

/*
 * Copyright (c) 2010 Steve Reed
 *
 * Licensed 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.
 */

package com.bigfatgun.fixjures;

import com.google.common.base.Charsets;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableMap;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Map;

/**
 * Factory methods for various fixture source strategies.
 *
 * @author Steve Reed
 */
public final class Strategies {

    /** A strategy for finding source data for a fixture of a given type and name. */
    public static interface SourceStrategy {

        /**
         * Produces a byte channel from which fixture data can be read for an object of the given type and name.
         *
         * @param type fixture object type
         * @param name object name or id
         * @return source data channel
         * @throws IOException can be thrown when there is an error reading or finding source data
         */
        ReadableByteChannel findStream(Class<?> type, String name) throws IOException;
    }

    /** A strategy for producing resource names where fixture data is stored for objects of a given type and name. */
    public static interface ResourceNameStrategy {

        /**
         * Produces a name of a resource from which fixture data can be read for an object of the given type and name.
         *
         * @param type fixture object type
         * @param name object name or id
         * @return resource name
         */
        String getResourceName(Class<?> type, String name);

    }

    /**
     * The default name strategy for classpath sourced fixture factories.
     * <p/>
     * This strategy makes the factory look for fixtures in the classpath in "fixjures/<i>package.Class</i>/<i>name</i>.json".
     */
    public static final ResourceNameStrategy DEFAULT_CLASSPATH_NAME_STRATEGY = newFormatStringStrategy(
            "fixjures/%s/%s.json");

    /**
     * Creates a new resource name strategy based on a format string that will be passed to {@code String.format} with
     * {@code type.getName()} and {@code name} as the format arguments.
     *
     * @param formatStr format string, must be non-null
     * @return resource name
     */
    public static ResourceNameStrategy newFormatStringStrategy(final String formatStr) {
        checkNotNull(formatStr);

        return new ResourceNameStrategy() {
            public String getResourceName(final Class<?> type, final String name) {
                return String.format(formatStr, type.getName(), name);
            }
        };
    }

    /**
     * This source strategy does a simple lookup of type and name in a map that stores fixture data in raw byte arrays. A
     * defensive copy is made of the map argument, so only the fixtures in the map at the time this method is invoked can
     * be created.
     *
     * @param mem map that holds fixture data in memory
     * @return new source strategy
     */
    public static SourceStrategy newInMemoryStrategy(final Map<? extends Class<?>, Map<String, String>> mem) {
        final ImmutableMap<Class<?>, Map<String, String>> copy = ImmutableMap.copyOf(mem);
        return new SourceStrategy() {
            public ReadableByteChannel findStream(final Class<?> type, final String name) throws IOException {
                assert type != null : "Type cannot be null.";
                assert name != null : "Name cannot be null.";

                if (!copy.containsKey(type)) {
                    throw new IOException("Data for " + type + " not found.");
                } else if (!copy.get(type).containsKey(name)) {
                    throw new IOException("Data for " + type.getName() + " named " + name + " not found.");
                } else {
                    final byte[] bytes = copy.get(type).get(name).getBytes(Charsets.UTF_8);
                    return Channels.newChannel(new ByteArrayInputStream(bytes));
                }
            }
        };
    }

    /**
     * Creates a new source strategy that looks for fixture source data in the classpath based on {@link
     * #DEFAULT_CLASSPATH_NAME_STRATEGY}.
     *
     * @return new source strategy
     */
    public static SourceStrategy newClasspathStrategy() {
        return newClasspathStrategy(DEFAULT_CLASSPATH_NAME_STRATEGY);
    }

    /**
     * Creates a new source strategy that looks for fixture source data within the fixture object type's classloader.
     *
     * @param nameStrategy resource name strategy, must be non-null
     * @return new source strategy
     * @throws NullPointerException if {@code nameStrategy} is null
     */
    public static SourceStrategy newClasspathStrategy(final ResourceNameStrategy nameStrategy) {
        if (nameStrategy == null) {
            throw new NullPointerException("nameStrategy");
        }

        return new SourceStrategy() {
            public ReadableByteChannel findStream(final Class<?> type, final String name) throws IOException {
                assert type != null : "Type cannot be null.";
                assert name != null : "Name cannot be null.";

                final String resourceName = nameStrategy.getResourceName(type, name);

                checkNotNull(resourceName);

                final InputStream stream = type.getClassLoader().getResourceAsStream(resourceName);
                if (stream == null) {
                    throw new FixtureException("Resource not found: " + resourceName);
                }

                return Channels.newChannel(stream);
            }
        };
    }

    /**
     * Creates a new source strategy that looks for fixture source data in files based on {@link
     * #DEFAULT_CLASSPATH_NAME_STRATEGY}.
     *
     * @return new source strategy
     */
    public static SourceStrategy newFileStrategy() {
        return newFileStrategy(DEFAULT_CLASSPATH_NAME_STRATEGY);
    }

    /**
     * Creates a new source strategy that looks for fixture source data in a file.
     *
     * @param nameStrategy resource name strategy, must be non-null
     * @return new source strategy
     * @throws NullPointerException if {@code nameStrategy} is null
     */
    public static SourceStrategy newFileStrategy(final ResourceNameStrategy nameStrategy) {
        checkNotNull(nameStrategy);

        return new SourceStrategy() {
            public ReadableByteChannel findStream(final Class<?> type, final String name) throws IOException {
                assert type != null : "Type cannot be null.";
                assert name != null : "Name cannot be null.";

                return new RandomAccessFile(new File(nameStrategy.getResourceName(type, name)), "r").getChannel();
            }
        };
    }

    /**
     * Creates a new source strategy that looks for fixture source data in a file.
     *
     * @param clsLoader class loader to use to find resources
     * @param nameStrategy resource name strategy, must be non-null
     * @return new source strategy
     * @throws NullPointerException if {@code nameStrategy} is null
     */
    public static SourceStrategy newResourceStrategy(final ClassLoader clsLoader,
            final ResourceNameStrategy nameStrategy) {
        checkNotNull(nameStrategy);

        return new SourceStrategy() {
            public ReadableByteChannel findStream(final Class<?> type, final String name) throws IOException {
                assert type != null : "Type cannot be null.";
                assert name != null : "Name cannot be null.";

                final String rsrcName = nameStrategy.getResourceName(type, name);
                final InputStream stream = clsLoader.getResourceAsStream(rsrcName);
                if (stream == null) {
                    throw new FileNotFoundException(rsrcName);
                }
                return Channels.newChannel(stream);
            }
        };
    }
}