org.wikidata.wdtk.testing.MockDirectoryManager.java Source code

Java tutorial

Introduction

Here is the source code for org.wikidata.wdtk.testing.MockDirectoryManager.java

Source

package org.wikidata.wdtk.testing;

/*
 * #%L
 * Wikidata Toolkit Dump File Handling
 * %%
 * Copyright (C) 2014 Wikidata Toolkit Developers
 * %%
 * 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.
 * #L%
 */

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;

import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.wikidata.wdtk.util.CompressionType;
import org.wikidata.wdtk.util.DirectoryManager;

/**
 * Mock implementation of {@link DirectoryManager} that simulates file access
 * without touching the file system.
 *
 * @author Markus Kroetzsch
 *
 */
public class MockDirectoryManager implements DirectoryManager {

    /**
     * Mock files with this content are interpreted as directories.
     */
    static final String DIRECTORY_MARKER_STRING = "DIRECTORY";

    /**
     * Mock files with this content are interpreted as directories.
     */
    static final byte[] DIRECTORY_MARKER = DIRECTORY_MARKER_STRING.getBytes(StandardCharsets.UTF_8);

    /**
     * The mocked file system. This is static so that it can be accessed after a
     * test even if the directory manager that was used is created internally.
     */
    public static HashMap<Path, byte[]> files = new HashMap<>();

    final Path directory;
    boolean returnFailingReaders;

    /**
     * Creates a new object and clears all previously stored files.
     *
     * @param directory
     *            initial directory that is managed
     * @throws IOException
     */
    public MockDirectoryManager(Path directory) throws IOException {

        this(directory, true);
    }

    /**
     * Creates a new object and clears all previously stored if requested.
     *
     * @param directory
     *            initial directory that is managed
     * @param resetFileSystem
     *            if true, the previously mocked files will be cleared
     * @throws IOException
     */
    public MockDirectoryManager(Path directory, boolean resetFileSystem) throws IOException {
        this.directory = directory;

        if (resetFileSystem) {
            files = new HashMap<>();
        }

        if (files.containsKey(directory) && !Arrays.equals(files.get(directory), DIRECTORY_MARKER)) {
            throw new IOException("Could not create mock working directory.");
        }
        setDirectory(directory);
    }

    /**
     * When set to true, every operation that returns reader objects to access
     * some file will return objects that fail with exceptions when trying to
     * read the file. This can be used to simulate problems like insufficient
     * access rights or files becoming inaccessible after being opened.
     * <p>
     * The property is inherited by any submanagers that are created by this
     * object.
     *
     * @param returnFailingReaders
     *            whether read operations should fail
     */
    public void setReturnFailingReaders(boolean returnFailingReaders) {
        this.returnFailingReaders = returnFailingReaders;
    }

    @Override
    public String toString() {
        return "[mocked directory] " + this.directory.toString();
    }

    /**
     * Sets the contents of the file at the given path and creates all parent
     * directories in our mocked view of the file system.
     *
     * @param path
     * @param contents
     * @throws IOException
     */
    public void setFileContents(Path path, String contents) throws IOException {
        setFileContents(path, contents, CompressionType.NONE);
    }

    /**
     * Sets the contents of the file at the given path and creates all parent
     * directories in our mocked view of the file system. If a compression is
     * chosen, the file contents is the compressed version of the given
     * contents. Strings are encoded as UTF8.
     *
     * @param path
     * @param contents
     * @param compressionType
     * @throws IOException
     */
    public void setFileContents(Path path, String contents, CompressionType compressionType) throws IOException {
        files.put(path, MockStringContentFactory.getBytesFromString(contents, compressionType));
        Path parent = path.getParent();
        if (parent != null) {
            setFileContents(parent, DIRECTORY_MARKER_STRING);
        }
    }

    /**
     * Create the given directory and all parent directories in our mocked view
     * of the file system.
     *
     * @param path
     * @throws IOException
     */
    public void setDirectory(Path path) throws IOException {
        setFileContents(path, DIRECTORY_MARKER_STRING);
    }

