001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.impl.nio.codecs;
029
030import java.io.IOException;
031import java.nio.ByteBuffer;
032import java.nio.channels.ReadableByteChannel;
033
034import org.apache.http.impl.io.HttpTransportMetricsImpl;
035import org.apache.http.nio.ContentDecoder;
036import org.apache.http.nio.reactor.SessionInputBuffer;
037import org.apache.http.util.Args;
038
039/**
040 * Abstract {@link ContentDecoder} that serves as a base for all content
041 * decoder implementations.
042 *
043 * @since 4.0
044 */
045public abstract class AbstractContentDecoder implements ContentDecoder {
046
047    protected final ReadableByteChannel channel;
048    protected final SessionInputBuffer buffer;
049    protected final HttpTransportMetricsImpl metrics;
050
051    protected boolean completed;
052
053    /**
054     * Creates an instance of this class.
055     *
056     * @param channel the source channel.
057     * @param buffer the session input buffer that can be used to store
058     *    session data for intermediate processing.
059     * @param metrics Transport metrics of the underlying HTTP transport.
060     */
061    public AbstractContentDecoder(
062            final ReadableByteChannel channel,
063            final SessionInputBuffer buffer,
064            final HttpTransportMetricsImpl metrics) {
065        super();
066        Args.notNull(channel, "Channel");
067        Args.notNull(buffer, "Session input buffer");
068        Args.notNull(metrics, "Transport metrics");
069        this.buffer = buffer;
070        this.channel = channel;
071        this.metrics = metrics;
072    }
073
074    @Override
075    public boolean isCompleted() {
076        return this.completed;
077    }
078
079    /**
080     * Reads from the channel to the destination.
081     *
082     * @param dst destination.
083     * @return number of bytes transferred.
084     *
085     * @since 4.3
086     */
087    protected int readFromChannel(final ByteBuffer dst) throws IOException {
088        final int bytesRead = this.channel.read(dst);
089        if (bytesRead > 0) {
090            this.metrics.incrementBytesTransferred(bytesRead);
091        }
092        return bytesRead;
093    }
094
095    /**
096     * Reads from the channel to the session buffer.
097     * @return number of bytes transferred.
098     *
099     * @since 4.3
100     */
101    protected int fillBufferFromChannel() throws IOException {
102        final int bytesRead = this.buffer.fill(this.channel);
103        if (bytesRead > 0) {
104            this.metrics.incrementBytesTransferred(bytesRead);
105        }
106        return bytesRead;
107    }
108
109    /**
110     * Reads from the channel to the destination.
111     *
112     * @param dst destination.
113     * @param limit max number of bytes to transfer.
114     * @return number of bytes transferred.
115     *
116     * @since 4.3
117     */
118    protected int readFromChannel(final ByteBuffer dst, final int limit) throws IOException {
119        final int bytesRead;
120        if (dst.remaining() > limit) {
121            final int oldLimit = dst.limit();
122            final int newLimit = oldLimit - (dst.remaining() - limit);
123            dst.limit(newLimit);
124            bytesRead = this.channel.read(dst);
125            dst.limit(oldLimit);
126        } else {
127            bytesRead = this.channel.read(dst);
128        }
129        if (bytesRead > 0) {
130            this.metrics.incrementBytesTransferred(bytesRead);
131        }
132        return bytesRead;
133    }
134
135}