001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0-beta1/module-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java $
003: * $Revision: 613298 $
004: * $Date: 2008-01-18 23:09:22 +0100 (Fri, 18 Jan 2008) $
005: *
006: * ====================================================================
007: * Licensed to the Apache Software Foundation (ASF) under one
008: * or more contributor license agreements. See the NOTICE file
009: * distributed with this work for additional information
010: * regarding copyright ownership. The ASF licenses this file
011: * to you under the Apache License, Version 2.0 (the
012: * "License"); you may not use this file except in compliance
013: * with the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing,
018: * software distributed under the License is distributed on an
019: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020: * KIND, either express or implied. See the License for the
021: * specific language governing permissions and limitations
022: * under the License.
023: * ====================================================================
024: *
025: * This software consists of voluntary contributions made by many
026: * individuals on behalf of the Apache Software Foundation. For more
027: * information on the Apache Software Foundation, please see
028: * <http://www.apache.org/>.
029: *
030: */
031:
032: package org.apache.http.impl.nio.codecs;
033:
034: import java.io.IOException;
035: import java.nio.ByteBuffer;
036: import java.nio.channels.FileChannel;
037: import java.nio.channels.ReadableByteChannel;
038:
039: import org.apache.http.impl.io.HttpTransportMetricsImpl;
040: import org.apache.http.nio.FileContentDecoder;
041: import org.apache.http.nio.reactor.SessionInputBuffer;
042:
043: /**
044: * Content-Length delimited decoder implementation.
045: *
046: * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
047: * @author Andrea Selva
048: *
049: * @version $Revision: 613298 $
050: *
051: * @since 4.0
052: */
053: public class LengthDelimitedDecoder extends AbstractContentDecoder
054: implements FileContentDecoder {
055:
056: private final long contentLength;
057:
058: private long len;
059:
060: public LengthDelimitedDecoder(final ReadableByteChannel channel,
061: final SessionInputBuffer buffer,
062: final HttpTransportMetricsImpl metrics, long contentLength) {
063: super (channel, buffer, metrics);
064: if (contentLength < 0) {
065: throw new IllegalArgumentException(
066: "Content length may not be negative");
067: }
068: this .contentLength = contentLength;
069: }
070:
071: public int read(final ByteBuffer dst) throws IOException {
072: if (dst == null) {
073: throw new IllegalArgumentException(
074: "Byte buffer may not be null");
075: }
076: if (this .completed) {
077: return -1;
078: }
079: int lenRemaining = (int) (this .contentLength - this .len);
080:
081: int bytesRead;
082: if (this .buffer.hasData()) {
083: int maxLen = Math.min(lenRemaining, this .buffer.length());
084: bytesRead = this .buffer.read(dst, maxLen);
085: } else {
086: if (dst.remaining() > lenRemaining) {
087: int oldLimit = dst.limit();
088: int newLimit = oldLimit
089: - (dst.remaining() - lenRemaining);
090: dst.limit(newLimit);
091: bytesRead = this .channel.read(dst);
092: dst.limit(oldLimit);
093: } else {
094: bytesRead = this .channel.read(dst);
095: }
096: if (bytesRead > 0) {
097: this .metrics.incrementBytesTransferred(bytesRead);
098: }
099: }
100: if (bytesRead == -1) {
101: this .completed = true;
102: return -1;
103: }
104: this .len += bytesRead;
105: if (this .len >= this .contentLength) {
106: this .completed = true;
107: }
108: return bytesRead;
109: }
110:
111: public long transfer(final FileChannel dst, long position,
112: long count) throws IOException {
113:
114: if (dst == null) {
115: return 0;
116: }
117: if (this .completed) {
118: return -1;
119: }
120:
121: int lenRemaining = (int) (this .contentLength - this .len);
122:
123: long bytesRead;
124: if (this .buffer.hasData()) {
125: int maxLen = Math.min(lenRemaining, this .buffer.length());
126: bytesRead = this .buffer.read(dst, maxLen);
127: } else {
128: if (count > lenRemaining) {
129: count = lenRemaining;
130: }
131: if (this .channel.isOpen()) {
132: bytesRead = dst.transferFrom(this .channel, position,
133: count);
134: } else {
135: bytesRead = -1;
136: }
137: if (bytesRead > 0) {
138: this .metrics.incrementBytesTransferred(bytesRead);
139: }
140: }
141: if (bytesRead == -1) {
142: this .completed = true;
143: return -1;
144: }
145: this .len += bytesRead;
146: if (this .len >= this .contentLength) {
147: this .completed = true;
148: }
149: return bytesRead;
150: }
151:
152: @Override
153: public String toString() {
154: StringBuffer buffer = new StringBuffer();
155: buffer.append("[content length: ");
156: buffer.append(this .contentLength);
157: buffer.append("; pos: ");
158: buffer.append(this .len);
159: buffer.append("; completed: ");
160: buffer.append(this .completed);
161: buffer.append("]");
162: return buffer.toString();
163: }
164: }
|