/*--- formatted by Jindent 2.1, (www.c-lab.de/~jindent) ---*/
/**
* ***************************************************************
* The LEAP libraries, when combined with certain JADE platform components,
* provide a run-time environment for enabling FIPA agents to execute on
* lightweight devices running Java. LEAP and JADE teams have jointly
* designed the API for ease of integration and hence to take advantage
* of these dual developments and extensions so that users only see
* one development platform and a
* single homogeneous set of APIs. Enabling deployment to a wide range of
* devices whilst still having access to the full development
* environment and functionalities that JADE provides.
* Copyright (C) 2001 Motorola.
*
* GNU Lesser General Public License
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation,
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* **************************************************************
*/
package jade.imtp.leap.JICP;
import java.io.*;
import jade.util.Logger;
/**
* This class is the JICP data packet representation along
* with methods for reading from and writing to dataXXputStreams.
* @author Ronnie Taib - Motorola
* @author Steffen Rusitschka - Siemens AG
*/
public class JICPPacket {
public static final int MAX_SIZE = 1000000;
/**
* The type of data included in the packet
*/
private byte type;
/**
* Bit encoded information about the content of the packet:
*/
private byte info;
/**
* An optional identifier for the session this packet belongs to
*/
private byte sessionID = -1;
/**
* An optional field indicating the actual recipient for this JICPPacket.
* - A JICPServer receiving a JICPPacket from a remote container
* interprets this field as the ID of a local Mediator.
* - A Mediator receiving a JICPPacket from its mediated container
* interprets this field as the serialized transport address of
* final destination to forward the packet.
*/
private String recipientID;
/**
* The payload data itself, as a byte array
*/
private byte[] data;
/**
* Empty constructor
*/
private JICPPacket() {
}
/**
* Constructor.
* @param type The type of data included in the packet
* @param data The data itself, as a byte array.
*/
public JICPPacket(byte type, byte info, byte[] data) {
init(type, info, null, data);
}
/**
* Constructor used to set the recipientID.
* @param type The type of data included in the packet
* @param data The data itself, as a byte array.
*/
public JICPPacket(byte type, byte info, String recipientID, byte[] data) {
init(type, info, recipientID, data);
}
/**
* constructs a JICPPacket of type JICPProtocol.ERROR_TYPE and sets the
* data to the string representation of the exception.
*/
public JICPPacket(String explanation, Exception e) {
if (e != null) {
explanation = explanation+": "+e.getClass().getName()+"#"+e.getMessage();
}
init(JICPProtocol.ERROR_TYPE, JICPProtocol.DEFAULT_INFO, null, explanation.getBytes());
}
/**
*/
private void init(byte t, byte i, String id, byte[] d) {
type = t;
info = i;
sessionID = -1;
data = d;
setRecipientID(id);
if (data != null) {
info |= JICPProtocol.DATA_PRESENT_INFO;
//if ((info & JICPProtocol.COMPRESSED_INFO) != 0) {
// data = JICPCompressor.compress(data);
//}
}
}
/**
* @return The type of data included in the packet.
*/
public byte getType() {
return type;
}
/**
* @return the info field of this packet
*/
public byte getInfo() {
return info;
}
/**
* @return The sessionID of this packet.
*/
public byte getSessionID() {
return sessionID;
}
/**
* Set the sessionID of this packet and adjust the info field
* accordingly.
*/
public void setSessionID(byte id) {
sessionID = id;
if (sessionID >= 0) {
info |= JICPProtocol.SESSION_ID_PRESENT_INFO;
}
else {
info &= (~JICPProtocol.SESSION_ID_PRESENT_INFO);
}
}
/**
* @return The recipientID of this packet.
*/
public String getRecipientID() {
return recipientID;
}
/**
* Set the recipientID of this packet and adjust the info field
* accordingly.
*/
public void setRecipientID(String id) {
recipientID = id;
if (recipientID != null) {
info |= JICPProtocol.RECIPIENT_ID_PRESENT_INFO;
}
else {
info &= (~JICPProtocol.RECIPIENT_ID_PRESENT_INFO);
}
}
/**
* Set the TERMINATED_INFO flag in the info field.
*/
public void setTerminatedInfo(boolean set) {
if (set) {
info |= JICPProtocol.TERMINATED_INFO;
}
else {
info &= (~JICPProtocol.TERMINATED_INFO);
}
}
/**
* @return The actual data included in the packet, as a byte array.
*/
public byte[] getData() {
//if (data != null && data.length != 0) {
// return (info & JICPProtocol.COMPRESSED_INFO) != 0 ? JICPCompressor.decompress(data) : data;
//}
//else {
return data;
//}
}
/**
* Writes the packet into the provided <code>OutputStream</code>.
* The packet is serialized in an internal representation, so the
* data should be retrieved and deserialized with the
* <code>readFrom()</code> static method below. The output stream is flushed
* but not opened nor closed by this method.
*
* @param out The <code>OutputStream</code> to write the data in
* @exception May send a large bunch of exceptions, mainly in the IO
* package.
*/
public int writeTo(OutputStream out) throws IOException {
int cnt = 2;
// Write the packet type
out.write(type);
// Write the packet info
out.write(info);
// Write the session ID if present
if ((info & JICPProtocol.SESSION_ID_PRESENT_INFO) != 0) {
out.write(sessionID);
cnt++;
}
// Write recipient ID only if != null
if ((info & JICPProtocol.RECIPIENT_ID_PRESENT_INFO) != 0) {
out.write(recipientID.length());
out.write(recipientID.getBytes());
cnt += (1 + recipientID.length());
}
// Write data only if != null
if (data != null) {
// Size
int size = data.length;
out.write(size);
out.write(size >> 8);
out.write(size >> 16);
out.write(size >> 24);
cnt += 4;
// Payload
if (size > 0) {
out.write(data, 0, size);
cnt += size;
}
}
// DEBUG
//System.out.println(getLength()+" bytes written");
return cnt;
}
/**
* This static method reads from a given
* <code>DataInputStream</code> and returns the JICPPacket that
* it reads. The input stream is not opened nor closed by this method.
*
* @param in The <code>InputStream</code> to read from
* @exception May send a large bunch of exceptions, mainly in the IO
* package.
*/
public static JICPPacket readFrom(InputStream in) throws IOException {
JICPPacket p = new JICPPacket();
// Read packet type
p.type = read(in);
// Read the packet info
p.info = read(in);
// Read session ID if present
if ((p.info & JICPProtocol.SESSION_ID_PRESENT_INFO) != 0) {
p.sessionID = read(in);
}
// Read recipient ID if present
if ((p.info & JICPProtocol.RECIPIENT_ID_PRESENT_INFO) != 0) {
int size = (read(in) & 0x000000ff);
byte[] bb = new byte[size];
in.read(bb, 0, size);
p.recipientID = new String(bb);
}
// Read data if present
if ((p.info & JICPProtocol.DATA_PRESENT_INFO) != 0) {
int b1 = read(in);
int b2 = read(in);
int size = ((b2 << 8) & 0x0000ff00) | (b1 & 0x000000ff);
int b3 = read(in);
int b4 = read(in);
size |= ((b4 << 24) & 0xff000000) | ((b3 << 16) & 0x00ff0000);
if (size == 0) {
p.data = new byte[0];
}
else {
// Read the actual data
p.data = new byte[size];
int cnt = 0;
int n;
do {
n = in.read(p.data, cnt, size-cnt);
if (n == -1) {
throw new EOFException("EOF reading packet data");
}
cnt += n;
}
while (cnt < size);
}
//Logger.println("JICPPacket read. Type:"+p.type+" Info:"+p.info+" RID:"+p.recipientID+" Data-length:"+(p.data != null ? p.data.length : 0));
}
// DEBUG
//System.out.println(p.getLength()+" bytes read");
return p;
}
private static final byte read(InputStream in) throws IOException {
int i = in.read();
if (i == -1) {
throw new EOFException("EOF reading packet header");
}
return (byte) i;
}
public int getLength() {
int cnt = 2;
if ((info & JICPProtocol.SESSION_ID_PRESENT_INFO) != 0) {
cnt++;
}
if ((info & JICPProtocol.RECIPIENT_ID_PRESENT_INFO) != 0) {
cnt += (1 + recipientID.getBytes().length);
}
if ((info & JICPProtocol.DATA_PRESENT_INFO) != 0) {
cnt += (4 + data.length);
}
return cnt;
}
}