org.apache.hadoop.fs.FSDataOutputStreamBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.fs.FSDataOutputStreamBuilder.java

Source

/**
 * 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.
 */
package org.apache.hadoop.fs;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Options.ChecksumOpt;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.util.Progressable;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;

import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_DEFAULT;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_KEY;

/**
 * Builder for {@link FSDataOutputStream} and its subclasses.
 *
 * It is used to create {@link FSDataOutputStream} when creating a new file or
 * appending an existing file on {@link FileSystem}.
 *
 * By default, it does not create parent directory that do not exist.
 * {@link FileSystem#createNonRecursive(Path, boolean, int, short, long,
 * Progressable)}.
 *
 * To create missing parent directory, use {@link #recursive()}.
 *
 * To be more generic, {@link #opt(String, int)} and {@link #must(String, int)}
 * variants provide implementation-agnostic way to customize the builder.
 * Each FS-specific builder implementation can interpret the FS-specific
 * options accordingly, for example:
 *
 * <code>
 *
 * // Don't
 * if (fs instanceof FooFileSystem) {
 *   FooFileSystem fs = (FooFileSystem) fs;
 *   OutputStream out = dfs.createFile(path)
 *     .optionA()
 *     .optionB("value")
 *     .cache()
 *   .build()
 * } else if (fs instanceof BarFileSystem) {
 *   ...
 * }
 *
 * // Do
 * OutputStream out = fs.createFile(path)
 *   .permission(perm)
 *   .bufferSize(bufSize)
 *   .opt("foofs:option.a", true)
 *   .opt("foofs:option.b", "value")
 *   .opt("barfs:cache", true)
 *   .must("foofs:cache", true)
 *   .must("barfs:cache-size", 256 * 1024 * 1024)
 *   .build();
 * </code>
 *
 * If the option is not related to the file system, the option will be ignored.
 * If the option is must, but not supported by the file system, a
 * {@link IllegalArgumentException} will be thrown.
 *
 */
@InterfaceAudience.Public
@InterfaceStability.Evolving
public abstract class FSDataOutputStreamBuilder<S extends FSDataOutputStream, B extends FSDataOutputStreamBuilder<S, B>> {
    private final FileSystem fs;
    private final Path path;
    private FsPermission permission = null;
    private int bufferSize;
    private short replication;
    private long blockSize;
    /** set to true to create missing directory. */
    private boolean recursive = false;
    private final EnumSet<CreateFlag> flags = EnumSet.noneOf(CreateFlag.class);
    private Progressable progress = null;
    private ChecksumOpt checksumOpt = null;

    /**
     * Contains optional and mandatory parameters.
     *
     * It does not load default configurations from default files.
     */
    private final Configuration options = new Configuration(false);

    /** Keep track of the keys for mandatory options. */
    private final Set<String> mandatoryKeys = new HashSet<>();

    /**
     * Return the concrete implementation of the builder instance.
     */
    protected abstract B getThisBuilder();

    /**
     * Construct from a {@link FileContext}.
     *
     * @param fc FileContext
     * @param p path.
     * @throws IOException
     */
    FSDataOutputStreamBuilder(@Nonnull FileContext fc, @Nonnull Path p) throws IOException {
        Preconditions.checkNotNull(fc);
        Preconditions.checkNotNull(p);
        this.fs = null;
        this.path = p;

        AbstractFileSystem afs = fc.getFSofPath(p);
        FsServerDefaults defaults = afs.getServerDefaults(p);
        bufferSize = defaults.getFileBufferSize();
        replication = defaults.getReplication();
        blockSize = defaults.getBlockSize();
    }

    /**
     * Constructor.
     */
    protected FSDataOutputStreamBuilder(@Nonnull FileSystem fileSystem, @Nonnull Path p) {
        Preconditions.checkNotNull(fileSystem);
        Preconditions.checkNotNull(p);
        fs = fileSystem;
        path = p;
        bufferSize = fs.getConf().getInt(IO_FILE_BUFFER_SIZE_KEY, IO_FILE_BUFFER_SIZE_DEFAULT);
        replication = fs.getDefaultReplication(path);
        blockSize = fs.getDefaultBlockSize(p);
    }

    protected FileSystem getFS() {
        Preconditions.checkNotNull(fs);
        return fs;
    }

    protected Path getPath() {
        return path;
    }

    protected FsPermission getPermission() {
        if (permission == null) {
            permission = FsPermission.getFileDefault();
        }
        return permission;
    }

    /**
     * Set permission for the file.
     */
    public B permission(@Nonnull final FsPermission perm) {
        Preconditions.checkNotNull(perm);
        permission = perm;
        return getThisBuilder();
    }

    protected int getBufferSize() {
        return bufferSize;
    }

    /**
     * Set the size of the buffer to be used.
     */
    public B bufferSize(int bufSize) {
        bufferSize = bufSize;
        return getThisBuilder();
    }

    protected short getReplication() {
        return replication;
    }

    /**
     * Set replication factor.
     */
    public B replication(short replica) {
        replication = replica;
        return getThisBuilder();
    }

    protected long getBlockSize() {
        return blockSize;
    }

    /**
     * Set block size.
     */
    public B blockSize(long blkSize) {
        blockSize = blkSize;
        return getThisBuilder();
    }

