/** * *************************************************************** * JADE - Java Agent DEvelopment Framework is a framework to develop * multi-agent systems in compliance with the FIPA specifications. * Copyright (C) 2000 CSELT S.p.A. * * 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.content.lang.leap; import jade.content.lang.*; import jade.content.onto.*; import jade.content.abs.*; import jade.content.schema.ObjectSchema; import jade.util.leap.*; import java.util.Vector; import java.util.Date; import java.io.*; /** * Content language codec for the LEAP language * @author Federico Bergenti - Universita` di Parma */ public class LEAPCodec extends ByteArrayCodec { public static final String NAME = "LEAP"; private transient ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); private transient DataOutputStream outStream = new DataOutputStream(outBuffer); private transient Vector stringReferences = new Vector(); //#MIDP_EXCLUDE_BEGIN private void readObject(java.io.ObjectInputStream oin) throws java.io.IOException, ClassNotFoundException { oin.defaultReadObject(); outBuffer = new ByteArrayOutputStream(); outStream = new DataOutputStream(outBuffer); stringReferences = new Vector(); } //#MIDP_EXCLUDE_END // Types private static final byte PRIMITIVE = 0; private static final byte AGGREGATE = 1; private static final byte CONTENT_ELEMENT_LIST = 2; private static final byte OBJECT = 3; // Markers for structured types private static final byte ELEMENT = 4; private static final byte END = 5; // Primitive types private static final byte STRING = 6; private static final byte BOOLEAN = 7; private static final byte INTEGER = 8; private static final byte LONG = 9; private static final byte FLOAT = 10; private static final byte DOUBLE = 11; private static final byte DATE = 12; private static final byte BYTE_SEQUENCE = 13; // Modifiers private static final byte MODIFIER = (byte) 0x10; // Only bit five set to 1 private static final byte UNMODIFIER = (byte) 0xEF; // Only bit five cleared to 1 /* LEAP Language operators public static final String INSTANCEOF = "INSTANCEOF"; public static final String INSTANCEOF_ENTITY = "entity"; public static final String INSTANCEOF_TYPE = "type"; public static final String IOTA = "IOTA"; */ /** * Construct a LEAPCodec object i.e. a Codec for the LEAP language */ public LEAPCodec() { super(NAME); } /** * Encodes an abstract descriptor holding a content element * into a byte array. * @param content the content as an abstract descriptor. * @return the content as a byte array. * @throws CodecException */ public synchronized byte[] encode(AbsContentElement content) throws CodecException { try { outBuffer.reset(); stringReferences.removeAllElements(); write(outStream, content); return outBuffer.toByteArray(); } catch (Throwable t) { throw new CodecException("Error encoding content", t); } } /** * Encodes a content into a byte array. * @param ontology the ontology * @param content the content as an abstract descriptor. * @return the content as a byte array. * @throws CodecException */ public byte[] encode(Ontology ontology, AbsContentElement content) throws CodecException { return encode(content); } /** * Decodes the content to an abstract descriptor. * @param content the content as a byte array. * @return the content as an abstract description. * @throws CodecException */ public AbsContentElement decode(byte[] content) throws CodecException { throw new CodecException("Not supported"); } /** * Decodes the content to an abstract description. * @param ontology the ontology. * @param content the content as a byte array. * @return the content as an abstract description. * @throws CodecException */ public synchronized AbsContentElement decode(Ontology ontology, byte[] content) throws CodecException { if (content.length == 0) { return null; } try { ByteArrayInputStream inpBuffer = new ByteArrayInputStream(content); DataInputStream inpStream = new DataInputStream(inpBuffer); stringReferences.removeAllElements(); AbsObject obj = read(inpStream, ontology); inpStream.close(); return (AbsContentElement) obj; } catch (Throwable t) { throw new CodecException("Error decoding content", t); } } /** * Synchronized so that it can possibly be executed by different threads */ private void write(DataOutputStream stream, AbsObject abs) throws Throwable { // PRIMITIVE if (abs instanceof AbsPrimitive) { //stream.writeByte(PRIMITIVE); Object obj = ((AbsPrimitive) abs).getObject(); if (obj instanceof String) { writeString(stream, STRING, (String) obj); } else if (obj instanceof Boolean) { stream.writeByte(BOOLEAN); stream.writeBoolean(((Boolean) obj).booleanValue()); } else if (obj instanceof Integer) { stream.writeByte(INTEGER); stream.writeInt(((Integer) obj).intValue()); } else if (obj instanceof Long) { stream.writeByte(LONG); stream.writeLong(((Long) obj).longValue()); } //#MIDP_EXCLUDE_BEGIN else if (obj instanceof Float) { stream.writeByte(FLOAT); stream.writeFloat(((Float) obj).floatValue()); } else if (obj instanceof Double) { stream.writeByte(DOUBLE); stream.writeDouble(((Double) obj).doubleValue()); } //#MIDP_EXCLUDE_END else if (obj instanceof Date) { stream.writeByte(DATE); stream.writeLong(((Date) obj).getTime()); } else if (obj instanceof byte[]) { stream.writeByte(BYTE_SEQUENCE); byte[] b = (byte[]) obj; stream.writeInt(b.length); stream.write(b, 0, b.length); } return; } // AGGREGATE if (abs instanceof AbsAggregate) { writeString(stream, AGGREGATE, abs.getTypeName()); AbsAggregate aggregate = (AbsAggregate) abs; for (int i = 0; i < aggregate.size(); i++) { stream.writeByte(ELEMENT); write(stream, aggregate.get(i)); } stream.writeByte(END); return; } // CONTENT_ELEMENT_LIST if (abs instanceof AbsContentElementList) { stream.writeByte(CONTENT_ELEMENT_LIST); AbsContentElementList acel = (AbsContentElementList) abs; for (int i = 0; i < acel.size(); i++) { stream.writeByte(ELEMENT); write(stream, acel.get(i)); } stream.writeByte(END); return; } // If we get here it must be a complex OBJECT writeString(stream, OBJECT, abs.getTypeName()); String[] names = abs.getNames(); for (int i = 0; i < abs.getCount(); i++) { writeString(stream, ELEMENT, names[i]); AbsObject child = abs.getAbsObject(names[i]); write(stream, child); } stream.writeByte(END); } /** * Synchronized so that it can possibly be executed by different threads */ private synchronized AbsObject read(DataInputStream stream, Ontology ontology) throws Throwable { byte type = stream.readByte(); // PRIMITIVE //if (type == PRIMITIVE) { // byte primitiveType = stream.readByte(); // AbsPrimitive abs = null; if ((type&UNMODIFIER) == STRING) { return AbsPrimitive.wrap(readString(stream, type)); } if (type == BOOLEAN) { boolean value = stream.readBoolean(); return AbsPrimitive.wrap(value); } if (type == INTEGER) { int value = stream.readInt(); return AbsPrimitive.wrap(value); } if (type == LONG) { long value = stream.readLong(); return AbsPrimitive.wrap(value); } //#MIDP_EXCLUDE_BEGIN if (type == FLOAT) { float value = stream.readFloat(); return AbsPrimitive.wrap(value); } if (type == DOUBLE) { double value = stream.readDouble(); return AbsPrimitive.wrap(value); } //#MIDP_EXCLUDE_END if (type == DATE) { long value = stream.readLong(); return AbsPrimitive.wrap(new Date(value)); } if (type == BYTE_SEQUENCE) { byte[] value = new byte[stream.readInt()]; stream.read(value, 0, value.length); return AbsPrimitive.wrap(value); } //return abs; //} // AGGREGATE if ((type&UNMODIFIER) == AGGREGATE) { String typeName = readString(stream, type); AbsAggregate abs = new AbsAggregate(typeName); byte marker = stream.readByte(); do { if (marker == ELEMENT) { AbsObject elementValue = read(stream, ontology); if (elementValue != null) { try { abs.add((AbsTerm) elementValue); } catch (ClassCastException cce) { throw new CodecException("Non term element in aggregate"); } } marker = stream.readByte(); } } while (marker != END); return abs; } // CONTENT_ELEMENT_LIST if (type == CONTENT_ELEMENT_LIST) { AbsContentElementList abs = new AbsContentElementList(); byte marker = stream.readByte(); do { if (marker == ELEMENT) { AbsObject elementValue = read(stream, ontology); if (elementValue != null) { try { abs.add((AbsContentElement) elementValue); } catch (ClassCastException cce) { throw new CodecException("Non content-element element in content-element-list"); } } marker = stream.readByte(); } } while (marker != END); return abs; } // If we get here it must be a complex OBJECT String typeName = readString(stream, type); // DEBUG System.out.println("Type is "+typeName); ObjectSchema schema = ontology.getSchema(typeName); // DEBUG System.out.println("Schema is "+schema); AbsObject abs = schema.newInstance(); byte marker = stream.readByte(); do { if ((marker&UNMODIFIER) == ELEMENT) { String attributeName = readString(stream, marker); AbsObject attributeValue = read(stream, ontology); if (attributeValue != null) { AbsHelper.setAttribute(abs, attributeName, attributeValue); } marker = stream.readByte(); } } while (marker != END); return abs; } private final void writeString(DataOutputStream stream, byte tag, String s) throws Throwable { int index = stringReferences.indexOf(s); if (index >= 0) { // Write the tag modified and just put the index //System.out.println("String "+s+" already encoded"); stream.writeByte(tag|MODIFIER); stream.writeByte(index); } else { stream.writeByte(tag); stream.writeUTF(s); if ((s.length() > 1) && (stringReferences.size() < 256)) { stringReferences.addElement(s); } } } private final String readString(DataInputStream stream, byte tag) throws Throwable { String s = null; if ((tag&MODIFIER) != 0) { int index = stream.readUnsignedByte(); if (index < stringReferences.size()) { s= (String) stringReferences.elementAt(index); } } else { s = stream.readUTF(); if ((s.length() > 1) && (stringReferences.size() < 256)) { stringReferences.addElement(s); } } return s; } }