    @Override
    public DirectoryManager getSubdirectoryManager(String subdirectoryName) throws IOException {
        MockDirectoryManager result = new MockDirectoryManager(directory.resolve(subdirectoryName), false);
        result.setReturnFailingReaders(this.returnFailingReaders);
        return result;
    }

    @Override
    public boolean hasSubdirectory(String subdirectoryName) {
        Path directoryPath = this.directory.resolve(subdirectoryName);
        return Arrays.equals(DIRECTORY_MARKER, files.get(directoryPath));
    }

    @Override
    public boolean hasFile(String fileName) {
        Path filePath = this.directory.resolve(fileName);
        return files.containsKey(filePath) && !Arrays.equals(files.get(filePath), DIRECTORY_MARKER);
    }

    @Override
    public long createFile(String fileName, InputStream inputStream) throws IOException {

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int nextByte = 0;
        while ((nextByte = inputStream.read()) >= 0) {
            out.write(nextByte);
        }
        out.close();

        Path filePath = this.directory.resolve(fileName);
        files.put(filePath, out.toByteArray());

        return out.size();

        // BufferedReader br = new BufferedReader(new InputStreamReader(
        // inputStream));
        // StringBuilder contentsBuilder = new StringBuilder();
        // String line;
        // while ((line = br.readLine()) != null) {
        // contentsBuilder.append(line).append("\n");
        // }
        // createFile(fileName, contentsBuilder.toString());
        //
        // return
        // contentsBuilder.toString().getBytes(StandardCharsets.UTF_8).length;
    }

    @Override
    public long createFileAtomic(String fileName, InputStream inputStream) throws IOException {
        return createFile(fileName, inputStream);
    }

    @Override
    public void createFile(String fileName, String fileContents) throws IOException {
        if (this.hasFile(fileName)) {
            throw new FileAlreadyExistsException("File exists");
        }
        Path filePath = this.directory.resolve(fileName);
        files.put(filePath, fileContents.getBytes(StandardCharsets.UTF_8));
    }

    @Override
    public OutputStream getOutputStreamForFile(String fileName) throws IOException {
        Path filePath = this.directory.resolve(fileName);
        return new MockOutputStream(filePath);
    }

    @Override
    public InputStream getInputStreamForFile(String fileName, CompressionType compressionType) throws IOException {
        if (compressionType == CompressionType.GZIP) {
            return new GZIPInputStream(getInputStreamForMockFile(fileName));
        } else if (compressionType == CompressionType.BZ2) {
            return new BZip2CompressorInputStream(getInputStreamForMockFile(fileName));
        } else {
            return getInputStreamForMockFile(fileName);
        }
    }

    /**
     * Get an input stream for the mocked contents of the given file, or throw
     * an exception if the file does not exist.
     *
     * @param fileName
     * @return input stream for file
     * @throws FileNotFoundException
     */
    InputStream getInputStreamForMockFile(String fileName) throws FileNotFoundException {
        if (!hasFile(fileName)) {
            throw new FileNotFoundException("Could not find file \"" + fileName + "\" in current directory \""
                    + this.directory.toString() + "\"");
        }

        if (this.returnFailingReaders) {
            return MockStringContentFactory.getFailingInputStream();
        } else {
            Path filePath = this.directory.resolve(fileName);
            return MockStringContentFactory.newMockInputStream(files.get(filePath));
        }
    }

    @Override
    public List<String> getSubdirectories(String glob) throws IOException {
        List<String> result = new ArrayList<String>();
        PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + glob);
        for (Path path : files.keySet()) {
            if (!this.directory.equals(path.getParent())) {
                continue;
            }
            if (pathMatcher.matches(path.getFileName())) {
                result.add(path.getFileName().toString());
            }
        }
        return result;
    }

    /**
     * Returns the byte contents of the mocked file for the given path. If the
     * file is not mocked, null is returned. If the file is a mocked directory,
     * the bytes of {@link MockDirectoryManager#DIRECTORY_MARKER} are returned.
     *
     * @param filePath
     *            the path of the mocked file
     * @return byte contents of mocked file
     */
    public static byte[] getMockedFileContents(Path filePath) {
        return files.get(filePath);
    }
}