    /**
     * Return true to create the parent directories if they do not exist.
     */
    protected boolean isRecursive() {
        return recursive;
    }

    /**
     * Create the parent directory if they do not exist.
     */
    public B recursive() {
        recursive = true;
        return getThisBuilder();
    }

    protected Progressable getProgress() {
        return progress;
    }

    /**
     * Set the facility of reporting progress.
     */
    public B progress(@Nonnull final Progressable prog) {
        Preconditions.checkNotNull(prog);
        progress = prog;
        return getThisBuilder();
    }

    protected EnumSet<CreateFlag> getFlags() {
        return flags;
    }

    /**
     * Create an FSDataOutputStream at the specified path.
     */
    public B create() {
        flags.add(CreateFlag.CREATE);
        return getThisBuilder();
    }

    /**
     * Set to true to overwrite the existing file.
     * Set it to false, an exception will be thrown when calling {@link #build()}
     * if the file exists.
     */
    public B overwrite(boolean overwrite) {
        if (overwrite) {
            flags.add(CreateFlag.OVERWRITE);
        } else {
            flags.remove(CreateFlag.OVERWRITE);
        }
        return getThisBuilder();
    }

    /**
     * Append to an existing file (optional operation).
     */
    public B append() {
        flags.add(CreateFlag.APPEND);
        return getThisBuilder();
    }

    protected ChecksumOpt getChecksumOpt() {
        return checksumOpt;
    }

    /**
     * Set checksum opt.
     */
    public B checksumOpt(@Nonnull final ChecksumOpt chksumOpt) {
        Preconditions.checkNotNull(chksumOpt);
        checksumOpt = chksumOpt;
        return getThisBuilder();
    }

    /**
     * Set optional Builder parameter.
     */
    public B opt(@Nonnull final String key, @Nonnull final String value) {
        mandatoryKeys.remove(key);
        options.set(key, value);
        return getThisBuilder();
    }

    /**
     * Set optional boolean parameter for the Builder.
     *
     * @see #opt(String, String)
     */
    public B opt(@Nonnull final String key, boolean value) {
        mandatoryKeys.remove(key);
        options.setBoolean(key, value);
        return getThisBuilder();
    }

    /**
     * Set optional int parameter for the Builder.
     *
     * @see #opt(String, String)
     */
    public B opt(@Nonnull final String key, int value) {
        mandatoryKeys.remove(key);
        options.setInt(key, value);
        return getThisBuilder();
    }

    /**
     * Set optional float parameter for the Builder.
     *
     * @see #opt(String, String)
     */
    public B opt(@Nonnull final String key, float value) {
        mandatoryKeys.remove(key);
        options.setFloat(key, value);
        return getThisBuilder();
    }

    /**
     * Set optional double parameter for the Builder.
     *
     * @see #opt(String, String)
     */
    public B opt(@Nonnull final String key, double value) {
        mandatoryKeys.remove(key);
        options.setDouble(key, value);
        return getThisBuilder();
    }

    /**
     * Set an array of string values as optional parameter for the Builder.
     *
     * @see #opt(String, String)
     */
    public B opt(@Nonnull final String key, @Nonnull final String... values) {
        mandatoryKeys.remove(key);
        options.setStrings(key, values);
        return getThisBuilder();
    }

    /**
     * Set mandatory option to the Builder.
     *
     * If the option is not supported or unavailable on the {@link FileSystem},
     * the client should expect {@link #build()} throws IllegalArgumentException.
     */
    public B must(@Nonnull final String key, @Nonnull final String value) {
        mandatoryKeys.add(key);
        options.set(key, value);
        return getThisBuilder();
    }

    /**
     * Set mandatory boolean option.
     *
     * @see #must(String, String)
     */
    public B must(@Nonnull final String key, boolean value) {
        mandatoryKeys.add(key);
        options.setBoolean(key, value);
        return getThisBuilder();
    }

    /**
     * Set mandatory int option.
     *
     * @see #must(String, String)
     */
    public B must(@Nonnull final String key, int value) {
        mandatoryKeys.add(key);
        options.setInt(key, value);
        return getThisBuilder();
    }

    /**
     * Set mandatory float option.
     *
     * @see #must(String, String)
     */
    public B must(@Nonnull final String key, float value) {
        mandatoryKeys.add(key);
        options.setFloat(key, value);
        return getThisBuilder();
    }

    /**
     * Set mandatory double option.
     *
     * @see #must(String, String)
     */
    public B must(@Nonnull final String key, double value) {
        mandatoryKeys.add(key);
        options.setDouble(key, value);
        return getThisBuilder();
    }

    /**
     * Set a string array as mandatory option.
     *
     * @see #must(String, String)
     */
    public B must(@Nonnull final String key, @Nonnull final String... values) {
        mandatoryKeys.add(key);
        options.setStrings(key, values);
        return getThisBuilder();
    }

    protected Configuration getOptions() {
        return options;
    }

    /**
     * Get all the keys that are set as mandatory keys.
     */
    @VisibleForTesting
    protected Set<String> getMandatoryKeys() {
        return Collections.unmodifiableSet(mandatoryKeys);
    }

    /**
     * Create the FSDataOutputStream to write on the file system.
     *
     * @throws IllegalArgumentException if the parameters are not valid.
     * @throws IOException on errors when file system creates or appends the file.
     */
    public abstract S build() throws IllegalArgumentException, IOException;
}