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}