package org.jacorb.orb.miop;
import java.io.ByteArrayOutputStream;
import org.jacorb.config.Configurable;
import org.jacorb.config.Configuration;
import org.jacorb.config.ConfigurationException;
import org.omg.MIOP.PacketHeader_1_0;
/**
* A collection of fragments of a giop message.
*
* @author Alysson Neves Bessani
* @version 1.0
* @see ServerMIOPConnection
*/
public class FragmentedMessage implements Configurable
{
public static final int NUMBER_OF_FRAGMENTS = 4;
public static final int FRAGMENT_INCREMENT = 2;
private final long creationTime = System.currentTimeMillis ();
private int numberOfFragments = NUMBER_OF_FRAGMENTS;
private byte[][] fragments;
private int lastPacketArrived = -1;
private int maxPacketArrived = -1;
private int packetsReceived = 0;
private boolean end_flag_dependent = false;
private boolean end_flag_received = false;
/** message's configuration parameters */
private int completionTimeout;
private short packetDataMaxSize;
/**
* Tests if this message can be discarded or not.
*
* @return true if it can be discarded.
*/
boolean canBeDiscarded ()
{
return (end_flag_received && !isComplete ())
|| (System.currentTimeMillis () - creationTime > numberOfFragments * completionTimeout);
}
/**
* If all the fragments arrived then the GIOP message can be build. Only called
* from ServerMIOPConnection is message.isComplete.
*
* @return byte[] of a GIOP message.
*/
byte[] buildMessage ()
{
ByteArrayOutputStream out =
new ByteArrayOutputStream (numberOfFragments * packetDataMaxSize);
for (int i = 0; i <= maxPacketArrived; i++)
{
out.write (fragments[i], 0, fragments[i].length);
}
return out.toByteArray ();
}
/**
* It verifies if there is some available position on the packet buffer.
* Even if the last fragment arrived, there can be some packets that were
* not delivered yet due to the non FIFO guarantees (of UDP),
* So, this method verify if all fragments of the message were received.
*
* @return true if it contains all message fragments.
*/
boolean isComplete ()
{
if (end_flag_dependent)
{
if (end_flag_received)
{
for (int i = 0; i < maxPacketArrived; i++)
{
if (fragments[i] == null)
{
return false;
}
}
return true;
}
else
{
return false;
}
}
else
{
return packetsReceived == numberOfFragments;
}
}
/**
* Adds a fragment.
*
* @param header the fragment header.
* @param fragment the fragment data.
*/
synchronized void addFragment (PacketHeader_1_0 header, byte[] fragment)
{
if (fragments == null)
{
// Run only on arrival of the first package
// Get the number of packets that must wait
// If this number is zero, I have to wait for the flag
if (header.number_of_packets > 0)
{
numberOfFragments = header.number_of_packets;
}
else
{
end_flag_dependent = true;
}
// create the array of fragments
fragments = new byte[numberOfFragments][];
}
// put the fragment in the proper position
lastPacketArrived = header.packet_number;
if (lastPacketArrived > maxPacketArrived)
{
maxPacketArrived = lastPacketArrived;
if (maxPacketArrived > fragments.length)
{
// the array beyond its size ... we will increase them.
// Please note that this will never happen if the field
// number_of_packets were properly completed
byte[] oldFragments[] = fragments;
numberOfFragments += FRAGMENT_INCREMENT;
fragments = new byte[numberOfFragments][];
System.arraycopy (oldFragments, 0, fragments, 0, fragments.length);
}
}
// Insert here
if (fragments[lastPacketArrived] == null)
{
fragments[lastPacketArrived] = fragment;
packetsReceived++;
}
if (end_flag_dependent)
{
end_flag_received = ((header.flags & MulticastUtil.STOP_FLAG) == MulticastUtil.STOP_FLAG);
}
}
public void configure (Configuration config) throws ConfigurationException
{
completionTimeout = config.getAttributeAsInteger ("jacorb.miop.message_completion_timeout",
MulticastUtil.MESSAGE_COMPLETION_TIMEOUT);
int packetMax = config.getAttributeAsInteger ("jacorb.miop.packet_max_size",
MulticastUtil.PACKET_MAX_SIZE);
packetDataMaxSize = (short)(packetMax - MulticastUtil.PACKET_DATA_MAX_SIZE);
}
}