summaryrefslogtreecommitdiff
path: root/java/common/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/common/src')
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java14
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTable.java393
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java41
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTableKeyEnumeration.java47
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java698
-rw-r--r--java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java117
7 files changed, 820 insertions, 492 deletions
diff --git a/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java b/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
index 6a4c385033..a908c76286 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
@@ -435,7 +435,7 @@ public class BasicContentHeaderProperties implements ContentHeaderProperties
if (_headers == null)
{
- setHeaders(new FieldTable());
+ setHeaders(FieldTableFactory.newFieldTable());
}
return _headers;
diff --git a/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java b/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
index 3a683b8e90..97fb434e1c 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
@@ -286,7 +286,7 @@ public class EncodingUtils
}
else
{
- return new FieldTable(buffer, length);
+ return FieldTableFactory.newFieldTable(buffer, length);
}
}
@@ -330,9 +330,9 @@ public class EncodingUtils
// than constructing one from a char array.
// this approach here is valid since we know that all the chars are
// ASCII (0-127)
- byte[] stringBytes = new byte[(int)length];
- buffer.get(stringBytes, 0, (int)length);
- char[] stringChars = new char[(int)length];
+ byte[] stringBytes = new byte[(int) length];
+ buffer.get(stringBytes, 0, (int) length);
+ char[] stringChars = new char[(int) length];
for (int i = 0; i < stringChars.length; i++)
{
stringChars[i] = (char) stringBytes[i];
@@ -350,7 +350,7 @@ public class EncodingUtils
}
else
{
- byte[] result = new byte[(int)length];
+ byte[] result = new byte[(int) length];
buffer.get(result);
return result;
}
@@ -388,7 +388,7 @@ public class EncodingUtils
// TODO: Doesn't support embedded quotes properly.
String[] expressions = selector.split(" +");
- FieldTable result = new FieldTable();
+ FieldTable result = FieldTableFactory.newFieldTable();
for (int i = 0; i < expressions.length; i++)
{
@@ -481,7 +481,7 @@ public class EncodingUtils
public static char[] convertToHexCharArray(byte[] from)
{
int length = from.length;
- char[] result_buff = new char[length * 2 + 2];
+ char[] result_buff = new char[length * 2 + 2];
result_buff[0] = '0';
result_buff[1] = 'x';
diff --git a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
index 796e1843af..44d0268561 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
@@ -1,317 +1,96 @@
/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
+ * 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.apache.qpid.framing;
-import org.apache.log4j.Logger;
import org.apache.mina.common.ByteBuffer;
-import java.util.*;
-
-/**
- * From the protocol document:
- * field-table = short-integer *field-value-pair
- * field-value-pair = field-name field-value
- * field-name = short-string
- * field-value = 'S' long-string
- * / 'I' long-integer
- * / 'D' decimal-value
- * / 'T' long-integer
- * decimal-value = decimals long-integer
- * decimals = OCTET
- */
-public class FieldTable extends LinkedHashMap
+import java.util.Map;
+import java.util.Enumeration;
+
+public interface FieldTable extends Map
{
- private static final Logger _logger = Logger.getLogger(FieldTable.class);
- private long _encodedSize = 0;
-
- public FieldTable()
- {
- super();
- }
-
- /**
- * Construct a new field table.
- *
- * @param buffer the buffer from which to read data. The length byte must be read already
- * @param length the length of the field table. Must be > 0.
- * @throws AMQFrameDecodingException if there is an error decoding the table
- */
- public FieldTable(ByteBuffer buffer, long length) throws AMQFrameDecodingException
- {
- super();
- final boolean debug = _logger.isDebugEnabled();
- assert length > 0;
- _encodedSize = length;
- int sizeRead = 0;
- while (sizeRead < _encodedSize)
- {
- int sizeRemaining = buffer.remaining();
- final String key = EncodingUtils.readShortString(buffer);
- // TODO: use proper charset decoder
- byte iType = buffer.get();
- final char type = (char) iType;
- Object value;
- switch (type)
- {
- case'S':
- value = EncodingUtils.readLongString(buffer);
- break;
- case'I':
- value = new Long(buffer.getUnsignedInt());
- break;
- default:
- String msg = "Field '" + key + "' - unsupported field table type: " + type;
- //some extra debug information...
- msg += " (" + iType + "), length=" + length + ", sizeRead=" + sizeRead + ", sizeRemaining=" + sizeRemaining;
- throw new AMQFrameDecodingException(msg);
- }
- sizeRead += (sizeRemaining - buffer.remaining());
-
- if (debug)
- {
- _logger.debug("FieldTable::FieldTable(buffer," + length + "): Read type '" + type + "', key '" + key + "', value '" + value + "' (now read " + sizeRead + " of " + length + " encoded bytes)...");
- }
-
- // we deliberately want to call put in the parent class since we do
- // not need to do the size calculations
- super.put(key, value);
- }
-
- if (debug)
- {
- _logger.debug("FieldTable::FieldTable(buffer," + length + "): Done.");
- }
- }
-
- public void writeToBuffer(ByteBuffer buffer)
- {
- final boolean debug = _logger.isDebugEnabled();
-
- if (debug)
- {
- _logger.debug("FieldTable::writeToBuffer: Writing encoded size of " + _encodedSize + "...");
- }
-
- // write out the total length, which we have kept up to date as data is added
- EncodingUtils.writeUnsignedInteger(buffer, _encodedSize);
- final Iterator it = this.entrySet().iterator();
- while (it.hasNext())
- {
- Map.Entry me = (Map.Entry) it.next();
- String key = (String) me.getKey();
-
- EncodingUtils.writeShortStringBytes(buffer, key);
- Object value = me.getValue();
-
- if (debug)
- {
- _logger.debug("FieldTable::writeToBuffer: Writing key '" + key + "' of type " + value.getClass() + ", value '" + value + "'...");
- }
-
- if (value instanceof byte[])
- {
- buffer.put((byte) 'S');
- EncodingUtils.writeLongstr(buffer, (byte[]) value);
- }
- else if (value instanceof String)
- {
- // TODO: look at using proper charset encoder
- buffer.put((byte) 'S');
- EncodingUtils.writeLongStringBytes(buffer, (String) value);
- }
- else if (value instanceof Long)
- {
- // TODO: look at using proper charset encoder
- buffer.put((byte) 'I');
- EncodingUtils.writeUnsignedInteger(buffer, ((Long) value).longValue());
- }
- else
- {
- // Should never get here
- throw new IllegalArgumentException("Key '" + key + "': Unsupported type in field table, type: " + ((value == null) ? "null-object" : value.getClass()));
- }
- }
-
- if (debug)
- {
- _logger.debug("FieldTable::writeToBuffer: Done.");
- }
- }
-
- public byte[] getDataAsBytes()
- {
- final ByteBuffer buffer = ByteBuffer.allocate((int) _encodedSize); // XXX: Is cast a problem?
- final Iterator it = this.entrySet().iterator();
- while (it.hasNext())
- {
- Map.Entry me = (Map.Entry) it.next();
- String key = (String) me.getKey();
- EncodingUtils.writeShortStringBytes(buffer, key);
- Object value = me.getValue();
- if (value instanceof byte[])
- {
- buffer.put((byte) 'S');
- EncodingUtils.writeLongstr(buffer, (byte[]) value);
- }
- else if (value instanceof String)
- {
- // TODO: look at using proper charset encoder
- buffer.put((byte) 'S');
- EncodingUtils.writeLongStringBytes(buffer, (String) value);
- }
- else if (value instanceof char[])
- {
- // TODO: look at using proper charset encoder
- buffer.put((byte) 'S');
- EncodingUtils.writeLongStringBytes(buffer, (char[]) value);
- }
- else if (value instanceof Long || value instanceof Integer)
- {
- // TODO: look at using proper charset encoder
- buffer.put((byte) 'I');
- EncodingUtils.writeUnsignedInteger(buffer, ((Long) value).longValue());
- }
- else
- {
- // Should never get here
- assert false;
- }
- }
- final byte[] result = new byte[(int) _encodedSize];
- buffer.flip();
- buffer.get(result);
- buffer.release();
- return result;
- }
-
- public Object put(Object key, Object value)
- {
- final boolean debug = _logger.isDebugEnabled();
-
- if (key == null)
- {
- throw new IllegalArgumentException("All keys must be Strings - was passed: null");
- }
- else if (!(key instanceof String))
- {
- throw new IllegalArgumentException("All keys must be Strings - was passed: " + key.getClass());
- }
-
- Object existing;
-
- if ((existing = super.remove(key)) != null)
- {
- if (debug)
- {
- _logger.debug("Found duplicate of key '" + key + "', previous value '" + existing + "' (" + existing.getClass() + "), to be replaced by '" + value + "', (" + value.getClass() + ") - stack trace of source of duplicate follows...", new Throwable().fillInStackTrace());
- }
-
- // If we are in effect deleting the value (see comment on null values being deleted
- // below) then we also need to remove the name from the encoding length.
- if (value == null)
- {
- _encodedSize -= EncodingUtils.encodedShortStringLength((String) key);
- }
-
- // FIXME: Should be able to short-cut this process if the old and new values are
- // the same object and/or type and size...
- _encodedSize -= getEncodingSize(existing);
- }
- else
- {
- if (value != null)
- {
- _encodedSize += EncodingUtils.encodedShortStringLength((String) key);
- }
- }
-
- // For now: Setting a null value is the equivalent of deleting it.
- // This is ambiguous in the JMS spec and needs thrashing out and potentially
- // testing against other implementations.
- if (value != null)
- {
- _encodedSize += getEncodingSize(value);
- }
-
- return super.put(key, value);
- }
-
- public Object remove(Object key)
- {
- if (super.containsKey(key))
- {
- final Object value = super.remove(key);
- _encodedSize -= EncodingUtils.encodedShortStringLength((String) key);
-
- // This check is, for now, unnecessary (we don't store null values).
- if (value != null)
- {
- _encodedSize -= getEncodingSize(value);
- }
-
- return value;
- }
- else
- {
- return null;
- }
- }
-
- /**
- * @return unsigned integer
- */
- public long getEncodedSize()
- {
- return _encodedSize;
- }
-
- /**
- * @return integer
- */
- private static int getEncodingSize(Object value)
- {
- int encodingSize;
-
- // the extra byte if for the type indicator that is written out
- if (value instanceof String)
- {
- encodingSize = 1 + EncodingUtils.encodedLongStringLength((String) value);
- }
- else if (value instanceof char[])
- {
- encodingSize = 1 + EncodingUtils.encodedLongStringLength((char[]) value);
- }
- else if (value instanceof Integer)
- {
- encodingSize = 1 + 4;
- }
- else if (value instanceof Long)
- {
- encodingSize = 1 + 4;
- }
- else
- {
- throw new IllegalArgumentException("Unsupported type in field table: " + value.getClass());
- }
-
- return encodingSize;
- }
+ void writeToBuffer(ByteBuffer buffer);
+
+ void setFromBuffer(ByteBuffer buffer, long length) throws AMQFrameDecodingException;
+
+ byte[] getDataAsBytes();
+
+ public long getEncodedSize();
+
+ Object put(Object key, Object value);
+
+ Object remove(Object key);
+
+
+ public Enumeration getPropertyNames();
+
+ public boolean propertyExists(String propertyName);
+
+ //Getters
+
+ public Boolean getBoolean(String string);
+
+ public Byte getByte(String string);
+
+ public Short getShort(String string);
+
+ public Integer getInteger(String string);
+
+ public Long getLong(String string);
+
+ public Float getFloat(String string);
+
+ public Double getDouble(String string);
+
+ public String getString(String string);
+
+ public Character getCharacter(String string);
+
+ public byte[] getBytes(String string);
+
+ public Object getObject(String string);
+
+ // Setters
+ public Object setBoolean(String string, boolean b);
+
+ public Object setByte(String string, byte b);
+
+ public Object setShort(String string, short i);
+
+ public Object setInteger(String string, int i);
+
+ public Object setLong(String string, long l);
+
+ public Object setFloat(String string, float v);
+
+ public Object setDouble(String string, double v);
+
+ public Object setString(String string, String string1);
+
+ public Object setChar(String string, char c);
+
+ public Object setBytes(String string, byte[] bytes);
+
+ public Object setBytes(String string, byte[] bytes, int start, int length);
+
+ public Object setObject(String string, Object object);
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java b/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java
new file mode 100644
index 0000000000..1ec57da35b
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.qpid.framing;
+
+import org.apache.mina.common.ByteBuffer;
+
+public class FieldTableFactory
+{
+ public static FieldTable newFieldTable()
+ {
+ return new PropertyFieldTable();
+ }
+
+ public static FieldTable newFieldTable(ByteBuffer byteBuffer, long length) throws AMQFrameDecodingException
+ {
+ return new PropertyFieldTable(byteBuffer, length);
+ }
+
+ public static PropertyFieldTable newFieldTable(String text)
+ {
+ return new PropertyFieldTable(text);
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/FieldTableKeyEnumeration.java b/java/common/src/main/java/org/apache/qpid/framing/FieldTableKeyEnumeration.java
deleted file mode 100644
index e3ba9080c7..0000000000
--- a/java/common/src/main/java/org/apache/qpid/framing/FieldTableKeyEnumeration.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.qpid.framing;
-
-import java.util.Enumeration;
-import java.util.Iterator;
-
-
-public class FieldTableKeyEnumeration implements Enumeration
-{
- protected FieldTable _table;
- protected Iterator _iterator;
-
- public FieldTableKeyEnumeration(FieldTable ft)
- {
- _table = ft;
- _iterator = ft.keySet().iterator();
- }
-
- public boolean hasMoreElements()
- {
- return _iterator.hasNext();
- }
-
- public Object nextElement()
- {
- return _iterator.next();
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java b/java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java
index 96360e4aaa..36558011ac 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java
@@ -21,20 +21,28 @@
package org.apache.qpid.framing;
import org.apache.log4j.Logger;
+import org.apache.mina.common.ByteBuffer;
+import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
//extends FieldTable
-public class PropertyFieldTable
+public class PropertyFieldTable implements FieldTable, Map
{
-
private static final Logger _logger = Logger.getLogger(PropertyFieldTable.class);
+
+ public static final char AMQP_DECIMAL_PROPERTY_PREFIX = 'D';
+ public static final char AMQP_UNSIGNEDINT_PROPERTY_PREFIX = 'I';
+ public static final char AMQP_TIMESTAMP_PROPERTY_PREFIX = 'T';
+ public static final char AMQP_STRING_PROPERTY_PREFIX = 'S';
+
public static final char BOOLEAN_PROPERTY_PREFIX = 'B';
public static final char BYTE_PROPERTY_PREFIX = 'b';
public static final char SHORT_PROPERTY_PREFIX = 's';
@@ -42,10 +50,12 @@ public class PropertyFieldTable
public static final char LONG_PROPERTY_PREFIX = 'l';
public static final char FLOAT_PROPERTY_PREFIX = 'f';
public static final char DOUBLE_PROPERTY_PREFIX = 'd';
- public static final char STRING_PROPERTY_PREFIX = 'S';
+ public static final char STRING_PROPERTY_PREFIX = AMQP_STRING_PROPERTY_PREFIX;
public static final char CHAR_PROPERTY_PREFIX = 'c';
public static final char BYTES_PROPERTY_PREFIX = 'y';
+ //Our custom prefix for encoding across the wire
+ private static final char XML_PROPERTY_PREFIX = 'X';
private static final String BOOLEAN = "boolean";
private static final String BYTE = "byte";
@@ -66,7 +76,7 @@ public class PropertyFieldTable
private LinkedHashMap<String, Object> _properties;
private LinkedHashMap<String, String> _propertyNamesTypeMap;
-
+ private long _encodedSize = 0;
public PropertyFieldTable()
{
@@ -84,73 +94,167 @@ public class PropertyFieldTable
}
catch (Exception e)
{
- System.out.println(textFormat);
- e.printStackTrace();
+ _logger.error("Unable to decode PropertyFieldTable format:" + textFormat, e);
}
+ }
+ /**
+ * Construct a new field table.
+ *
+ * @param buffer the buffer from which to read data. The length byte must be read already
+ * @param length the length of the field table. Must be > 0.
+ * @throws AMQFrameDecodingException if there is an error decoding the table
+ */
+ public PropertyFieldTable(ByteBuffer buffer, long length) throws AMQFrameDecodingException
+ {
+ this();
+ setFromBuffer(buffer, length);
}
// ************ Getters
+ private Object get(String propertyName, char prefix)
+ {
+ String type = _propertyNamesTypeMap.get(propertyName);
+
+ if (type == null)
+ {
+ return null;
+ }
+
+ if (type.equals("" + prefix))
+ {
+ return _properties.get(propertyName);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
public Boolean getBoolean(String string)
{
- return (Boolean) _properties.get(BOOLEAN_PROPERTY_PREFIX + string);
+ Object o = get(string, BOOLEAN_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (Boolean) o;
+ }
+ else
+ {
+ return null;
+ }
}
public Byte getByte(String string)
{
- return (Byte) _properties.get(BYTE_PROPERTY_PREFIX + string);
+ Object o = get(string, BYTE_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (Byte) o;
+ }
+ else
+ {
+ return null;
+ }
}
public Short getShort(String string)
{
- return (Short) _properties.get(SHORT_PROPERTY_PREFIX + string);
+ Object o = get(string, SHORT_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (Short) o;
+ }
+ else
+ {
+ return null;
+ }
}
public Integer getInteger(String string)
{
- return (Integer) _properties.get(INT_PROPERTY_PREFIX + string);
+ Object o = get(string, INT_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (Integer) o;
+ }
+ else
+ {
+ return null;
+ }
}
public Long getLong(String string)
{
- return (Long) _properties.get(LONG_PROPERTY_PREFIX + string);
+ Object o = get(string, LONG_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (Long) o;
+ }
+ else
+ {
+ return null;
+ }
}
public Float getFloat(String string)
{
- return (Float) _properties.get(FLOAT_PROPERTY_PREFIX + string);
+ Object o = get(string, FLOAT_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (Float) o;
+ }
+ else
+ {
+ return null;
+ }
}
public Double getDouble(String string)
{
- return (Double) _properties.get(DOUBLE_PROPERTY_PREFIX + string);
+ Object o = get(string, DOUBLE_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (Double) o;
+ }
+ else
+ {
+ return null;
+ }
}
public String getString(String string)
{
- return (String) _properties.get(STRING_PROPERTY_PREFIX + string);
+ Object o = get(string, STRING_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (String) o;
+ }
+ else
+ {
+ return null;
+ }
}
public Character getCharacter(String string)
{
- return (Character) _properties.get(CHAR_PROPERTY_PREFIX + string);
+ Object o = get(string, CHAR_PROPERTY_PREFIX);
+ if (o != null)
+ {
+ return (Character) o;
+ }
+ else
+ {
+ return null;
+ }
}
public byte[] getBytes(String string)
{
- return (byte[]) _properties.get(BYTES_PROPERTY_PREFIX + string);
- }
-
- public Object getObject(String string)
- {
- String typestring = _propertyNamesTypeMap.get(string);
-
- if (typestring != null && !typestring.equals(""))
+ Object o = get(string, BYTES_PROPERTY_PREFIX);
+ if (o != null)
{
- char type = typestring.charAt(0);
-
- return _properties.get(type + string);
+ return (byte[]) o;
}
else
{
@@ -158,91 +262,66 @@ public class PropertyFieldTable
}
}
- // ************ Setters
-
-
- public void setBoolean(String string, boolean b)
+ public Object getObject(String string)
{
- checkPropertyName(string, BOOLEAN_PROPERTY_PREFIX);
+ return _properties.get(string);
+ }
+ // ************ Setters
- _propertyNamesTypeMap.put(string, "" + BOOLEAN_PROPERTY_PREFIX);
- _properties.put(BOOLEAN_PROPERTY_PREFIX + string, b);// ? new Long(1) : new Long(0));
+ public Object setBoolean(String string, boolean b)
+ {
+ return put(BOOLEAN_PROPERTY_PREFIX + string, b);
}
- public void setByte(String string, byte b)
+ public Object setByte(String string, byte b)
{
- checkPropertyName(string, BYTE_PROPERTY_PREFIX);
-
-
- _properties.put(BYTE_PROPERTY_PREFIX + string, b);
+ return put(BYTE_PROPERTY_PREFIX + string, b);
}
- public void setShort(String string, short i)
+ public Object setShort(String string, short i)
{
- checkPropertyName(string, SHORT_PROPERTY_PREFIX);
-
-
- _properties.put(SHORT_PROPERTY_PREFIX + string, i);
+ return put(SHORT_PROPERTY_PREFIX + string, i);
}
- public void setInteger(String string, int i)
+ public Object setInteger(String string, int i)
{
- checkPropertyName(string, INT_PROPERTY_PREFIX);
-
-
- _properties.put(INT_PROPERTY_PREFIX + string, i);
+ return put(INT_PROPERTY_PREFIX + string, i);
}
- public void setLong(String string, long l)
+ public Object setLong(String string, long l)
{
- checkPropertyName(string, LONG_PROPERTY_PREFIX);
-
-
- _properties.put(LONG_PROPERTY_PREFIX + string, l);
+ return put(LONG_PROPERTY_PREFIX + string, l);
}
- public void setFloat(String string, float v)
+ public Object setFloat(String string, float v)
{
- checkPropertyName(string, FLOAT_PROPERTY_PREFIX);
-
-
- _properties.put(FLOAT_PROPERTY_PREFIX + string, v);
+ return put(FLOAT_PROPERTY_PREFIX + string, v);
}
- public void setDouble(String string, double v)
+ public Object setDouble(String string, double v)
{
- checkPropertyName(string, DOUBLE_PROPERTY_PREFIX);
-
-
- _properties.put(DOUBLE_PROPERTY_PREFIX + string, v);
+ return put(DOUBLE_PROPERTY_PREFIX + string, v);
}
- public void setString(String string, String string1)
+ public Object setString(String string, String string1)
{
- checkPropertyName(string, STRING_PROPERTY_PREFIX);
-
-
- _properties.put(STRING_PROPERTY_PREFIX + string, string1);
+ return put(STRING_PROPERTY_PREFIX + string, string1);
}
- public void setChar(String string, char c)
+ public Object setChar(String string, char c)
{
- checkPropertyName(string, CHAR_PROPERTY_PREFIX);
-
- _properties.put(CHAR_PROPERTY_PREFIX + string, c);
+ return put(CHAR_PROPERTY_PREFIX + string, c);
}
- public void setBytes(String string, byte[] bytes)
+ public Object setBytes(String string, byte[] bytes)
{
- setBytes(string, bytes, 0, bytes.length);
+ return setBytes(string, bytes, 0, bytes.length);
}
- public void setBytes(String string, byte[] bytes, int start, int length)
+ public Object setBytes(String string, byte[] bytes, int start, int length)
{
- checkPropertyName(string, BYTES_PROPERTY_PREFIX);
-
- _properties.put(BYTES_PROPERTY_PREFIX + string, sizeByteArray(bytes, start, length));
+ return put(BYTES_PROPERTY_PREFIX + string, sizeByteArray(bytes, start, length));
}
private byte[] sizeByteArray(byte[] bytes, int start, int length)
@@ -259,65 +338,65 @@ public class PropertyFieldTable
}
- public void setObject(String string, Object object)
+ public Object setObject(String string, Object object)
{
if (object instanceof Boolean)
{
- setBoolean(string, (Boolean) object);
+ return setBoolean(string, (Boolean) object);
}
else
{
if (object instanceof Byte)
{
- setByte(string, (Byte) object);
+ return setByte(string, (Byte) object);
}
else
{
if (object instanceof Short)
{
- setShort(string, (Short) object);
+ return setShort(string, (Short) object);
}
else
{
if (object instanceof Integer)
{
- setInteger(string, (Integer) object);
+ return setInteger(string, (Integer) object);
}
else
{
if (object instanceof Long)
{
- setLong(string, (Long) object);
+ return setLong(string, (Long) object);
}
else
{
if (object instanceof Float)
{
- setFloat(string, (Float) object);
+ return setFloat(string, (Float) object);
}
else
{
if (object instanceof Double)
{
- setDouble(string, (Double) object);
+ return setDouble(string, (Double) object);
}
else
{
if (object instanceof String)
{
- setString(string, (String) object);
+ return setString(string, (String) object);
}
else
{
if (object instanceof Character)
{
- setChar(string, (Character) object);
+ return setChar(string, (Character) object);
}
else
{
if (object instanceof byte[])
{
- setBytes(string, (byte[]) object);
+ return setBytes(string, (byte[]) object);
}
}
}
@@ -328,8 +407,7 @@ public class PropertyFieldTable
}
}
}
-
-
+ return null;
}
// ***** Methods
@@ -344,12 +422,16 @@ public class PropertyFieldTable
{
String key = (String) keys.next();
- names.add(key.substring(1));
+ names.add(key);
}
return names.elements();
}
+ public boolean propertyExists(String propertyName)
+ {
+ return _propertyNamesTypeMap.containsKey(propertyName);
+ }
public boolean itemExists(String string)
{
@@ -367,7 +449,6 @@ public class PropertyFieldTable
return false;
}
-
public String toString()
{
return valueOf(this);
@@ -390,35 +471,55 @@ public class PropertyFieldTable
else
{
buf.append('\n');
- buf.append(propertyXML(propertyName, true));
- if (propertyName.charAt(0) == BYTES_PROPERTY_PREFIX)
- {
- //remove '>'
- buf.deleteCharAt(buf.length() - 1);
+ buf.append(valueAsXML(table._propertyNamesTypeMap.get(propertyName) + propertyName, entry.getValue()));
+ }
+ }
+ buf.append("\n");
+ buf.append(PROPERTY_FIELD_TABLE_CLOSE_XML);
- byte[] bytes = (byte[]) entry.getValue();
- buf.append(" length='").append(bytes.length).append("'>");
+ return buf.toString();
+ }
- buf.append(byteArrayToXML(propertyName.substring(1), bytes));
- }
- else
- {
+ private static String valueAsXML(String name, Object value)
+ {
+ char propertyPrefix = name.charAt(0);
+ String propertyName = name.substring(1);
- buf.append(String.valueOf(entry.getValue()));
- }
- buf.append(propertyXML(propertyName, false));
- }
+ StringBuffer buf = new StringBuffer();
+ // Start Tag
+ buf.append(propertyXML(name, true));
+
+ // Value
+ if (propertyPrefix == BYTES_PROPERTY_PREFIX)
+ {
+ //remove '>'
+ buf.deleteCharAt(buf.length() - 1);
+
+ byte[] bytes = (byte[]) value;
+ buf.append(" length='").append(bytes.length).append("'>");
+
+ buf.append(byteArrayToXML(propertyName, bytes));
+ }
+ else
+ {
+ buf.append(String.valueOf(value));
}
- buf.append("\n");
- buf.append(PROPERTY_FIELD_TABLE_CLOSE_XML);
+
+ //End Tag
+ buf.append(propertyXML(name, false));
return buf.toString();
}
- private void checkPropertyName(String propertyName, char propertyPrefix)
+ private Object checkPropertyName(String name)
{
+ String propertyName = name.substring(1);
+ char propertyPrefix = name.charAt(0);
+
+ Object previous = null;
+
if (propertyName == null)
{
throw new IllegalArgumentException("Property name must not be null");
@@ -432,15 +533,29 @@ public class PropertyFieldTable
if (currentValue != null)
{
- _properties.remove(currentValue + propertyName);
+ previous = _properties.remove(currentValue + propertyName);
+
+ // If we are in effect deleting the value (see comment on null values being deleted
+ // below) then we also need to remove the name from the encoding length.
+ if (previous == null)
+ {
+ _encodedSize -= EncodingUtils.encodedShortStringLength(propertyName);
+ }
+
+ // FIXME: Should be able to short-cut this process if the old and new values are
+ // the same object and/or type and size...
+ _encodedSize -= getEncodingSize(currentValue + propertyName, previous);
}
_propertyNamesTypeMap.put(propertyName, "" + propertyPrefix);
+
+ return previous;
}
- private static String propertyXML(String propertyName, boolean start)
+ private static String propertyXML(String name, boolean start)
{
- char typeIdentifier = propertyName.charAt(0);
+ char propertyPrefix = name.charAt(0);
+ String propertyName = name.substring(1);
StringBuffer buf = new StringBuffer();
@@ -453,8 +568,7 @@ public class PropertyFieldTable
buf.append("</");
}
-
- switch (typeIdentifier)
+ switch (propertyPrefix)
{
case BOOLEAN_PROPERTY_PREFIX:
buf.append(BOOLEAN);
@@ -487,14 +601,13 @@ public class PropertyFieldTable
buf.append(CHAR);
break;
default:
- buf.append(UNKNOWN + " (identifier ").append(typeIdentifier).append(")");
+ buf.append(UNKNOWN + " (identifier ").append(propertyPrefix).append(")");
break;
}
-
if (start)
{
- buf.append(" name='").append(propertyName.substring(1)).append("'");
+ buf.append(" name='").append(propertyName).append("'");
}
buf.append(">");
@@ -519,8 +632,6 @@ public class PropertyFieldTable
private void processBytesXMLLine(String xmlline)
{
- String type = xmlline.substring(1, xmlline.indexOf(" "));
-
String propertyName = xmlline.substring(xmlline.indexOf('\'') + 1,
xmlline.indexOf('\'', xmlline.indexOf('\'') + 1));
String value = xmlline.substring(xmlline.indexOf(">") + 1,
@@ -545,7 +656,6 @@ public class PropertyFieldTable
{
String token = tokenizer.nextToken();
-
if (token.equals(PROPERTY_FIELD_TABLE_CLOSE_XML)
|| token.equals(BYTES_CLOSE_XML))
{
@@ -555,7 +665,6 @@ public class PropertyFieldTable
if (token.equals(BYTES_CLOSE_XML))
{
processing_bytes = false;
-
}
if (processing)
@@ -578,11 +687,9 @@ public class PropertyFieldTable
{
processing = true;
}
-
}
}
-
private void processXMLLine(String xmlline)
{
// <<type> name='<property>'><value></<type>>
@@ -611,11 +718,39 @@ public class PropertyFieldTable
}
if (type.equals(BYTES))
{
- Integer length = Integer.parseInt(xmlline.substring(
- xmlline.lastIndexOf("=") + 2
- , xmlline.lastIndexOf("'")));
+ int headerEnd = xmlline.indexOf('>');
+ String bytesHeader = xmlline.substring(0, headerEnd);
+
+ //Extract length value
+ Integer length = Integer.parseInt(bytesHeader.substring(
+ bytesHeader.lastIndexOf("=") + 2
+ , bytesHeader.lastIndexOf("'")));
+
+
byte[] bytes = new byte[length];
setBytes(propertyName, bytes);
+
+ //Check if the line contains all the byte values
+ // This is needed as the XMLLine sent across the wire is the bytes value
+
+ int byteStart = xmlline.indexOf('<', headerEnd);
+
+ if (byteStart > 0)
+ {
+ while (!xmlline.startsWith(BYTES_CLOSE_XML, byteStart))
+ {
+ //This should be the next byte line
+ int bytePrefixEnd = xmlline.indexOf('>', byteStart) + 1;
+ int byteEnd = xmlline.indexOf('>', bytePrefixEnd) + 1;
+
+ String byteline = xmlline.substring(byteStart, byteEnd);
+
+ processBytesXMLLine(byteline);
+
+ byteStart = xmlline.indexOf('<', byteEnd);
+ }
+ }
+
}
if (type.equals(SHORT))
{
@@ -651,6 +786,311 @@ public class PropertyFieldTable
}
}
+ // ************************* Byte Buffer Processing
-}
+ public void writeToBuffer(ByteBuffer buffer)
+ {
+ final boolean debug = _logger.isDebugEnabled();
+
+ if (debug)
+ {
+ _logger.debug("FieldTable::writeToBuffer: Writing encoded size of " + _encodedSize + "...");
+ }
+
+ EncodingUtils.writeUnsignedInteger(buffer, _encodedSize);
+
+ putDataInBuffer(buffer);
+ }
+
+ public byte[] getDataAsBytes()
+ {
+ final ByteBuffer buffer = ByteBuffer.allocate((int) _encodedSize); // FIXME XXX: Is cast a problem?
+
+ putDataInBuffer(buffer);
+
+ final byte[] result = new byte[(int) _encodedSize];
+ buffer.flip();
+ buffer.get(result);
+ buffer.release();
+ return result;
+ }
+
+ public int size()
+ {
+ return _properties.size();
+ }
+
+ public boolean isEmpty()
+ {
+ return _properties.isEmpty();
+ }
+
+ public boolean containsKey(Object key)
+ {
+ return _properties.containsKey(key);
+ }
+
+ public boolean containsValue(Object value)
+ {
+ return _properties.containsValue(value);
+ }
+
+ public Object get(Object key)
+ {
+ return _properties.get(key);
+ }
+
+
+ public Object put(Object key, Object value)
+ {
+ return setObject(key.toString(), value);
+ }
+
+ protected Object put(String key, Object value)
+ {
+ Object previous = checkPropertyName(key);
+
+
+ String propertyName = key.substring(1);
+ char propertyPrefix = _propertyNamesTypeMap.get(propertyName).charAt(0);
+
+ if (value != null)
+ {
+ //Add the size of the propertyName
+ _encodedSize += EncodingUtils.encodedShortStringLength(propertyName);
+
+ // For now: Setting a null value is the equivalent of deleting it.
+ // This is ambiguous in the JMS spec and needs thrashing out and potentially
+ // testing against other implementations.
+
+ //Add the size of the content
+ _encodedSize += getEncodingSize(key, value);
+ }
+
+ _properties.put((String) propertyName, value);
+
+ return previous;
+ }
+
+ public Object remove(Object key)
+ {
+ if (key instanceof String)
+ {
+ throw new IllegalArgumentException("Property key be a string");
+ }
+
+ char propertyPrefix = ((String) key).charAt(0);
+
+ if (_properties.containsKey(key))
+ {
+ final Object value = _properties.remove(key);
+ // plus one for the type
+ _encodedSize -= EncodingUtils.encodedShortStringLength(((String) key));
+
+ // This check is, for now, unnecessary (we don't store null values).
+ if (value != null)
+ {
+ _encodedSize -= getEncodingSize(propertyPrefix + (String) key, value);
+ }
+
+ return value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void putAll(Map t)
+ {
+ Iterator it = t.keySet().iterator();
+
+ while (it.hasNext())
+ {
+ Object key = it.next();
+ put(key, t.get(key));
+ }
+ }
+
+ public void clear()
+ {
+ _properties.clear();
+ _propertyNamesTypeMap.clear();
+ }
+
+ public Set keySet()
+ {
+ return _properties.keySet();
+ }
+
+ public Collection values()
+ {
+ return _properties.values();
+ }
+
+ public Set entrySet()
+ {
+ return _properties.entrySet();
+ }
+
+ public long getEncodedSize()
+ {
+ return _encodedSize;
+ }
+
+
+ private void putDataInBuffer(ByteBuffer buffer)
+ {
+ final Iterator it = _properties.entrySet().iterator();
+
+ //If there are values then write out the encoded Size... could check _encodedSize != 0
+ // write out the total length, which we have kept up to date as data is added
+
+
+ while (it.hasNext())
+ {
+ Map.Entry me = (Map.Entry) it.next();
+ String propertyName = (String) me.getKey();
+
+ //The type value
+ char propertyPrefix = _propertyNamesTypeMap.get(propertyName).charAt(0);
+ //The actual param name skipping type
+
+ EncodingUtils.writeShortStringBytes(buffer, propertyName);
+ Object value = me.getValue();
+
+ switch (propertyPrefix)
+ {
+
+ case STRING_PROPERTY_PREFIX:
+ // TODO: look at using proper charset encoder
+ buffer.put((byte) STRING_PROPERTY_PREFIX);
+ EncodingUtils.writeLongStringBytes(buffer, (String) value);
+ break;
+
+ case AMQP_UNSIGNEDINT_PROPERTY_PREFIX:
+ case LONG_PROPERTY_PREFIX:
+ case INT_PROPERTY_PREFIX:
+ case BOOLEAN_PROPERTY_PREFIX:
+ case BYTE_PROPERTY_PREFIX:
+ case SHORT_PROPERTY_PREFIX:
+ case FLOAT_PROPERTY_PREFIX:
+ case DOUBLE_PROPERTY_PREFIX:
+ case CHAR_PROPERTY_PREFIX:
+ case BYTES_PROPERTY_PREFIX:
+ case XML_PROPERTY_PREFIX:
+ // Encode as XML
+ buffer.put((byte) XML_PROPERTY_PREFIX);
+ EncodingUtils.writeLongStringBytes(buffer, valueAsXML(propertyPrefix + propertyName, value));
+ break;
+ default:
+ {
+
+ // Should never get here
+ throw new IllegalArgumentException("Key '" + propertyName + "': Unsupported type in field table, type: " + ((value == null) ? "null-object" : value.getClass()));
+ }
+ }
+ }
+ }
+
+
+ public void setFromBuffer(ByteBuffer buffer, long length) throws AMQFrameDecodingException
+ {
+ final boolean debug = _logger.isDebugEnabled();
+
+ int sizeRead = 0;
+ while (sizeRead < length)
+ {
+ int sizeRemaining = buffer.remaining();
+ final String key = EncodingUtils.readShortString(buffer);
+ // TODO: use proper charset decoder
+ byte iType = buffer.get();
+ final char type = (char) iType;
+ Object value = null;
+
+ switch (type)
+ {
+ case STRING_PROPERTY_PREFIX:
+ value = EncodingUtils.readLongString(buffer);
+ break;
+ case LONG_PROPERTY_PREFIX:
+ case INT_PROPERTY_PREFIX:
+ case BOOLEAN_PROPERTY_PREFIX:
+ case BYTE_PROPERTY_PREFIX:
+ case SHORT_PROPERTY_PREFIX:
+ case FLOAT_PROPERTY_PREFIX:
+ case DOUBLE_PROPERTY_PREFIX:
+ case CHAR_PROPERTY_PREFIX:
+ case BYTES_PROPERTY_PREFIX:
+ case XML_PROPERTY_PREFIX:
+ processXMLLine(EncodingUtils.readLongString(buffer));
+ break;
+ default:
+ String msg = "Field '" + key + "' - unsupported field table type: " + type + ".";
+ //some extra debug information...
+ msg += " (" + iType + "), length=" + length + ", sizeRead=" + sizeRead + ", sizeRemaining=" + sizeRemaining;
+ throw new AMQFrameDecodingException(msg);
+ }
+
+ sizeRead += (sizeRemaining - buffer.remaining());
+
+ if (debug)
+ {
+ _logger.debug("FieldTable::PropFieldTable(buffer," + length + "): Read type '" + type + "', key '" + key + "', value '" + value + "' (now read " + sizeRead + " of " + length + " encoded bytes)...");
+ }
+
+ if (type != XML_PROPERTY_PREFIX)
+ {
+ setObject(key, value);
+ }
+ }
+
+ if (debug)
+ {
+ _logger.debug("FieldTable::FieldTable(buffer," + length + "): Done.");
+ }
+ }
+
+
+ /**
+ * @param name the property name with type prefix
+ * @param value the property value
+ * @return integer
+ */
+ private static int getEncodingSize(String name, Object value)
+ {
+ int encodingSize;
+
+ char propertyPrefix = name.charAt(0);
+
+ switch (propertyPrefix)
+ {
+ // the extra byte if for the type indicator that is written out
+ case STRING_PROPERTY_PREFIX:
+ encodingSize = 1 + EncodingUtils.encodedLongStringLength((String) value);
+ break;
+ case LONG_PROPERTY_PREFIX:
+ case INT_PROPERTY_PREFIX:
+ case BOOLEAN_PROPERTY_PREFIX:
+ case BYTE_PROPERTY_PREFIX:
+ case SHORT_PROPERTY_PREFIX:
+ case FLOAT_PROPERTY_PREFIX:
+ case DOUBLE_PROPERTY_PREFIX:
+ case CHAR_PROPERTY_PREFIX:
+ case BYTES_PROPERTY_PREFIX:
+ case XML_PROPERTY_PREFIX:
+ encodingSize = 1 + EncodingUtils.encodedLongStringLength(valueAsXML(name, value));
+ break;
+ default:
+ //encodingSize = 1 + EncodingUtils.encodedLongStringLength(String.valueOf(value));
+ // We are using XML String encoding
+ throw new IllegalArgumentException("Unsupported type in field table: " + value.getClass());
+ }
+
+// the extra byte for the type indicator is calculated in the name
+ return encodingSize;
+ }
+
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java b/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
index 5070b6ecb1..0b6820b8a9 100644
--- a/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
+++ b/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
@@ -25,6 +25,10 @@ import junit.framework.TestCase;
import java.util.Enumeration;
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.ByteBufferProxy;
+import org.apache.mina.common.support.BaseByteBuffer;
+
public class PropertyFieldTableTest extends TestCase
{
@@ -206,7 +210,7 @@ public class PropertyFieldTableTest extends TestCase
PropertyFieldTable table2 = new PropertyFieldTable(table1XML);
- Assert.assertEquals(table1XML, table2.toString());
+ Assert.assertEquals(table1XML, table2.toString());
}
public void testKeyEnumeration()
@@ -273,6 +277,117 @@ public class PropertyFieldTableTest extends TestCase
Assert.assertEquals(Short.MAX_VALUE, table.getObject("object-short"));
}
+
+ public void testwriteBuffer()
+ {
+ byte[] bytes = {99, 98, 97, 96, 95};
+
+ PropertyFieldTable table = new PropertyFieldTable();
+ table.setBoolean("bool", true);
+ table.setByte("byte", Byte.MAX_VALUE);
+
+ table.setBytes("bytes", bytes);
+ table.setChar("char", 'c');
+ table.setDouble("double", Double.MAX_VALUE);
+ table.setFloat("float", Float.MAX_VALUE);
+ table.setInteger("int", Integer.MAX_VALUE);
+ table.setLong("long", Long.MAX_VALUE);
+ table.setShort("short", Short.MAX_VALUE);
+
+
+ final ByteBuffer buffer = ByteBuffer.allocate((int) table.getEncodedSize()); // FIXME XXX: Is cast a problem?
+
+ table.writeToBuffer(buffer);
+
+ buffer.flip();
+
+ long length = buffer.getUnsignedInt();
+
+ try
+ {
+ PropertyFieldTable table2 = new PropertyFieldTable(buffer, length);
+
+ Assert.assertEquals((Boolean) true, table2.getBoolean("bool"));
+ Assert.assertEquals((Byte) Byte.MAX_VALUE, table2.getByte("byte"));
+ assertBytesEqual(bytes, table2.getBytes("bytes"));
+ Assert.assertEquals((Character) 'c', table2.getCharacter("char"));
+ Assert.assertEquals(Double.MAX_VALUE, table2.getDouble("double"));
+ Assert.assertEquals(Float.MAX_VALUE, table2.getFloat("float"));
+ Assert.assertEquals((Integer) Integer.MAX_VALUE, table2.getInteger("int"));
+ Assert.assertEquals((Long) Long.MAX_VALUE, table2.getLong("long"));
+ Assert.assertEquals((Short) Short.MAX_VALUE, table2.getShort("short"));
+ }
+ catch (AMQFrameDecodingException e)
+ {
+ e.printStackTrace();
+ fail("PFT should be instantiated from bytes." + e.getCause());
+ }
+ }
+
+ public void testEncodingSize()
+ {
+ FieldTable result = FieldTableFactory.newFieldTable();
+ int size = 0;
+ result.put("one", 1L);
+ // size is 1(size) + bytes for short string
+ size = 1 + 3; // 1 + key length
+ // or size is 1(the type) + number of bytes (4bytes worth) + bytes
+ size += 1 + 4; // 1 + 4 + value length
+ size += "<long name='one'>1</long>".length(); // this is the xml encoding for a long.
+ assertEquals(size, result.getEncodedSize());
+
+ result.put("two", 2L);
+ size += 1 + 3; // 1 + key length
+ size += 1 + 4; // 1 + 4 + value length
+ size += "<long name='two'>2</long>".length(); // this is the xml encoding for a long.
+ assertEquals(size, result.getEncodedSize());
+
+ result.put("three", 3L);
+ size += 1 + 5; // 1 + key length
+ size += 1 + 4; // 1 + 4 + value length
+ size += "<long name='three'>3</long>".length(); // this is the xml encoding for a long.
+ assertEquals(size, result.getEncodedSize());
+
+ result.put("four", 4L);
+ size += 1 + 4; // 1 + key length
+ size += 1 + 4; // 1 + 4 + value length
+ size += "<long name='four'>4</long>".length(); // this is the xml encoding for a long.
+ assertEquals(size, result.getEncodedSize());
+
+ result.put("five", 5L);
+ size += 1 + 4; // 1 + key length
+ size += 1 + 4; // 1 + 4 + value length
+ size += "<long name='five'>5</long>".length(); // this is the xml encoding for a long.
+ assertEquals(size, result.getEncodedSize());
+
+ //fixme should perhaps be expanded to incorporate all types.
+
+ final ByteBuffer buffer = ByteBuffer.allocate((int) result.getEncodedSize()); // FIXME XXX: Is cast a problem?
+
+ result.writeToBuffer(buffer);
+
+ buffer.flip();
+
+ long length = buffer.getUnsignedInt();
+
+ try
+ {
+ PropertyFieldTable table2 = new PropertyFieldTable(buffer, length);
+
+ Assert.assertEquals((Long) 1L, table2.getLong("one"));
+ Assert.assertEquals((Long) 2L, table2.getLong("two"));
+ Assert.assertEquals((Long) 3L, table2.getLong("three"));
+ Assert.assertEquals((Long) 4L, table2.getLong("four"));
+ Assert.assertEquals((Long) 5L, table2.getLong("five"));
+ }
+ catch (AMQFrameDecodingException e)
+ {
+ e.printStackTrace();
+ fail("PFT should be instantiated from bytes." + e.getCause());
+ }
+
+ }
+
private void assertBytesEqual(byte[] expected, byte[] actual)
{
Assert.assertEquals(expected.length, actual.length);