All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xnio.conduits.BufferedStreamSinkConduit Maven / Gradle / Ivy

There is a newer version: 3.8.16.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 *
 * Copyright 2013 Red Hat, Inc. and/or its affiliates.
 *
 * 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 org.xnio.conduits;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import org.xnio.Buffers;
import org.xnio.Pooled;
import org.xnio.channels.StreamSourceChannel;

/**
 * A stream sink conduit that buffers output data.
 *
 * @author David M. Lloyd
 */
public final class BufferedStreamSinkConduit extends AbstractStreamSinkConduit {

    private final Pooled pooledBuffer;
    private boolean terminate;

    /**
     * Construct a new instance.
     *
     * @param next the delegate conduit to set
     * @param pooledBuffer the pooled buffer to use
     */
    public BufferedStreamSinkConduit(final StreamSinkConduit next, final Pooled pooledBuffer) {
        super(next);
        this.pooledBuffer = pooledBuffer;
    }

    public long transferFrom(final FileChannel src, final long position, final long count) throws IOException {
        return flushLocal() ? super.transferFrom(src, position, count) : 0L;
    }

    public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException {
        // todo: optimize to include our buffer in the copies
        if (flushLocal()) {
            return super.transferFrom(source, count, throughBuffer);
        } else {
            throughBuffer.limit(0);
            return 0L;
        }
    }

    public int write(final ByteBuffer src) throws IOException {
        try {
            final ByteBuffer buffer = pooledBuffer.getResource();
            final int pos = buffer.position();
            final int lim = buffer.limit();
            final int srcRem = src.remaining();
            final int ourRem = lim - pos;
            if (srcRem < ourRem) {
                buffer.put(src);
                return srcRem;
            } else if (buffer.position() == 0) {
                final int res = super.write(src);
                if (srcRem > res) {
                    final int cnt = Buffers.copy(buffer, src);
                    return res + cnt;
                } else {
                    return res;
                }
            } else {
                buffer.flip();
                try {
                    super.write(new ByteBuffer[] { buffer, src }, 0, 2);
                } finally {
                    buffer.compact();
                }
                if (src.hasRemaining()) {
                    Buffers.copy(buffer, src);
                }
                return srcRem - src.remaining();
            }
        } catch (IllegalStateException ignored) {
            throw new ClosedChannelException();
        }
    }

    public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException {
        if (len == 0) {
            return 0L;
        } else if (len == 1) {
            return write(srcs[offs]);
        } else try {
            final ByteBuffer buffer = pooledBuffer.getResource();
            final int pos = buffer.position();
            final int lim = buffer.limit();
            final long srcRem = Buffers.remaining(srcs, offs, len);
            final int ourRem = lim - pos;
            if (srcRem < ourRem) {
                for (int i = 0; i < len; i++) {
                    buffer.put(srcs[i]);
                }
                return srcRem;
            } else if (buffer.position() == 0) {
                final long res = super.write(srcs, offs, len);
                if (srcRem > res) {
                    final int cnt = Buffers.copy(buffer, srcs, offs, len);
                    return res + cnt;
                } else {
                    return res;
                }
            } else {
                buffer.flip();
                try {
                    final ByteBuffer[] buffers;
                    if (offs > 0) {
                        buffers = Arrays.copyOfRange(srcs, offs - 1, offs + len);
                    } else {
                        buffers = new ByteBuffer[len + 1];
                        System.arraycopy(srcs, offs, buffers, 1, len);
                    }
                    buffers[0] = buffer;
                    super.write(buffers, 0, buffers.length);
                } finally {
                    buffer.compact();
                }
                Buffers.copy(buffer, srcs, offs, len);
                return srcRem - Buffers.remaining(srcs, offs, len);
            }
        } catch (IllegalStateException ignored) {
            throw new ClosedChannelException();
        }
    }

    private boolean flushLocal() throws IOException {
        try {
            final ByteBuffer buffer = pooledBuffer.getResource();
            if (buffer.position() > 0) {
                buffer.flip();
                try {
                    for (;;) {
                        super.write(buffer);
                        if (! buffer.hasRemaining()) {
                            if (terminate) {
                                pooledBuffer.free();
                            }
                            return true;
                        }
                    }
                } finally {
                    buffer.compact();
                }
            } else {
                return true;
            }
        } catch (IllegalStateException ignored) {
            return true;
        }
    }

    @Override
    public int writeFinal(ByteBuffer src) throws IOException {
        //todo: non-naive implementations of this
        return Conduits.writeFinalBasic(this, src);
    }

    @Override
    public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException {
        //todo: non-naive implementations of this
        return Conduits.writeFinalBasic(this, srcs, offset, length);
    }

    public boolean flush() throws IOException {
        return flushLocal() && super.flush();
    }

    public void truncateWrites() throws IOException {
        pooledBuffer.free();
        super.truncateWrites();
    }

    public void terminateWrites() throws IOException {
        terminate = true;
        super.terminateWrites();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy