/*
* PacketBuilder.java February 2007
*
* Copyright (C) 2007, Niall Gallagher <niallg@users.sf.net>
*
* 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.simpleframework.transport;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* The <code>PacketBuilder</code> object is used to accumulate octets from
* provided byte buffers. This will create <code>Packet</code> objects which
* encapsulate all of the information associated with the byte buffer, and can
* tell the transport how the buffer should be written. Packets can be either
* references or copies.
*
* @author Niall Gallagher
*/
class PacketBuilder {
/**
* This is packet allocator that is used to create packets.
*/
private PacketAllocator allocator;
/**
* This is the packet within the packet builder being built.
*/
private Packet packet;
/**
* This is the size of the packets that will be created.
*/
private int size;
/**
* Constructor for the <code>PacketBuilder</code> object. This is used to
* create a builder that can be used to aggregate multiple byte buffers in
* to a single packet object. This will limit the number of packets that can
* be created by this builder.
*/
public PacketBuilder() {
this(3);
}
/**
* Constructor for the <code>PacketBuilder</code> object. This is used to
* create a builder that can be used to aggregate multiple byte buffers in
* to a single packet object. This will limit the number of packets that can
* be created by this builder.
*
* @param queue
* this is a limit to the number of packets built
*/
public PacketBuilder(int queue) {
this(queue, 4096);
}
/**
* Constructor for the <code>PacketBuilder</code> object. This is used to
* create a builder that can be used to aggregate multiple byte buffers in
* to a single packet object. This will limit the number of packets that can
* be created by this builder.
*
* @param queue
* this is a limit to the number of packets built
* @param size
* this is the size of the packets to be built
*/
public PacketBuilder(int queue, int size) {
this.allocator = new PacketAllocator(queue, size);
this.size = size;
}
/**
* This is used to acquire the current packet that has been built within the
* builder. When the packet is returned from this method another packet is
* allocated for the next build.
*
* @return this returns the current packet within the builder
*/
public Packet build() throws IOException {
Packet local = null;
if (this.packet != null) {
int length = this.packet.length();
if (length <= 0) {
this.packet.close();
} else {
local = this.packet;
}
this.packet = null;
}
return local;
}
/**
* This is used to build the a <code>Packet</code> within the builder using
* the provided buffer. The returned packet will contain the accumulated
* bytes from calls to the build method. If the previous packets are not
* closed this method will block until such time as the packet is closed.
*
* @param buffer
* this is the buffer to be added to the packet
*
* @return this returns the packet containing the bytes
*/
public Packet build(ByteBuffer buffer) throws IOException {
int ready = buffer.remaining();
if (this.packet != null) return this.build(buffer, this.packet);
if (ready > this.size) return this.allocator.allocate(buffer);
if (ready > 0) {
if (this.packet == null) {
this.packet = this.allocator.allocate();
}
return this.build(buffer, this.packet);
}
return null;
}
/**
* This is used to build the a <code>Packet</code> within the builder using
* the provided buffer. The returned packet will contain the accumulated
* bytes from calls to the build method. If the previous packets are not
* closed this method will block until such time as the packet is closed.
*
* @param buffer
* this is the buffer to be added to the packet
* @param packet
* this is the packet to add the buffer to
*
* @return this returns the packet containing the bytes
*/
private Packet build(ByteBuffer buffer, Packet packet) throws IOException {
int ready = buffer.remaining();
int length = packet.length();
int space = packet.space();
if (ready <= space) {
packet.append(buffer);
} else {
int capacity = buffer.capacity();
if (length == 0) return this.allocator.allocate(buffer);
if (space < capacity) {
if (space > 0) {
packet.append(buffer);
}
return this.build();
}
return this.allocator.allocate(buffer);
}
if (space == ready) return this.build();
return null;
}
}