    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      https://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.io.channels;
    019
    020import java.io.IOException;
    021import java.nio.ByteBuffer;
    022import java.nio.MappedByteBuffer;
    023import java.nio.channels.Channel;
    024import java.nio.channels.FileChannel;
    025import java.nio.channels.FileLock;
    026import java.nio.channels.ReadableByteChannel;
    027import java.nio.channels.WritableByteChannel;
    028import java.util.Objects;
    029
    030import org.apache.commons.io.build.AbstractStreamBuilder;
    031
    032/**
    033 * Filters a {@link FileChannel}.
    034 * <p>
    035 * A {@code FilterFileChannel} wraps some other channel, which it uses as its basic source of data, possibly transforming the data along the way or providing
    036 * additional functionality. The class {@code FilterFileChannel} itself simply overrides methods of {@code FileChannel} with versions that pass all requests to
    037 * the wrapped channel. Subclasses of {@code FilterFileChannel} may of course override any methods declared or inherited by {@code FilterFileChannel}, and may
    038 * also provide additional fields and methods.
    039 * </p>
    040 * <p>
    041 * You construct s simple instance with the {@link FilterFileChannel#FilterFileChannel(FileChannel) channel constructor} and more advanced instances through the
    042 * {@link Builder}.
    043 * </p>
    044 *
    045 * @since 2.22.0
    046 */
    047public class FilterFileChannel extends FileChannel {
    048
    049    /**
    050     * Builds instances of {@link FilterFileChannel} for subclasses.
    051     *
    052     * @param <F> The {@link FilterFileChannel} type.
    053     * @param <C> The {@link Channel} type wrapped by the FilterChannel.
    054     * @param <B> The builder type.
    055     */
    056    public abstract static class AbstractBuilder<F extends FilterFileChannel, C extends FileChannel, B extends AbstractBuilder<F, C, B>>
    057            extends AbstractStreamBuilder<F, AbstractBuilder<F, C, B>> {
    058
    059        /**
    060         * Constructs instance for subclasses.
    061         */
    062        protected AbstractBuilder() {
    063            // empty
    064        }
    065    }
    066
    067    /**
    068     * Builds instances of {@link FilterFileChannel}.
    069     */
    070    public static class Builder extends AbstractBuilder<FilterFileChannel, FileChannel, Builder> {
    071
    072        /**
    073         * Builds instances of {@link FilterChannel}.
    074         */
    075        protected Builder() {
    076            // empty
    077        }
    078
    079        @Override
    080        public FilterFileChannel get() throws IOException {
    081            return new FilterFileChannel(this);
    082        }
    083    }
    084
    085    /**
    086     * Creates a new {@link Builder}.
    087     *
    088     * @return a new {@link Builder}.
    089     */
    090    public static Builder forFilterFileChannel() {
    091        return new Builder();
    092    }
    093
    094    final FileChannel fileChannel;
    095
    096    private FilterFileChannel(final Builder builder) throws IOException {
    097        this.fileChannel = builder.getChannel(FileChannel.class);
    098    }
    099
    100    /**
    101     * Constructs a new instance.
    102     *
    103     * @param fileChannel the file channel to wrap.
    104     */
    105    public FilterFileChannel(final FileChannel fileChannel) {
    106        this.fileChannel = Objects.requireNonNull(fileChannel, "fileChannel");
    107    }
    108
    109    @Override
    110    public boolean equals(final Object o) {
    111        return fileChannel.equals(o);
    112    }
    113
    114    @Override
    115    public void force(final boolean metaData) throws IOException {
    116        fileChannel.force(metaData);
    117    }
    118
    119    @Override
    120    public int hashCode() {
    121        return fileChannel.hashCode();
    122    }
    123
    124    @Override
    125    protected void implCloseChannel() throws IOException {
    126        fileChannel.close();
    127    }
    128
    129    @Override
    130    public FileLock lock(final long position, final long size, final boolean shared) throws IOException {
    131        return fileChannel.lock(position, size, shared);
    132    }
    133
    134    @Override
    135    public MappedByteBuffer map(final MapMode mode, final long position, final long size) throws IOException {
    136        return fileChannel.map(mode, position, size);
    137    }
    138
    139    @Override
    140    public long position() throws IOException {
    141        return fileChannel.position();
    142    }
    143
    144    @Override
    145    public FileChannel position(final long newPosition) throws IOException {
    146        return fileChannel.position(newPosition);
    147    }
    148
    149    @Override
    150    public int read(final ByteBuffer dst) throws IOException {
    151        return fileChannel.read(dst);
    152    }
    153
    154    @Override
    155    public int read(final ByteBuffer dst, final long position) throws IOException {
    156        return fileChannel.read(dst, position);
    157    }
    158
    159    @Override
    160    public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException {
    161        return fileChannel.read(dsts, offset, length);
    162    }
    163
    164    @Override
    165    public long size() throws IOException {
    166        return fileChannel.size();
    167    }
    168
    169    @Override
    170    public String toString() {
    171        return fileChannel.toString();
    172    }
    173
    174    @Override
    175    public long transferFrom(final ReadableByteChannel src, final long position, final long count) throws IOException {
    176        return fileChannel.transferFrom(src, position, count);
    177    }
    178
    179    @Override
    180    public long transferTo(final long position, final long count, final WritableByteChannel target) throws IOException {
    181        return fileChannel.transferTo(position, count, target);
    182    }
    183
    184    @Override
    185    public FileChannel truncate(final long size) throws IOException {
    186        return fileChannel.truncate(size);
    187    }
    188
    189    @Override
    190    public FileLock tryLock(final long position, final long size, final boolean shared) throws IOException {
    191        return fileChannel.tryLock(position, size, shared);
    192    }
    193
    194    /**
    195     * Unwraps this instance by returning the underlying {@link FileChannel}.
    196     * <p>
    197     * Use with caution.
    198     * </p>
    199     *
    200     * @return the underlying {@link FileChannel}.
    201     */
    202    public FileChannel unwrap() {
    203        return fileChannel;
    204    }
    205
    206    @Override
    207    public int write(final ByteBuffer src) throws IOException {
    208        return fileChannel.write(src);
    209    }
    210
    211    @Override
    212    public int write(final ByteBuffer src, final long position) throws IOException {
    213        return fileChannel.write(src, position);
    214    }
    215
    216    @Override
    217    public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException {
    218        return fileChannel.write(srcs, offset, length);
    219    }
    220}