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

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

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.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.FileChannel;
import java.util.concurrent.TimeUnit;
import org.xnio.Buffers;
import org.xnio.Pooled;
import org.xnio.channels.StreamSinkChannel;

/**
 * A stream source conduit which allows buffers to be "pushed back" to the head of the stream.
 *
 * @author David M. Lloyd
 */
public final class PushBackStreamSourceConduit extends AbstractStreamSourceConduit implements StreamSourceConduit {
    private StreamSourceConduit current = next;
    private boolean shutdown;

    /**
     * Construct a new instance.
     *
     * @param next the delegate conduit to set
     */
    public PushBackStreamSourceConduit(final StreamSourceConduit next) {
        super(next);
    }

    public void resumeReads() {
        current.resumeReads();
    }

    public int read(final ByteBuffer dst) throws IOException {
        return current.read(dst);
    }

    public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException {
        return current.read(dsts, offs, len);
    }

    public long transferTo(final long position, final long count, final FileChannel target) throws IOException {
        return current.transferTo(position, count, target);
    }

    public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException {
        return current.transferTo(count, throughBuffer, target);
    }

    public void awaitReadable() throws IOException {
        current.awaitReadable();
    }

    public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException {
        current.awaitReadable(time, timeUnit);
    }

    public void terminateReads() throws IOException {
        shutdown = true;
        current.terminateReads();
    }

    public void setReadReadyHandler(final ReadReadyHandler handler) {
        current.setReadReadyHandler(handler);
    }

    /**
     * Push a buffer back to the head of the stream.  Once the buffer data is consumed, it will
     * be released back to its original pool (if any).
     *
     * @param pooledBuffer the buffer to push back
     */
    public void pushBack(Pooled pooledBuffer) {
        if (pooledBuffer == null) {
            return;
        }
        if (shutdown || ! pooledBuffer.getResource().hasRemaining()) {
            pooledBuffer.free();
        } else {
            current = new BufferConduit(current, pooledBuffer);
        }
    }

    class BufferConduit extends AbstractStreamSourceConduit implements StreamSourceConduit {

        private final Pooled pooledBuffer;

        BufferConduit(final StreamSourceConduit next, final Pooled pooledBuffer) {
            super(next);
            this.pooledBuffer = pooledBuffer;
        }

        public void resumeReads() {
            next.wakeupReads();
        }

        public void terminateReads() throws IOException {
            try {
                super.terminateReads();
            } finally {
                if (pooledBuffer != null) {
                    pooledBuffer.free();
                }
                next.terminateReads();
            }
        }

        public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException {
            // readable
        }

        public void awaitReadable() throws IOException {
            // readable
        }

        public int read(final ByteBuffer dst) throws IOException {
            int cnt;
            if (! dst.hasRemaining()) {
                return 0;
            }
            final StreamSourceConduit next = this.next;
            try {
                final ByteBuffer src = pooledBuffer.getResource();
                cnt = Buffers.copy(dst, src);
                if (src.hasRemaining()) {
                    return cnt;
                }
                moveToNext();
                if (cnt > 0 && next == PushBackStreamSourceConduit.this.next) {
                    // don't hit the main channel until the user wants to
                    return cnt;
                }
            } catch (IllegalStateException ignored) {
                moveToNext();
                cnt = 0;
            }
            final int res = next.read(dst);
            return res > 0 ? res + cnt : cnt > 0 ? cnt : res;
        }

        public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException {
            long cnt;
            final StreamSourceConduit next = this.next;
            try {
                final ByteBuffer src = pooledBuffer.getResource();
                cnt = Buffers.copy(dsts, offs, len, src);
                if (src.hasRemaining()) {
                    return cnt;
                }
                moveToNext();
                if (cnt > 0L && next == PushBackStreamSourceConduit.this.next) {
                    // don't hit the main channel until the user wants to
                    return cnt;
                }
            } catch (IllegalStateException ignored) {
                moveToNext();
                cnt = 0;
            }
            final long res = next.read(dsts, offs, len);
            return res > 0 ? res + cnt : cnt > 0 ? cnt : res;
        }

        public long transferTo(long position, long count, final FileChannel target) throws IOException {
            long cnt;
            final ByteBuffer src;
            try {
                src = pooledBuffer.getResource();
                final int pos = src.position();
                final int rem = src.remaining();
                if (rem > count) try {
                    // partial empty of our buffer
                    src.limit(pos + (int) count);
                    return target.write(src, position);
                } finally {
                    src.limit(pos + rem);
                } else {
                    // full empty of our buffer
                    cnt = target.write(src, position);
                    if (cnt == rem) {
                        // we emptied our buffer
                        moveToNext();
                    } else {
                        return cnt;
                    }
                    position += cnt;
                    count -= cnt;
                }
            } catch (IllegalStateException ignored) {
                moveToNext();
                cnt = 0L;
            }
            return cnt + next.transferTo(position, count, target);
        }

        public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException {
            long cnt;
            final ByteBuffer src;
            try {
                src = pooledBuffer.getResource();
                final int pos = src.position();
                final int rem = src.remaining();
                if (rem > count) try {
                    // partial empty of our buffer
                    src.limit(pos + (int) count);
                    int res = target.write(src);
                    if(res == 0) {
                        //a bit yuck, but if we have filed to copy anything we need to transfer data into the throughbuffer
                        //this signals to the called that it was not the read that did not succeed, but the write
                        throughBuffer.clear();
                        Buffers.copy(throughBuffer, src);
                        throughBuffer.flip();
                    } else {
                        //make sure throughbuffer is empty
                        throughBuffer.clear();
                        throughBuffer.flip();
                    }
                    return res;
                } finally {
                    src.limit(pos + rem);
                } else {
                    // full empty of our buffer
                    cnt = target.write(src);
                    if (cnt == rem) {
                        // we emptied our buffer
                        moveToNext();
                    } else {
                        if (cnt == 0) {
                            //a bit yuck, but if we have filed to copy anything we need to transfer data into the throughbuffer
                            //this signals to the called that it was not the read that did not succeed, but the write
                            throughBuffer.clear();
                            Buffers.copy(throughBuffer, src);
                            throughBuffer.flip();
                        } else {
                            //make sure throughbuffer is empty
                            throughBuffer.clear();
                            throughBuffer.flip();
                        }
                        return cnt;
                    }
                }
            } catch (IllegalStateException ignored) {
                moveToNext();
                cnt = 0L;
            }
            final long res = next.transferTo(count - cnt, throughBuffer, target);
            return res > 0L ? cnt + res : cnt > 0L ? cnt : res;
        }

        private final void moveToNext() {
            current = next;
            pooledBuffer.free();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy