diff options
author | Martin Ritchie <ritchiem@apache.org> | 2006-12-18 12:41:15 +0000 |
---|---|---|
committer | Martin Ritchie <ritchiem@apache.org> | 2006-12-18 12:41:15 +0000 |
commit | 3df6475c3538b5fe8c31178529c268c3c82467c0 (patch) | |
tree | 0bccdd24680345d3fda71a08bac4c657581b58bb | |
parent | 1c83d0defb47c7f9503ba8341e039876b7871879 (diff) | |
download | qpid-python-3df6475c3538b5fe8c31178529c268c3c82467c0.tar.gz |
Trunk Merges
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/jmsselectors@488251 13f79535-47bb-0310-9956-ffa450edef68
26 files changed, 3717 insertions, 573 deletions
diff --git a/java/common/pom.xml b/java/common/pom.xml index 0d48a24646..653b2a8a9d 100644 --- a/java/common/pom.xml +++ b/java/common/pom.xml @@ -39,14 +39,14 @@ <spec.stylesheet>${basedir}/src/main/xsl/framing.xsl</spec.stylesheet> <registry.stylesheet>${basedir}/src/main/xsl/registry.xsl</registry.stylesheet> <registry.template>${basedir}/src/main/xsl/registry.template</registry.template> - <generated.path>${project.build.directory}/generated/xsl</generated.path> + <generated.path>${project.build.directory}/generated-sources/xsl</generated.path> <generated.package>org/apache/qpid/framing</generated.package> <generated.dir>${generated.path}/${generated.package}</generated.dir> <specs.dir>${topDirectoryLocation}/../specs</specs.dir> </properties> <build> - <plugins> + <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> @@ -77,19 +77,6 @@ </plugins> </build> - <repositories> - <repository> - <snapshots> - <enabled>true</enabled> - </snapshots> - <id>java.net repository</id> - <name>Maven 1.x Repository</name> - <url>httsp://maven-repository.dev.java.net/nonav/repository/</url> - <layout>legacy</layout> - </repository> - - - </repositories> <dependencies> <dependency> <groupId>log4j</groupId> @@ -99,18 +86,13 @@ <groupId>org.apache.mina</groupId> <artifactId>mina-core</artifactId> </dependency> - <!-- dependency> - <groupId>grizzly</groupId> - <artifactId>grizzly</artifactId> - <version>1.0.4</version> - </dependency --> <dependency> - <groupId>org.apache.geronimo.specs</groupId> - <artifactId>geronimo-jms_1.1_spec</artifactId> - </dependency> - <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jms_1.1_spec</artifactId> + </dependency> </dependencies> </project> diff --git a/java/common/protocol-version.xml b/java/common/protocol-version.xml index 59e83d7f8f..96ce348523 100644 --- a/java/common/protocol-version.xml +++ b/java/common/protocol-version.xml @@ -21,6 +21,8 @@ <project name="Qpid Common Protocol Versions" default="generate"> <property name="saxon.jar" value="lib/saxon/saxon8.jar"/> + <!-- temporarily hard-wired XML spec version for build avoidance --> + <property name="amqp.xml" value="${specs.dir}/amqp-8.0.xml"/> <macrodef name="saxon"> <attribute name="out"/> @@ -61,8 +63,7 @@ flags="s" byline="true"/> <!-- Create directory; generate from specification file --> - <mkdir dir="${generated.dir}_${@{ver}.amqp(major)}_${@{ver}.amqp(minor)}"/> - <saxon out="${generated.dir}_${@{ver}.amqp(major)}_${@{ver}.amqp(minor)}/results.out" + <saxon out="${generated.dir}/results.out" src="${specs.dir}/amqp-@{ver}.xml" xsl="${spec.stylesheet}"> <arg value="major=${@{ver}.amqp(major)}"/> @@ -70,14 +71,14 @@ <arg value="registry_name=MainRegistry"/> </saxon> <!-- --> - <saxon out="${generated.dir}_${@{ver}.amqp(major)}_${@{ver}.amqp(minor)}/cluster.out" + <saxon out="${generated.dir}/cluster.out" src="${cluster.asl}" xsl="${spec.stylesheet}"> <arg value="major=${@{ver}.amqp(major)}"/> <arg value="minor=${@{ver}.amqp(minor)}"/> <arg value="registry_name=ClusterRegistry"/> </saxon> - <saxon out="${generated.dir}_${@{ver}.amqp(major)}_${@{ver}.amqp(minor)}/registry.out" + <saxon out="${generated.dir}/registry.out" src="${registry.template}" xsl="${registry.stylesheet}"> <arg value="major=${@{ver}.amqp(major)}"/> @@ -86,11 +87,10 @@ </sequential> </macrodef> -<!-- <uptodate property="generated" targetfile="${generated.dir}/results.out" - srcfile="${amqp.xml}"/> --> + <uptodate property="generated" targetfile="${generated.dir}/results.out" + srcfile="${amqp.xml}"/> -<!-- <target name="generate" unless="generated"> --> - <target name="generate"> + <target name="generate" unless="generated"> <mkdir dir="${generated.dir}"/> <copy file="src/main/versions/ProtocolVersionList.java.tmpl" tofile="${proto_version}" overwrite="true"/> diff --git a/java/common/src/main/java/org/apache/qpid/AMQPInvalidClassException.java b/java/common/src/main/java/org/apache/qpid/AMQPInvalidClassException.java new file mode 100644 index 0000000000..883e13e5e6 --- /dev/null +++ b/java/common/src/main/java/org/apache/qpid/AMQPInvalidClassException.java @@ -0,0 +1,30 @@ +/* + * 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; + + +public class AMQPInvalidClassException extends RuntimeException +{ + public AMQPInvalidClassException(String s) + { + super(s); + } +} diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java b/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java index 37efe1a34f..d829144b11 100644 --- a/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java +++ b/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java @@ -24,7 +24,7 @@ import org.apache.mina.common.ByteBuffer; public abstract class AMQBody { - protected abstract byte getType(); + protected abstract byte getFrameType(); /** * Get the size of the body diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java b/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java index 21c4bc8d5b..e75f37d623 100644 --- a/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java +++ b/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java @@ -45,7 +45,7 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock public void writePayload(ByteBuffer buffer) { - buffer.put(bodyFrame.getType()); + buffer.put(bodyFrame.getFrameType()); // TODO: how does channel get populated EncodingUtils.writeUnsignedShort(buffer, channel); EncodingUtils.writeUnsignedInteger(buffer, bodyFrame.getSize()); diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java index c3e02aed56..6659b4ff8f 100644 --- a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java +++ b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java @@ -42,7 +42,7 @@ public abstract class AMQMethodBody extends AMQBody protected abstract void writeMethodPayload(ByteBuffer buffer); - protected byte getType() + protected byte getFrameType() { return TYPE; } 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 a908c76286..61837f65cc 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 @@ -57,6 +57,8 @@ public class BasicContentHeaderProperties implements ContentHeaderProperties private FieldTable _headers; + private JMSPropertyFieldTable _jmsHeaders; + private byte _deliveryMode; private byte _priority; @@ -276,6 +278,7 @@ public class BasicContentHeaderProperties implements ContentHeaderProperties if ((_propertyFlags & (1 << 13)) > 0) { _headers = EncodingUtils.readFieldTable(buffer); + setJMSHeaders(); } if ((_propertyFlags & (1 << 12)) > 0) { @@ -358,6 +361,8 @@ public class BasicContentHeaderProperties implements ContentHeaderProperties if ((_propertyFlags & (1 << 13)) > 0) { _headers = EncodingUtils.readFieldTable(buffer); + setJMSHeaders(); + } _decodedHeaders = true; } @@ -446,6 +451,26 @@ public class BasicContentHeaderProperties implements ContentHeaderProperties clearEncodedForm(); _propertyFlags |= (1 << 13); _headers = headers; + setJMSHeaders(); + } + + private void setJMSHeaders() + { + if (_jmsHeaders == null) + { + _jmsHeaders = new JMSPropertyFieldTable(_headers); + } + else + { + _jmsHeaders.setFieldTable(_headers); + } + } + + public JMSPropertyFieldTable getJMSHeaders() + { + //This will ensure we have a blank header + getHeaders(); + return _jmsHeaders; } public byte getDeliveryMode() diff --git a/java/common/src/main/java/org/apache/qpid/framing/Content.java b/java/common/src/main/java/org/apache/qpid/framing/Content.java new file mode 100644 index 0000000000..e5feeec2a4 --- /dev/null +++ b/java/common/src/main/java/org/apache/qpid/framing/Content.java @@ -0,0 +1,26 @@ +/* + * + * 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; + +public interface Content +{ + // TODO: New Content class required for AMQP 0-9. +} diff --git a/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java b/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java index 2aae833fcd..3a2e4b3b3c 100644 --- a/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java +++ b/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java @@ -28,7 +28,7 @@ public class ContentBody extends AMQBody public ByteBuffer payload; - protected byte getType() + protected byte getFrameType() { return TYPE; } diff --git a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java index 46b933b2c3..a59869b1d8 100644 --- a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java +++ b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java @@ -53,7 +53,7 @@ public class ContentHeaderBody extends AMQBody this.bodySize = bodySize; } - protected byte getType() + protected byte getFrameType() { return TYPE; } 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 97fb434e1c..46dff9ffa8 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 @@ -98,6 +98,12 @@ public class EncodingUtils } } + public static int encodedContentLength(Content table) + { + // TODO: New Content class required for AMQP 0-9. + return 0; + } + public static void writeShortStringBytes(ByteBuffer buffer, String s) { if (s != null) @@ -108,9 +114,7 @@ public class EncodingUtils { encodedString[i] = (byte) cha[i]; } - // TODO: check length fits in an unsigned byte - writeUnsignedByte(buffer, (short) encodedString.length); - buffer.put(encodedString); + writeBytes(buffer, encodedString); } else { @@ -195,6 +199,12 @@ public class EncodingUtils } } + + public static long unsignedIntegerLength() + { + return 4; + } + public static void writeUnsignedInteger(ByteBuffer buffer, long l) { // TODO: Is this comparison safe? Do I need to cast RHS to long? @@ -227,6 +237,11 @@ public class EncodingUtils } } + public static void writeContentBytes(ByteBuffer buffer, Content content) + { + // TODO: New Content class required for AMQP 0-9. + } + public static void writeBooleans(ByteBuffer buffer, boolean[] values) { byte packedValue = 0; @@ -243,6 +258,7 @@ public class EncodingUtils /** * This is used for writing longstrs. + * * @param buffer * @param data */ @@ -290,6 +306,12 @@ public class EncodingUtils } } + public static Content readContent(ByteBuffer buffer) throws AMQFrameDecodingException + { + // TODO: New Content class required for AMQP 0-9. + return null; + } + public static String readShortString(ByteBuffer buffer) { short length = buffer.getUnsigned(); @@ -321,7 +343,7 @@ public class EncodingUtils long length = buffer.getUnsignedInt(); if (length == 0) { - return null; + return ""; } else { @@ -363,97 +385,6 @@ public class EncodingUtils return buffer.getUnsignedInt(); } - // Will barf with a NPE on a null input. Not sure whether it should return null or - // an empty field-table (which would be slower - perhaps unnecessarily). - // - // Some sample input and the result output: - // - // Input: "a=1" "a=2 c=3" "a=3 c=4 d" "a='four' b='five'" "a=bad" - // - // Parsing <a=1>... - // {a=1} - // Parsing <a=2 c=3>... - // {a=2, c=3} - // Parsing <a=3 c=4 d>... - // {a=3, c=4, d=null} - // Parsing <a='four' b='five'>... - // {a=four, b=five} - // Parsing <a=bad>... - // java.lang.IllegalArgumentException: a: Invalid integer in <bad> from <a=bad>. - // - public static FieldTable createFieldTableFromMessageSelector(String selector) - { - boolean debug = _logger.isDebugEnabled(); - - // TODO: Doesn't support embedded quotes properly. - String[] expressions = selector.split(" +"); - - FieldTable result = FieldTableFactory.newFieldTable(); - - for (int i = 0; i < expressions.length; i++) - { - String expr = expressions[i]; - - if (debug) - { - _logger.debug("Expression = <" + expr + ">"); - } - - int equals = expr.indexOf('='); - - if (equals < 0) - { - // Existence check - result.put("S" + expr.trim(), null); - } - else - { - String key = expr.substring(0, equals).trim(); - String value = expr.substring(equals + 1).trim(); - - if (debug) - { - _logger.debug("Key = <" + key + ">, Value = <" + value + ">"); - } - - if (value.charAt(0) == '\'') - { - if (value.charAt(value.length() - 1) != '\'') - { - throw new IllegalArgumentException(key + ": Missing quote in <" + value + "> from <" + selector + ">."); - } - else - { - value = value.substring(1, value.length() - 1); - - result.put("S" + key, value); - } - } - else - { - try - { - int intValue = Integer.parseInt(value); - - result.put("i" + key, value); - } - catch (NumberFormatException e) - { - throw new IllegalArgumentException(key + ": Invalid integer in <" + value + "> from <" + selector + ">."); - - } - } - } - } - - if (debug) - { - _logger.debug("Field-table created from <" + selector + "> is <" + result + ">"); - } - - return (result); - - } static byte[] hexToByteArray(String id) { @@ -526,24 +457,174 @@ public class EncodingUtils return (new String(convertToHexCharArray(from))); } - public static void main(String[] args) + private static char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + //**** new methods + + // AMQP_BOOLEAN_PROPERTY_PREFIX + + public static void writeBoolean(ByteBuffer buffer, Boolean aBoolean) + { + buffer.put((byte) (aBoolean ? 1 : 0)); + } + + public static Boolean readBoolean(ByteBuffer buffer) + { + byte packedValue = buffer.get(); + return (packedValue == 1); + } + + public static int encodedBooleanLength() + { + return 1; + } + + // AMQP_BYTE_PROPERTY_PREFIX + public static void writeByte(ByteBuffer buffer, Byte aByte) + { + buffer.put(aByte); + } + + public static Byte readByte(ByteBuffer buffer) + { + return buffer.get(); + } + + public static int encodedByteLength() + { + return 1; + } + + + // AMQP_SHORT_PROPERTY_PREFIX + public static void writeShort(ByteBuffer buffer, Short aShort) + { + buffer.putShort(aShort); + } + + public static Short readShort(ByteBuffer buffer) + { + return buffer.getShort(); + } + + public static int encodedShortLength() + { + return 2; + } + + // INTEGER_PROPERTY_PREFIX + public static void writeInteger(ByteBuffer buffer, Integer aInteger) { - for (int i = 0; i < args.length; i++) + buffer.putInt(aInteger); + } + + public static Integer readInteger(ByteBuffer buffer) + { + return buffer.getInt(); + } + + public static int encodedIntegerLength() + { + return 4; + } + + // AMQP_LONG_PROPERTY_PREFIX + public static void writeLong(ByteBuffer buffer, Long aLong) + { + buffer.putLong(aLong); + } + + public static Long readLong(ByteBuffer buffer) + { + return buffer.getLong(); + } + + public static int encodedLongLength() + { + return 8; + } + + // Float_PROPERTY_PREFIX + public static void writeFloat(ByteBuffer buffer, Float aFloat) + { + buffer.putFloat(aFloat); + } + + public static Float readFloat(ByteBuffer buffer) + { + return buffer.getFloat(); + } + + public static int encodedFloatLength() + { + return 4; + } + + + // Double_PROPERTY_PREFIX + public static void writeDouble(ByteBuffer buffer, Double aDouble) + { + buffer.putDouble(aDouble); + } + + public static Double readDouble(ByteBuffer buffer) + { + return buffer.getDouble(); + } + + public static int encodedDoubleLength() + { + return 8; + } + + + public static byte[] readBytes(ByteBuffer buffer) + { + short length = buffer.getUnsigned(); + if (length == 0) + { + return null; + } + else { - String selector = args[i]; + byte[] dataBytes = new byte[length]; + buffer.get(dataBytes, 0, length); - System.err.println("Parsing <" + selector + ">..."); + return dataBytes; + } + } - try - { - System.err.println(createFieldTableFromMessageSelector(selector)); - } - catch (IllegalArgumentException e) - { - System.err.println(e); - } + public static void writeBytes(ByteBuffer buffer, byte[] data) + { + if (data != null) + { + // TODO: check length fits in an unsigned byte + writeUnsignedByte(buffer, (short) data.length); + buffer.put(data); + } + else + { + // really writing out unsigned byte + buffer.put((byte) 0); } } - private static char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + //CHAR_PROPERTY + public static int encodedCharLength() + { + return encodedByteLength(); + } + + public static char readChar(ByteBuffer buffer) + { + //This is valid as we know that the Character is ASCII 0..127 + return (char) buffer.get(); + } + + public static void writeChar(ByteBuffer buffer, char character) + { + //This is valid as we know that the Character is ASCII 0..127 + writeByte(buffer, (byte) character); + } + } 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 44d0268561..193c7adf1c 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 @@ -93,4 +93,6 @@ public interface FieldTable extends Map public Object setObject(String string, Object object); + public boolean isNullStringValue(String name); + } 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 index 1ec57da35b..b1fcd8a20b 100644 --- a/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java +++ b/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java @@ -34,7 +34,7 @@ public class FieldTableFactory return new PropertyFieldTable(byteBuffer, length); } - public static PropertyFieldTable newFieldTable(String text) + public static FieldTable newFieldTable(String text) { return new PropertyFieldTable(text); } diff --git a/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java b/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java index 6bbdaaeed5..7a160ef471 100644 --- a/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java +++ b/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java @@ -27,7 +27,7 @@ public class HeartbeatBody extends AMQBody public static final byte TYPE = 8; public static AMQFrame FRAME = new HeartbeatBody().toFrame(); - protected byte getType() + protected byte getFrameType() { return TYPE; } diff --git a/java/common/src/main/java/org/apache/qpid/framing/JMSPropertyFieldTable.java b/java/common/src/main/java/org/apache/qpid/framing/JMSPropertyFieldTable.java new file mode 100644 index 0000000000..142a689a01 --- /dev/null +++ b/java/common/src/main/java/org/apache/qpid/framing/JMSPropertyFieldTable.java @@ -0,0 +1,471 @@ +/* + * 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; +import org.apache.qpid.AMQPInvalidClassException; + +import javax.jms.MessageFormatException; +import javax.jms.JMSException; +import java.util.Enumeration; + + +public class JMSPropertyFieldTable +{ + private FieldTable _fieldtable; + + public JMSPropertyFieldTable() + { + _fieldtable = new PropertyFieldTable(); + } + + public JMSPropertyFieldTable(FieldTable table) + { + _fieldtable = table; + } + + public JMSPropertyFieldTable(ByteBuffer buffer, long length) throws JMSException + { + try + { + _fieldtable = new PropertyFieldTable(buffer, length); + } + catch (AMQFrameDecodingException e) + { + JMSException error = new JMSException(e.getMessage()); + error.setLinkedException(e); + throw error; + } + } + + private void checkPropertyName(String propertyName) + { + if (propertyName == null) + { + throw new IllegalArgumentException("Property name must not be null"); + } + else if ("".equals(propertyName)) + { + throw new IllegalArgumentException("Property name must not be the empty string"); + } + + checkIdentiferFormat(propertyName); + } + + protected static void checkIdentiferFormat(String propertyName) + { +// JMS requirements 3.5.1 Property Names +// Identifiers: +// - An identifier is an unlimited-length character sequence that must begin +// with a Java identifier start character; all following characters must be Java +// identifier part characters. An identifier start character is any character for +// which the method Character.isJavaIdentifierStart returns true. This includes +// '_' and '$'. An identifier part character is any character for which the +// method Character.isJavaIdentifierPart returns true. +// - Identifiers cannot be the names NULL, TRUE, or FALSE. +// – Identifiers cannot be NOT, AND, OR, BETWEEN, LIKE, IN, IS, or +// ESCAPE. +// – Identifiers are either header field references or property references. The +// type of a property value in a message selector corresponds to the type +// used to set the property. If a property that does not exist in a message is +// referenced, its value is NULL. The semantics of evaluating NULL values +// in a selector are described in Section 3.8.1.2, “Null Values.” +// – The conversions that apply to the get methods for properties do not +// apply when a property is used in a message selector expression. For +// example, suppose you set a property as a string value, as in the +// following: +// myMessage.setStringProperty("NumberOfOrders", "2"); +// The following expression in a message selector would evaluate to false, +// because a string cannot be used in an arithmetic expression: +// "NumberOfOrders > 1" +// – Identifiers are case sensitive. +// – Message header field references are restricted to JMSDeliveryMode, +// JMSPriority, JMSMessageID, JMSTimestamp, JMSCorrelationID, and +// JMSType. JMSMessageID, JMSCorrelationID, and JMSType values may be +// null and if so are treated as a NULL value. + + if (Boolean.getBoolean("strict-jms")) + { + // JMS start character + if (!(Character.isJavaIdentifierStart(propertyName.charAt(0)))) + { + throw new IllegalArgumentException("Identifier '" + propertyName + "' does not start with a valid JMS identifier start character"); + } + + // JMS part character + int length = propertyName.length(); + for (int c = 1; c < length; c++) + { + if (!(Character.isJavaIdentifierPart(propertyName.charAt(c)))) + { + throw new IllegalArgumentException("Identifier '" + propertyName + "' contains an invalid JMS identifier character"); + } + } + + // JMS invalid names + if ((propertyName.equals("NULL") + || propertyName.equals("TRUE") + || propertyName.equals("FALSE") + || propertyName.equals("NOT") + || propertyName.equals("AND") + || propertyName.equals("OR") + || propertyName.equals("BETWEEN") + || propertyName.equals("LIKE") + || propertyName.equals("IN") + || propertyName.equals("IS") + || propertyName.equals("ESCAPE"))) + { + throw new IllegalArgumentException("Identifier '" + propertyName + "' is not allowed in JMS"); + } + } + + } + + // MapMessage Interface + public boolean getBoolean(String string) throws JMSException + { + Boolean b = _fieldtable.getBoolean(string); + + if (b == null) + { + if (_fieldtable.containsKey(string)) + { + Object str = _fieldtable.getObject(string); + + if (str == null || !(str instanceof String)) + { + throw new MessageFormatException("getBoolean can't use " + string + " item."); + } + else + { + return Boolean.valueOf((String) str); + } + } + else + { + b = Boolean.valueOf(null); + } + } + + return b; + } + + public char getCharacter(String string) throws JMSException + { + Character c = _fieldtable.getCharacter(string); + + if (c == null) + { + if (_fieldtable.isNullStringValue(string)) + { + throw new NullPointerException("Cannot convert null char"); + } + else + { + throw new MessageFormatException("getChar can't use " + string + " item."); + } + } + else + { + return (char) c; + } + } + + public byte[] getBytes(String string) throws JMSException + { + byte[] bs = _fieldtable.getBytes(string); + + if (bs == null) + { + throw new MessageFormatException("getBytes can't use " + string + " item."); + } + else + { + return bs; + } + } + + public byte getByte(String string) throws JMSException + { + Byte b = _fieldtable.getByte(string); + if (b == null) + { + if (_fieldtable.containsKey(string)) + { + Object str = _fieldtable.getObject(string); + + if (str == null || !(str instanceof String)) + { + throw new MessageFormatException("getByte can't use " + string + " item."); + } + else + { + return Byte.valueOf((String) str); + } + } + else + { + b = Byte.valueOf(null); + } + } + + return b; + } + + public short getShort(String string) throws JMSException + { + Short s = _fieldtable.getShort(string); + + if (s == null) + { + s = Short.valueOf(getByte(string)); + } + + return s; + } + + public int getInteger(String string) throws JMSException + { + Integer i = _fieldtable.getInteger(string); + + if (i == null) + { + i = Integer.valueOf(getShort(string)); + } + + return i; + } + + public long getLong(String string) throws JMSException + { + Long l = _fieldtable.getLong(string); + + if (l == null) + { + l = Long.valueOf(getInteger(string)); + } + + return l; + } + + public float getFloat(String string) throws JMSException + { + Float f = _fieldtable.getFloat(string); + + if (f == null) + { + if (_fieldtable.containsKey(string)) + { + Object str = _fieldtable.getObject(string); + + if (str == null || !(str instanceof String)) + { + throw new MessageFormatException("getFloat can't use " + string + " item."); + } + else + { + return Float.valueOf((String) str); + } + } + else + { + f = Float.valueOf(null); + } + + } + + return f; + } + + public double getDouble(String string) throws JMSException + { + Double d = _fieldtable.getDouble(string); + + if (d == null) + { + d = Double.valueOf(getFloat(string)); + } + + return d; + } + + public String getString(String string) throws JMSException + { + String s = _fieldtable.getString(string); + + if (s == null) + { + if (_fieldtable.containsKey(string)) + { + Object o = _fieldtable.getObject(string); + if (o instanceof byte[]) + { + throw new MessageFormatException("getObject couldn't find " + string + " item."); + } + else + { + if (o == null) + { + return null; + } + else + { + s = String.valueOf(o); + } + } + } + } + + return s; + } + + public Object getObject(String string) throws JMSException + { + return _fieldtable.getObject(string); + } + + public void setBoolean(String string, boolean b) throws JMSException + { + checkPropertyName(string); + _fieldtable.setBoolean(string, b); + } + + public void setChar(String string, char c) throws JMSException + { + checkPropertyName(string); + _fieldtable.setChar(string, c); + } + + public Object setBytes(String string, byte[] bytes) + { + return _fieldtable.setBytes(string, bytes, 0, bytes.length); + } + + public Object setBytes(String string, byte[] bytes, int start, int length) + { + return _fieldtable.setBytes(string, bytes, start, length); + } + + public void setByte(String string, byte b) throws JMSException + { + checkPropertyName(string); + _fieldtable.setByte(string, b); + } + + public void setShort(String string, short i) throws JMSException + { + checkPropertyName(string); + _fieldtable.setShort(string, i); + } + + public void setInteger(String string, int i) throws JMSException + { + checkPropertyName(string); + _fieldtable.setInteger(string, i); + } + + public void setLong(String string, long l) throws JMSException + { + checkPropertyName(string); + _fieldtable.setLong(string, l); + } + + public void setFloat(String string, float v) throws JMSException + { + checkPropertyName(string); + _fieldtable.setFloat(string, v); + } + + public void setDouble(String string, double v) throws JMSException + { + checkPropertyName(string); + _fieldtable.setDouble(string, v); + } + + public void setString(String string, String string1) throws JMSException + { + checkPropertyName(string); + _fieldtable.setString(string, string1); + } + + public void setObject(String string, Object object) throws JMSException + { + checkPropertyName(string); + try + { + _fieldtable.setObject(string, object); + } + catch (AMQPInvalidClassException aice) + { + throw new MessageFormatException("Only primatives are allowed object is:" + object.getClass()); + } + } + + public boolean itemExists(String string) throws JMSException + { + return _fieldtable.containsKey(string); + } + + public void setFieldTable(FieldTable headers) + { + _fieldtable = headers; + } + + public Enumeration getPropertyNames() + { + return _fieldtable.getPropertyNames(); + } + + public void clear() + { + _fieldtable.clear(); + } + + public boolean propertyExists(String propertyName) + { + return _fieldtable.propertyExists(propertyName); + } + + public Object put(Object key, Object value) + { + return _fieldtable.put(key, value); + } + + public Object remove(String propertyName) + { + return _fieldtable.remove(propertyName); + } + + public boolean isEmpty() + { + return _fieldtable.isEmpty(); + } + + public void writeToBuffer(ByteBuffer data) + { + _fieldtable.writeToBuffer(data); + } + + public Enumeration getMapNames() + { + return getPropertyNames(); + } +} 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 36558011ac..1292ff2f6e 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 @@ -7,9 +7,9 @@ * 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 @@ -22,6 +22,7 @@ package org.apache.qpid.framing; import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.AMQPInvalidClassException; import java.util.Collection; import java.util.Enumeration; @@ -31,32 +32,13 @@ import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.Vector; +import java.util.HashMap; //extends FieldTable -public class PropertyFieldTable implements FieldTable, Map +public class PropertyFieldTable implements FieldTable { 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'; - public static final char INT_PROPERTY_PREFIX = 'i'; - 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 = 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"; private static final String BYTES = "bytes"; @@ -66,6 +48,7 @@ public class PropertyFieldTable implements FieldTable, Map private static final String FLOAT = "float"; private static final String DOUBLE = "double"; private static final String STRING = "string"; + private static final String NULL_STRING = "nullstring"; private static final String CHAR = "char"; private static final String UNKNOWN = "unknown type"; @@ -74,15 +57,67 @@ public class PropertyFieldTable implements FieldTable, Map private static final String BYTES_CLOSE_XML = "</" + BYTES + ">"; private static final String BYTES_OPEN_XML_START = "<" + BYTES; + public static enum Prefix + { + //AMQP FieldTable Wire Types + AMQP_DECIMAL_PROPERTY_PREFIX('D'), + AMQP_UNSIGNED_SHORT_PROPERTY_PREFIX('S'), + AMQP_UNSIGNED_INT_PROPERTY_PREFIX('I'), + AMQP_UNSIGNED_LONG_PROPERTY_PREFIX('L'), + AMQP_DOUBLE_EXTTENDED_PROPERTY_PREFIX('D'), + + AMQP_TIMESTAMP_PROPERTY_PREFIX('T'), + AMQP_BINARY_PROPERTY_PREFIX('x'), + + //Strings + AMQP_ASCII_STRING_PROPERTY_PREFIX('c'), + AMQP_WIDE_STRING_PROPERTY_PREFIX('C'), + AMQP_NULL_STRING_PROPERTY_PREFIX('n'), + + //Java Primative Types + AMQP_BOOLEAN_PROPERTY_PREFIX('t'), + AMQP_BYTE_PROPERTY_PREFIX('b'), + AMQP_ASCII_CHARACTER_PROPERTY_PREFIX('k'), + AMQP_SHORT_PROPERTY_PREFIX('s'), + AMQP_INT_PROPERTY_PREFIX('i'), + AMQP_LONG_PROPERTY_PREFIX('l'), + AMQP_FLOAT_PROPERTY_PREFIX('f'), + AMQP_DOUBLE_PROPERTY_PREFIX('d'); + + private final char _identifier; + + Prefix(char identifier) + { + _identifier = identifier; + //_reverseTypeMap.put(identifier, this); + } + + public final char identifier() + { + return _identifier; + } + + } + + public static Map<Character, Prefix> _reverseTypeMap = new HashMap<Character, Prefix>(); + + static + { + for (Prefix p : Prefix.values()) + { + _reverseTypeMap.put(p.identifier(), p); + } + } + private LinkedHashMap<String, Object> _properties; - private LinkedHashMap<String, String> _propertyNamesTypeMap; + private LinkedHashMap<String, Prefix> _propertyNamesTypeMap; private long _encodedSize = 0; public PropertyFieldTable() { super(); _properties = new LinkedHashMap<String, Object>(); - _propertyNamesTypeMap = new LinkedHashMap<String, String>(); + _propertyNamesTypeMap = new LinkedHashMap<String, Prefix>(); } public PropertyFieldTable(String textFormat) @@ -94,7 +129,8 @@ public class PropertyFieldTable implements FieldTable, Map } catch (Exception e) { - _logger.error("Unable to decode PropertyFieldTable format:" + textFormat, e); + _logger.warn("Unable to decode PropertyFieldTable format:" + textFormat, e); + throw new IllegalArgumentException("Unable to decode PropertyFieldTable format:" + textFormat); } } @@ -112,17 +148,17 @@ public class PropertyFieldTable implements FieldTable, Map } // ************ Getters - - private Object get(String propertyName, char prefix) + private Object get(String propertyName, Prefix prefix) { - String type = _propertyNamesTypeMap.get(propertyName); + //Retrieve the type associated with this name + Prefix type = _propertyNamesTypeMap.get(propertyName); if (type == null) { return null; } - - if (type.equals("" + prefix)) + + if (type.equals(prefix)) { return _properties.get(propertyName); } @@ -134,8 +170,8 @@ public class PropertyFieldTable implements FieldTable, Map public Boolean getBoolean(String string) { - Object o = get(string, BOOLEAN_PROPERTY_PREFIX); - if (o != null) + Object o = get(string, Prefix.AMQP_BOOLEAN_PROPERTY_PREFIX); + if (o != null && o instanceof Boolean) { return (Boolean) o; } @@ -147,7 +183,7 @@ public class PropertyFieldTable implements FieldTable, Map public Byte getByte(String string) { - Object o = get(string, BYTE_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_BYTE_PROPERTY_PREFIX); if (o != null) { return (Byte) o; @@ -160,7 +196,7 @@ public class PropertyFieldTable implements FieldTable, Map public Short getShort(String string) { - Object o = get(string, SHORT_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_SHORT_PROPERTY_PREFIX); if (o != null) { return (Short) o; @@ -173,7 +209,7 @@ public class PropertyFieldTable implements FieldTable, Map public Integer getInteger(String string) { - Object o = get(string, INT_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_INT_PROPERTY_PREFIX); if (o != null) { return (Integer) o; @@ -186,7 +222,7 @@ public class PropertyFieldTable implements FieldTable, Map public Long getLong(String string) { - Object o = get(string, LONG_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_LONG_PROPERTY_PREFIX); if (o != null) { return (Long) o; @@ -199,7 +235,7 @@ public class PropertyFieldTable implements FieldTable, Map public Float getFloat(String string) { - Object o = get(string, FLOAT_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_FLOAT_PROPERTY_PREFIX); if (o != null) { return (Float) o; @@ -212,7 +248,7 @@ public class PropertyFieldTable implements FieldTable, Map public Double getDouble(String string) { - Object o = get(string, DOUBLE_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_DOUBLE_PROPERTY_PREFIX); if (o != null) { return (Double) o; @@ -225,20 +261,63 @@ public class PropertyFieldTable implements FieldTable, Map public String getString(String string) { - Object o = get(string, STRING_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_ASCII_STRING_PROPERTY_PREFIX); if (o != null) { return (String) o; } else { - return null; + o = get(string, Prefix.AMQP_WIDE_STRING_PROPERTY_PREFIX); + if (o != null) + { + return (String) o; + } + else + { + + Prefix type = _propertyNamesTypeMap.get(string); + + if (type == null || type.equals(Prefix.AMQP_NULL_STRING_PROPERTY_PREFIX)) + { + return null; + } + else + { + switch (type) + { + case AMQP_ASCII_STRING_PROPERTY_PREFIX: + case AMQP_WIDE_STRING_PROPERTY_PREFIX: + case AMQP_BINARY_PROPERTY_PREFIX: + return null; + default: + case AMQP_BYTE_PROPERTY_PREFIX: + case AMQP_BOOLEAN_PROPERTY_PREFIX: + case AMQP_SHORT_PROPERTY_PREFIX: + case AMQP_INT_PROPERTY_PREFIX: + case AMQP_LONG_PROPERTY_PREFIX: + case AMQP_FLOAT_PROPERTY_PREFIX: + case AMQP_DOUBLE_PROPERTY_PREFIX: + return String.valueOf(_properties.get(string)); + case AMQP_ASCII_CHARACTER_PROPERTY_PREFIX: + Object value = _properties.get(string); + if (value == null) + { + throw new NullPointerException("null char cannot be converted to String"); + } + else + { + return String.valueOf(value); + } + } + } + } } } public Character getCharacter(String string) { - Object o = get(string, CHAR_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_ASCII_CHARACTER_PROPERTY_PREFIX); if (o != null) { return (Character) o; @@ -251,7 +330,7 @@ public class PropertyFieldTable implements FieldTable, Map public byte[] getBytes(String string) { - Object o = get(string, BYTES_PROPERTY_PREFIX); + Object o = get(string, Prefix.AMQP_BINARY_PROPERTY_PREFIX); if (o != null) { return (byte[]) o; @@ -271,47 +350,62 @@ public class PropertyFieldTable implements FieldTable, Map public Object setBoolean(String string, boolean b) { - return put(BOOLEAN_PROPERTY_PREFIX + string, b); + return put(Prefix.AMQP_BOOLEAN_PROPERTY_PREFIX, string, b); } public Object setByte(String string, byte b) { - return put(BYTE_PROPERTY_PREFIX + string, b); + return put(Prefix.AMQP_BYTE_PROPERTY_PREFIX, string, b); } public Object setShort(String string, short i) { - return put(SHORT_PROPERTY_PREFIX + string, i); + return put(Prefix.AMQP_SHORT_PROPERTY_PREFIX, string, i); } public Object setInteger(String string, int i) { - return put(INT_PROPERTY_PREFIX + string, i); + return put(Prefix.AMQP_INT_PROPERTY_PREFIX, string, i); } public Object setLong(String string, long l) { - return put(LONG_PROPERTY_PREFIX + string, l); + return put(Prefix.AMQP_LONG_PROPERTY_PREFIX, string, l); } public Object setFloat(String string, float v) { - return put(FLOAT_PROPERTY_PREFIX + string, v); + return put(Prefix.AMQP_FLOAT_PROPERTY_PREFIX, string, v); } public Object setDouble(String string, double v) { - return put(DOUBLE_PROPERTY_PREFIX + string, v); + return put(Prefix.AMQP_DOUBLE_PROPERTY_PREFIX, string, v); } public Object setString(String string, String string1) { - return put(STRING_PROPERTY_PREFIX + string, string1); + if (string1 == null) + { + return put(Prefix.AMQP_NULL_STRING_PROPERTY_PREFIX, string, null); + } + else + { + //FIXME: determine string encoding and set either WIDE or ASCII string +// if () + { + return put(Prefix.AMQP_WIDE_STRING_PROPERTY_PREFIX, string, string1); + } +// else +// { +// return put(Prefix.AMQP_ASCII_STRING_PROPERTY_PREFIX, string, string1); +// } + } } public Object setChar(String string, char c) { - return put(CHAR_PROPERTY_PREFIX + string, c); + return put(Prefix.AMQP_ASCII_CHARACTER_PROPERTY_PREFIX, string, c); } public Object setBytes(String string, byte[] bytes) @@ -321,7 +415,7 @@ public class PropertyFieldTable implements FieldTable, Map public Object setBytes(String string, byte[] bytes, int start, int length) { - return put(BYTES_PROPERTY_PREFIX + string, sizeByteArray(bytes, start, length)); + return put(Prefix.AMQP_BINARY_PROPERTY_PREFIX, string, sizeByteArray(bytes, start, length)); } private byte[] sizeByteArray(byte[] bytes, int start, int length) @@ -344,70 +438,53 @@ public class PropertyFieldTable implements FieldTable, Map { return setBoolean(string, (Boolean) object); } - else + else if (object instanceof Byte) { - if (object instanceof Byte) - { - return setByte(string, (Byte) object); - } - else - { - if (object instanceof Short) - { - return setShort(string, (Short) object); - } - else - { - if (object instanceof Integer) - { - return setInteger(string, (Integer) object); - } - else - { - if (object instanceof Long) - { - return setLong(string, (Long) object); - } - else - { - if (object instanceof Float) - { - return setFloat(string, (Float) object); - } - else - { - if (object instanceof Double) - { - return setDouble(string, (Double) object); - } - else - { - if (object instanceof String) - { - return setString(string, (String) object); - } - else - { - if (object instanceof Character) - { - return setChar(string, (Character) object); - } - else - { - if (object instanceof byte[]) - { - return setBytes(string, (byte[]) object); - } - } - } - } - } - } - } - } - } + return setByte(string, (Byte) object); } - return null; + else if (object instanceof Short) + { + return setShort(string, (Short) object); + } + else if (object instanceof Integer) + { + return setInteger(string, (Integer) object); + } + else if (object instanceof Long) + { + return setLong(string, (Long) object); + } + else if (object instanceof Float) + { + return setFloat(string, (Float) object); + } + else if (object instanceof Double) + { + return setDouble(string, (Double) object); + } + else if (object instanceof String) + { + return setString(string, (String) object); + } + else if (object instanceof Character) + { + return setChar(string, (Character) object); + } + else if (object instanceof byte[]) + { + return setBytes(string, (byte[]) object); + } + + throw new AMQPInvalidClassException("Only Primatives objects allowed Object is:" + object.getClass()); + } + + + public boolean isNullStringValue(String name) + { + return _properties.containsKey(name) && (_properties.get(name) == null) && + _propertyNamesTypeMap.get(name).equals(Prefix.AMQP_NULL_STRING_PROPERTY_PREFIX); + + } // ***** Methods @@ -430,23 +507,12 @@ public class PropertyFieldTable implements FieldTable, Map public boolean propertyExists(String propertyName) { - return _propertyNamesTypeMap.containsKey(propertyName); + return itemExists(propertyName); } public boolean itemExists(String string) { - Iterator keys = _properties.keySet().iterator(); - - while (keys.hasNext()) - { - String key = (String) keys.next(); - - if (key.endsWith(string)) - { - return true; - } - } - return false; + return _properties.containsKey(string); } public String toString() @@ -464,16 +530,9 @@ public class PropertyFieldTable implements FieldTable, Map { final Map.Entry entry = (Map.Entry) it.next(); final String propertyName = (String) entry.getKey(); - if (propertyName == null) - { - buf.append("\nInternal error: Property with NULL key defined"); - } - else - { - buf.append('\n'); - buf.append(valueAsXML(table._propertyNamesTypeMap.get(propertyName) + propertyName, entry.getValue())); - } + buf.append('\n'); + buf.append(valueAsXML(table._propertyNamesTypeMap.get(propertyName), propertyName, entry.getValue())); } buf.append("\n"); buf.append(PROPERTY_FIELD_TABLE_CLOSE_XML); @@ -481,18 +540,14 @@ public class PropertyFieldTable implements FieldTable, Map return buf.toString(); } - private static String valueAsXML(String name, Object value) + private static String valueAsXML(Prefix type, String propertyName, Object value) { - char propertyPrefix = name.charAt(0); - String propertyName = name.substring(1); - - StringBuffer buf = new StringBuffer(); // Start Tag - buf.append(propertyXML(name, true)); + buf.append(propertyXML(type, propertyName, true)); // Value - if (propertyPrefix == BYTES_PROPERTY_PREFIX) + if (type.equals(Prefix.AMQP_BINARY_PROPERTY_PREFIX)) { //remove '>' buf.deleteCharAt(buf.length() - 1); @@ -504,22 +559,19 @@ public class PropertyFieldTable implements FieldTable, Map } else { - buf.append(String.valueOf(value)); + if (!type.equals(Prefix.AMQP_NULL_STRING_PROPERTY_PREFIX)) + { + buf.append(String.valueOf(value)); + } } - //End Tag - buf.append(propertyXML(name, false)); + buf.append(propertyXML(type, propertyName, false)); return buf.toString(); } - private Object checkPropertyName(String name) + private void checkPropertyName(String propertyName) { - 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"); @@ -529,34 +581,39 @@ public class PropertyFieldTable implements FieldTable, Map throw new IllegalArgumentException("Property name must not be the empty string"); } - String currentValue = _propertyNamesTypeMap.get(propertyName); + checkIdentiferFormat(propertyName); + } - if (currentValue != null) - { - 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); - } + protected static void checkIdentiferFormat(String propertyName) + { +// AMQP Spec: 4.2.5.5 Field Tables +// Guidelines for implementers: +// * Field names MUST start with a letter, '$' or '#' and may continue with +// letters, '$' or '#', digits, or underlines, to a maximum length of 128 +// characters. +// * The server SHOULD validate field names and upon receiving an invalid +// field name, it SHOULD signal a connection exception with reply code +// 503 (syntax error). Conformance test: amq_wlp_table_01. +// * A peer MUST handle duplicate fields by using only the first instance. - // 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); + // AMQP length limit + if (propertyName.length() > 128) + { + throw new IllegalArgumentException("AMQP limits property names to 128 characters"); } - _propertyNamesTypeMap.put(propertyName, "" + propertyPrefix); - - return previous; + // AMQ start character + if (!(Character.isLetter(propertyName.charAt(0)) + || propertyName.charAt(0) == '$' + || propertyName.charAt(0) == '#')) + { + throw new IllegalArgumentException("Identifier '" + propertyName + "' does not start with a valid AMQP start character"); + } } - private static String propertyXML(String name, boolean start) + private static String propertyXML(Prefix type, String propertyName, boolean start) { - char propertyPrefix = name.charAt(0); - String propertyName = name.substring(1); - StringBuffer buf = new StringBuffer(); if (start) @@ -568,40 +625,44 @@ public class PropertyFieldTable implements FieldTable, Map buf.append("</"); } - switch (propertyPrefix) + switch (type) { - case BOOLEAN_PROPERTY_PREFIX: + case AMQP_BOOLEAN_PROPERTY_PREFIX: buf.append(BOOLEAN); break; - case BYTE_PROPERTY_PREFIX: + case AMQP_BYTE_PROPERTY_PREFIX: buf.append(BYTE); break; - case BYTES_PROPERTY_PREFIX: + case AMQP_BINARY_PROPERTY_PREFIX: buf.append(BYTES); break; - case SHORT_PROPERTY_PREFIX: + case AMQP_SHORT_PROPERTY_PREFIX: buf.append(SHORT); break; - case INT_PROPERTY_PREFIX: + case AMQP_INT_PROPERTY_PREFIX: buf.append(INT); break; - case LONG_PROPERTY_PREFIX: + case AMQP_LONG_PROPERTY_PREFIX: buf.append(LONG); break; - case FLOAT_PROPERTY_PREFIX: + case AMQP_FLOAT_PROPERTY_PREFIX: buf.append(FLOAT); break; - case DOUBLE_PROPERTY_PREFIX: + case AMQP_DOUBLE_PROPERTY_PREFIX: buf.append(DOUBLE); break; - case STRING_PROPERTY_PREFIX: + case AMQP_NULL_STRING_PROPERTY_PREFIX: + buf.append(NULL_STRING); + break; + case AMQP_ASCII_STRING_PROPERTY_PREFIX: + case AMQP_WIDE_STRING_PROPERTY_PREFIX: buf.append(STRING); break; - case CHAR_PROPERTY_PREFIX: + case AMQP_ASCII_CHARACTER_PROPERTY_PREFIX: buf.append(CHAR); break; default: - buf.append(UNKNOWN + " (identifier ").append(propertyPrefix).append(")"); + buf.append(UNKNOWN + " (identifier ").append(type.identifier()).append(")"); break; } @@ -622,9 +683,9 @@ public class PropertyFieldTable implements FieldTable, Map for (int index = 0; index < bytes.length; index++) { buf.append("\n"); - buf.append(propertyXML(BYTE_PROPERTY_PREFIX + propertyName + "[" + index + "]", true)); + buf.append(propertyXML(Prefix.AMQP_BYTE_PROPERTY_PREFIX, propertyName + "[" + index + "]", true)); buf.append(bytes[index]); - buf.append(propertyXML(BYTE_PROPERTY_PREFIX + propertyName + "[" + index + "]", false)); + buf.append(propertyXML(Prefix.AMQP_BYTE_PROPERTY_PREFIX, propertyName + "[" + index + "]", false)); } buf.append("\n"); return buf.toString(); @@ -648,16 +709,26 @@ public class PropertyFieldTable implements FieldTable, Map { StringTokenizer tokenizer = new StringTokenizer(textFormat, "\n"); + boolean finished = false; boolean processing = false; boolean processing_bytes = false; + if (!tokenizer.hasMoreTokens()) + { + throw new IllegalArgumentException("XML has no tokens to parse."); + } + while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); - if (token.equals(PROPERTY_FIELD_TABLE_CLOSE_XML) - || token.equals(BYTES_CLOSE_XML)) + if (token.equals(PROPERTY_FIELD_TABLE_CLOSE_XML)) + { + processing = false; + finished = true; + } + if (token.equals(BYTES_CLOSE_XML)) { processing = false; } @@ -688,6 +759,12 @@ public class PropertyFieldTable implements FieldTable, Map processing = true; } } + + if (!finished) + { + throw new IllegalArgumentException("XML was not in a valid format."); + } + } private void processXMLLine(String xmlline) @@ -735,6 +812,7 @@ public class PropertyFieldTable implements FieldTable, Map int byteStart = xmlline.indexOf('<', headerEnd); + //Don't think this is required. if (byteStart > 0) { while (!xmlline.startsWith(BYTES_CLOSE_XML, byteStart)) @@ -772,8 +850,12 @@ public class PropertyFieldTable implements FieldTable, Map { setDouble(propertyName, Double.parseDouble(value)); } - if (type.equals(STRING)) + if (type.equals(STRING) || type.equals(NULL_STRING)) { + if (type.equals(NULL_STRING)) + { + value = null; + } setString(propertyName, value); } if (type.equals(CHAR)) @@ -782,7 +864,7 @@ public class PropertyFieldTable implements FieldTable, Map } if (type.equals(UNKNOWN)) { - _logger.error("Ignoring unknown property value:" + xmlline); + _logger.warn("Ignoring unknown property value:" + xmlline); } } @@ -790,11 +872,11 @@ public class PropertyFieldTable implements FieldTable, Map public void writeToBuffer(ByteBuffer buffer) { - final boolean debug = _logger.isDebugEnabled(); + final boolean trace = _logger.isTraceEnabled(); - if (debug) + if (trace) { - _logger.debug("FieldTable::writeToBuffer: Writing encoded size of " + _encodedSize + "..."); + _logger.trace("FieldTable::writeToBuffer: Writing encoded size of " + _encodedSize + "..."); } EncodingUtils.writeUnsignedInteger(buffer, _encodedSize); @@ -847,53 +929,57 @@ public class PropertyFieldTable implements FieldTable, Map return setObject(key.toString(), value); } - protected Object put(String key, Object value) + protected Object put(Prefix type, String propertyName, Object value) { - Object previous = checkPropertyName(key); + checkPropertyName(propertyName); + //remove the previous value + Object previous = remove(propertyName); - String propertyName = key.substring(1); - char propertyPrefix = _propertyNamesTypeMap.get(propertyName).charAt(0); - if (value != null) + if (_logger.isTraceEnabled()) { - //Add the size of the propertyName - _encodedSize += EncodingUtils.encodedShortStringLength(propertyName); + int valueSize = 0; + if (value != null) + { + valueSize = getEncodingSize(type, value); + } + _logger.trace("Put:" + propertyName + + " encoding size Now:" + _encodedSize + + " name size= " + EncodingUtils.encodedShortStringLength(propertyName) + + " value size= " + valueSize); + } - // 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 propertyName plus one for the type identifier + _encodedSize += EncodingUtils.encodedShortStringLength(propertyName) + 1; + if (value != null) + { //Add the size of the content - _encodedSize += getEncodingSize(key, value); + _encodedSize += getEncodingSize(type, value); } - _properties.put((String) propertyName, value); + //Store new values + _propertyNamesTypeMap.put(propertyName, type); + _properties.put(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); + Prefix type = _propertyNamesTypeMap.remove(key); // plus one for the type - _encodedSize -= EncodingUtils.encodedShortStringLength(((String) key)); + _encodedSize -= EncodingUtils.encodedShortStringLength(((String) key)) + 1; // This check is, for now, unnecessary (we don't store null values). if (value != null) { - _encodedSize -= getEncodingSize(propertyPrefix + (String) key, value); + _encodedSize -= getEncodingSize(type, value); } - return value; } else @@ -915,6 +1001,7 @@ public class PropertyFieldTable implements FieldTable, Map public void clear() { + _encodedSize = 0; _properties.clear(); _propertyNamesTypeMap.clear(); } @@ -942,6 +1029,7 @@ public class PropertyFieldTable implements FieldTable, Map 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 @@ -954,42 +1042,97 @@ public class PropertyFieldTable implements FieldTable, Map String propertyName = (String) me.getKey(); //The type value - char propertyPrefix = _propertyNamesTypeMap.get(propertyName).charAt(0); - //The actual param name skipping type + Prefix type = _propertyNamesTypeMap.get(propertyName); - EncodingUtils.writeShortStringBytes(buffer, propertyName); Object value = me.getValue(); - - switch (propertyPrefix) + try { + if (_logger.isTraceEnabled()) + { + _logger.trace("Writing Property:" + propertyName + + " Type:" + type + + " Value:" + value); + _logger.trace("Buffer Position:" + buffer.position() + + " Remaining:" + buffer.remaining()); + } - case STRING_PROPERTY_PREFIX: - // TODO: look at using proper charset encoder - buffer.put((byte) STRING_PROPERTY_PREFIX); - EncodingUtils.writeLongStringBytes(buffer, (String) value); - break; + //Write the actual parameter name + EncodingUtils.writeShortStringBytes(buffer, propertyName); - 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: + switch (type) { - - // Should never get here - throw new IllegalArgumentException("Key '" + propertyName + "': Unsupported type in field table, type: " + ((value == null) ? "null-object" : value.getClass())); + case AMQP_BOOLEAN_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_BOOLEAN_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeBoolean(buffer, (Boolean) value); + break; + case AMQP_BYTE_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_BYTE_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeByte(buffer, (Byte) value); + break; + case AMQP_SHORT_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_SHORT_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeShort(buffer, (Short) value); + break; + case AMQP_INT_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_INT_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeInteger(buffer, (Integer) value); + break; + case AMQP_UNSIGNED_INT_PROPERTY_PREFIX: // Currently we don't create these + buffer.put((byte) Prefix.AMQP_UNSIGNED_INT_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeUnsignedInteger(buffer, (Long) value); + break; + case AMQP_LONG_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_LONG_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeLong(buffer, (Long) value); + break; + case AMQP_FLOAT_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_FLOAT_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeFloat(buffer, (Float) value); + break; + case AMQP_DOUBLE_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_DOUBLE_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeDouble(buffer, (Double) value); + break; + case AMQP_NULL_STRING_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_NULL_STRING_PROPERTY_PREFIX.identifier()); + break; + case AMQP_WIDE_STRING_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_WIDE_STRING_PROPERTY_PREFIX.identifier()); + // FIXME: use proper charset encoder + EncodingUtils.writeLongStringBytes(buffer, (String) value); + break; + case AMQP_ASCII_STRING_PROPERTY_PREFIX: + //This is a simple ASCII string + buffer.put((byte) Prefix.AMQP_ASCII_STRING_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeLongStringBytes(buffer, (String) value); + break; + case AMQP_ASCII_CHARACTER_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_ASCII_CHARACTER_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeChar(buffer, (Character) value); + break; + case AMQP_BINARY_PROPERTY_PREFIX: + buffer.put((byte) Prefix.AMQP_BINARY_PROPERTY_PREFIX.identifier()); + EncodingUtils.writeBytes(buffer, (byte[]) value); + break; + default: + { + // Should never get here + throw new IllegalArgumentException("Key '" + propertyName + "': Unsupported type in field table, type: " + ((value == null) ? "null-object" : value.getClass())); + } + } + } + catch (Exception e) + { + if (_logger.isTraceEnabled()) + { + _logger.trace("Exception thrown:" + e); + _logger.trace("Writing Property:" + propertyName + + " Type:" + type + + " Value:" + value); + _logger.trace("Buffer Position:" + buffer.position() + + " Remaining:" + buffer.remaining()); } + throw new RuntimeException(e); } } } @@ -997,100 +1140,141 @@ public class PropertyFieldTable implements FieldTable, Map public void setFromBuffer(ByteBuffer buffer, long length) throws AMQFrameDecodingException { - final boolean debug = _logger.isDebugEnabled(); + final boolean trace = _logger.isTraceEnabled(); 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; + + Character mapKey = new Character((char) iType); + Prefix type = _reverseTypeMap.get(mapKey); + + if (type == null) + { + String msg = "Field '" + key + "' - unsupported field table type: " + type + "."; + //some extra trace information... + msg += " (" + iType + "), length=" + length + ", sizeRead=" + sizeRead + ", sizeRemaining=" + sizeRemaining; + throw new AMQFrameDecodingException(msg); + } + Object value; switch (type) { - case STRING_PROPERTY_PREFIX: + case AMQP_BOOLEAN_PROPERTY_PREFIX: + value = EncodingUtils.readBoolean(buffer); + break; + case AMQP_BYTE_PROPERTY_PREFIX: + value = EncodingUtils.readByte(buffer); + break; + case AMQP_SHORT_PROPERTY_PREFIX: + value = EncodingUtils.readShort(buffer); + break; + case AMQP_INT_PROPERTY_PREFIX: + value = EncodingUtils.readInteger(buffer); + break; + case AMQP_UNSIGNED_INT_PROPERTY_PREFIX:// This will only fit in a long + //Change this type for java lookups + type = Prefix.AMQP_LONG_PROPERTY_PREFIX; + case AMQP_LONG_PROPERTY_PREFIX: + value = EncodingUtils.readLong(buffer); + break; + case AMQP_FLOAT_PROPERTY_PREFIX: + value = EncodingUtils.readFloat(buffer); + break; + case AMQP_DOUBLE_PROPERTY_PREFIX: + value = EncodingUtils.readDouble(buffer); + break; + case AMQP_WIDE_STRING_PROPERTY_PREFIX: + // FIXME: use proper charset encoder + case AMQP_ASCII_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)); + case AMQP_NULL_STRING_PROPERTY_PREFIX: + value = null; + break; + case AMQP_ASCII_CHARACTER_PROPERTY_PREFIX: + value = EncodingUtils.readChar((buffer)); + break; + case AMQP_BINARY_PROPERTY_PREFIX: + value = EncodingUtils.readBytes(buffer); break; default: - String msg = "Field '" + key + "' - unsupported field table type: " + type + "."; - //some extra debug information... - msg += " (" + iType + "), length=" + length + ", sizeRead=" + sizeRead + ", sizeRemaining=" + sizeRemaining; + String msg = "Internal error, the following type identifier is not handled: " + type; throw new AMQFrameDecodingException(msg); } sizeRead += (sizeRemaining - buffer.remaining()); - if (debug) + if (trace) { - _logger.debug("FieldTable::PropFieldTable(buffer," + length + "): Read type '" + type + "', key '" + key + "', value '" + value + "' (now read " + sizeRead + " of " + length + " encoded bytes)..."); + _logger.trace("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); - } + put(type, key, value); } - if (debug) + if (trace) { - _logger.debug("FieldTable::FieldTable(buffer," + length + "): Done."); + _logger.trace("FieldTable::FieldTable(buffer," + length + "): Done."); } } - /** - * @param name the property name with type prefix + * @param type the type to calucluate encoding for * @param value the property value * @return integer */ - private static int getEncodingSize(String name, Object value) + private static int getEncodingSize(Prefix type, Object value) { - int encodingSize; - - char propertyPrefix = name.charAt(0); + int encodingSize = 0; - switch (propertyPrefix) + switch (type) { - // the extra byte if for the type indicator that is written out - case STRING_PROPERTY_PREFIX: - encodingSize = 1 + EncodingUtils.encodedLongStringLength((String) value); + case AMQP_BOOLEAN_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedBooleanLength(); + break; + case AMQP_BYTE_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedByteLength(); + break; + case AMQP_SHORT_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedShortLength(); + break; + case AMQP_INT_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedIntegerLength(); + break; + case AMQP_LONG_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedLongLength(); 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)); + case AMQP_FLOAT_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedFloatLength(); + break; + case AMQP_DOUBLE_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedDoubleLength(); + break; + case AMQP_WIDE_STRING_PROPERTY_PREFIX: + // FIXME: use proper charset encoder + case AMQP_ASCII_STRING_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedLongStringLength((String) value); + break; +// This is not required as this method is never called if the value is null +// case AMQP_NULL_STRING_PROPERTY_PREFIX: +// // There is no need for additional size beyond the prefix +// break; + case AMQP_ASCII_CHARACTER_PROPERTY_PREFIX: + encodingSize = EncodingUtils.encodedCharLength(); + break; + case AMQP_BINARY_PROPERTY_PREFIX: + encodingSize = 1 + ((byte[]) value).length; 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 + // the extra byte for the type indicator is calculated in the name return encodingSize; } - - } diff --git a/java/common/src/main/java/org/apache/qpid/pool/Event.java b/java/common/src/main/java/org/apache/qpid/pool/Event.java index 71ab6e7863..7364b9293a 100644 --- a/java/common/src/main/java/org/apache/qpid/pool/Event.java +++ b/java/common/src/main/java/org/apache/qpid/pool/Event.java @@ -109,6 +109,6 @@ class Event public String toString() { - return "Event: type " + type + ", data: " + data; + return "Event: type " + type + ", data: " + data; } } diff --git a/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java b/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java index ba614a26c2..38cfa68c78 100644 --- a/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java +++ b/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java @@ -58,7 +58,10 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH Job job = getJobForSession(session); job.acquire(); //prevents this job being removed from _jobs job.add(event); - if (job.activate()) + + //Additional checks on pool to check that it hasn't shutdown. + // The alternative is to catch the RejectedExecutionException that will result from executing on a shutdown pool + if (job.activate() && _poolReference.getPool() != null && !_poolReference.getPool().isShutdown()) { _poolReference.getPool().execute(job); } @@ -100,7 +103,9 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH } else { - if (job.activate()) + // ritchiem : 2006-12-13 Do we need to perform the additional checks here? + // Can the pool be shutdown at this point? + if (job.activate() && _poolReference.getPool() != null && !_poolReference.getPool().isShutdown()) { _poolReference.getPool().execute(job); } @@ -184,3 +189,4 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH _poolReference.releaseExecutorService(); } } + diff --git a/java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java b/java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java index fc83c0726d..a0d243ca30 100644 --- a/java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java +++ b/java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java @@ -55,7 +55,7 @@ public final class AMQConstant { return _name; } - + public static final AMQConstant FRAME_MIN_SIZE = new AMQConstant(4096, "frame min size", true); public static final AMQConstant FRAME_END = new AMQConstant(206, "frame end", true); @@ -74,6 +74,8 @@ public final class AMQConstant public static final AMQConstant CONTEXT_UNKNOWN = new AMQConstant(321, "context unknown", true); + public static final AMQConstant INVALID_SELECTOR = new AMQConstant(322, "selector invalid", true); + public static final AMQConstant INVALID_PATH = new AMQConstant(402, "invalid path", true); public static final AMQConstant ACCESS_REFUSED = new AMQConstant(403, "access refused", true); diff --git a/java/common/src/main/java/org/apache/qpid/url/URLHelper.java b/java/common/src/main/java/org/apache/qpid/url/URLHelper.java index f8c621e413..2121346c02 100644 --- a/java/common/src/main/java/org/apache/qpid/url/URLHelper.java +++ b/java/common/src/main/java/org/apache/qpid/url/URLHelper.java @@ -64,9 +64,9 @@ public class URLHelper if (valueIndex + 1 < options.length()) { if (options.charAt(valueIndex + 1) == DEFAULT_OPTION_SEPERATOR || - options.charAt(valueIndex + 1) == ALTERNATIVE_OPTION_SEPARATOR || - options.charAt(valueIndex + 1) == BROKER_SEPARATOR || - options.charAt(valueIndex + 1) == '\'') + options.charAt(valueIndex + 1) == ALTERNATIVE_OPTION_SEPARATOR || + options.charAt(valueIndex + 1) == BROKER_SEPARATOR || + options.charAt(valueIndex + 1) == '\'') { nestedQuotes--; // System.out.println( @@ -119,7 +119,7 @@ public class URLHelper else { parseError(sepIndex, "Unterminated option. Possible illegal option separator:'" + - options.charAt(sepIndex) + "'", options); + options.charAt(sepIndex) + "'", options); } } diff --git a/java/common/src/main/java/org/apache/qpid/url/URLSyntaxException.java b/java/common/src/main/java/org/apache/qpid/url/URLSyntaxException.java index 5cac2505a8..3ff7195794 100644 --- a/java/common/src/main/java/org/apache/qpid/url/URLSyntaxException.java +++ b/java/common/src/main/java/org/apache/qpid/url/URLSyntaxException.java @@ -62,12 +62,12 @@ public class URLSyntaxException extends URISyntaxException if (getIndex() > -1) { - if (_length > 1) + if (_length != -1) { sb.append(" between indicies "); sb.append(getIndex()); sb.append(" and "); - sb.append(getIndex() + _length); + sb.append(_length); } else { diff --git a/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java b/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java new file mode 100644 index 0000000000..66dd1b10ef --- /dev/null +++ b/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java @@ -0,0 +1,192 @@ +/* + * + * 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; + +import java.util.HashMap; + +import junit.framework.TestCase; + + +public class BasicContentHeaderPropertiesTest extends TestCase +{ + + BasicContentHeaderProperties _testProperties; + PropertyFieldTable _testTable; + String _testString = "This is a test string"; + int _testint = 666; + + /** + * Currently only test setting/getting String, int and boolean props + */ + public BasicContentHeaderPropertiesTest() + { + _testProperties = new BasicContentHeaderProperties(); + } + + public void setUp() + { + HashMap _testMap = new HashMap(10); + _testMap.put("TestString", _testString); + _testMap.put("Testint", _testint); + _testTable = new PropertyFieldTable(); + _testTable.putAll(_testMap); + _testProperties = new BasicContentHeaderProperties(); + _testProperties.setHeaders(_testTable); + } + + public void testGetPropertyListSize() + { + //needs a better test but at least we're exercising the code ! + // FT size is encoded in an int + int expectedSize = EncodingUtils.encodedIntegerLength(); + + expectedSize += EncodingUtils.encodedShortStringLength("TestInt"); + // 1 is for the Encoding Letter. here an 'i' + expectedSize += 1 + EncodingUtils.encodedIntegerLength(); + + expectedSize += EncodingUtils.encodedShortStringLength("TestString"); + // 1 is for the Encoding Letter. here an 'S' + expectedSize += 1 + EncodingUtils.encodedLongStringLength(_testString); + + + int size = _testProperties.getPropertyListSize(); + + assertEquals(expectedSize, size); + } + + public void testGetSetPropertyFlags() + { + _testProperties.setPropertyFlags(99); + assertEquals(99, _testProperties.getPropertyFlags()); + } + + public void testWritePropertyListPayload() + { + ByteBuffer buf = ByteBuffer.allocate(300); + _testProperties.writePropertyListPayload(buf); + } + + public void testPopulatePropertiesFromBuffer() throws Exception + { + ByteBuffer buf = ByteBuffer.allocate(300); + _testProperties.populatePropertiesFromBuffer(buf, 99, 99); + } + + public void testSetGetContentType() + { + String contentType = "contentType"; + _testProperties.setContentType(contentType); + assertEquals(contentType, _testProperties.getContentType()); + } + + public void testSetGetEncoding() + { + String encoding = "encoding"; + _testProperties.setEncoding(encoding); + assertEquals(encoding, _testProperties.getEncoding()); + } + + public void testSetGetHeaders() + { + _testProperties.setHeaders(_testTable); + assertEquals(_testTable, _testProperties.getHeaders()); + } + + public void testSetGetDeliveryMode() + { + byte deliveryMode = 1; + _testProperties.setDeliveryMode(deliveryMode); + assertEquals(deliveryMode, _testProperties.getDeliveryMode()); + } + + public void testSetGetPriority() + { + byte priority = 1; + _testProperties.setPriority(priority); + assertEquals(priority, _testProperties.getPriority()); + } + + public void testSetGetCorrelationId() + { + String correlationId = "correlationId"; + _testProperties.setCorrelationId(correlationId); + assertEquals(correlationId, _testProperties.getCorrelationId()); + } + + public void testSetGetReplyTo() + { + String replyTo = "replyTo"; + _testProperties.setReplyTo(replyTo); + assertEquals(replyTo, _testProperties.getReplyTo()); + } + + public void testSetGetExpiration() + { + long expiration = 999999999; + _testProperties.setExpiration(expiration); + assertEquals(expiration, _testProperties.getExpiration()); + } + + public void testSetGetMessageId() + { + String messageId = "messageId"; + _testProperties.setMessageId(messageId); + assertEquals(messageId, _testProperties.getMessageId()); + } + + public void testSetGetTimestamp() + { + long timestamp = 999999999; + _testProperties.setTimestamp(timestamp); + assertEquals(timestamp, _testProperties.getTimestamp()); + } + + public void testSetGetType() + { + String type = "type"; + _testProperties.setType(type); + assertEquals(type, _testProperties.getType()); + } + + public void testSetGetUserId() + { + String userId = "userId"; + _testProperties.setUserId(userId); + assertEquals(userId, _testProperties.getUserId()); + } + + public void testSetGetAppId() + { + String appId = "appId"; + _testProperties.setAppId(appId); + assertEquals(appId, _testProperties.getAppId()); + } + + public void testSetGetClusterId() + { + String clusterId = "clusterId"; + _testProperties.setClusterId(clusterId); + assertEquals(clusterId, _testProperties.getClusterId()); + } + +} diff --git a/java/common/src/test/java/org/apache/qpid/framing/JMSPropertyFieldTableTest.java b/java/common/src/test/java/org/apache/qpid/framing/JMSPropertyFieldTableTest.java new file mode 100644 index 0000000000..865735499b --- /dev/null +++ b/java/common/src/test/java/org/apache/qpid/framing/JMSPropertyFieldTableTest.java @@ -0,0 +1,1020 @@ +/* + * 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 junit.framework.Assert; +import junit.framework.TestCase; + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; + +import org.apache.mina.common.ByteBuffer; +import org.apache.log4j.Logger; + +import javax.jms.JMSException; +import javax.jms.MessageFormatException; + +public class JMSPropertyFieldTableTest extends TestCase +{ + + private static final Logger _logger = Logger.getLogger(JMSPropertyFieldTableTest.class); + + + public void setUp() + { + System.getProperties().setProperty("strict-jms", "true"); + } + + public void tearDown() + { + System.getProperties().remove("strict-jms"); + } + + /** + * Test that setting a similar named value replaces any previous value set on that name + */ + public void testReplacement() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + //Set a boolean value + table1.setBoolean("value", true); + + // reset value to an integer + table1.setInteger("value", Integer.MAX_VALUE); + + //Check boolean value is null + try + { + table1.getBoolean("value"); + } + catch (MessageFormatException mfe) + { + //normal execution + } + // ... and integer value is good + Assert.assertEquals(Integer.MAX_VALUE, table1.getInteger("value")); + } + + public void testRemoval() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + //Set a boolean value + table1.setBoolean("value", true); + + Assert.assertTrue(table1.getBoolean("value")); + + table1.remove("value"); + + //Check boolean value is null + try + { + table1.getBoolean("value"); + } + catch (MessageFormatException mfe) + { + //normal execution + } + } + + + /** + * Set a boolean and check that we can only get it back as a boolean and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testBoolean() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + table1.setBoolean("value", true); + Assert.assertTrue(table1.propertyExists("value")); + + //Test Getting right value back + Assert.assertEquals(true, table1.getBoolean("value")); + + //Check we don't get anything back for other gets + try + { + table1.getByte("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + try + { + table1.getByte("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + try + { + table1.getShort("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + try + { + table1.getDouble("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + try + { + table1.getFloat("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + try + { + table1.getInteger("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + try + { + table1.getLong("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + //except value as a string + Assert.assertEquals("true", table1.getString("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.propertyExists("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value will return false + Assert.assertFalse(table1.getBoolean("Rubbish")); + } + + /** + * Set a byte and check that we can only get it back as a byte and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testByte() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + table1.setByte("value", Byte.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + try + { + table1.getBoolean("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + try + { + table1.getDouble("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getFloat("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + Assert.assertEquals(Byte.MAX_VALUE, (byte) table1.getShort("value")); + Assert.assertEquals(Byte.MAX_VALUE, (byte) table1.getInteger("value")); + Assert.assertEquals(Byte.MAX_VALUE, (byte) table1.getLong("value")); + Assert.assertEquals(Byte.MAX_VALUE, table1.getByte("value")); + //... and a the string value of it. + Assert.assertEquals("" + Byte.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.propertyExists("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + try + { + table1.getByte("Rubbish"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException mfs) + { + //normal Execution + } + + } + + + /** + * Set a short and check that we can only get it back as a short and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testShort() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + table1.setShort("value", Short.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + + try + { + table1.getBoolean("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getByte("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + try + { + table1.getDouble("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getFloat("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + + Assert.assertEquals(Short.MAX_VALUE, (short) table1.getLong("value")); + Assert.assertEquals(Short.MAX_VALUE, (short) table1.getInteger("value")); + Assert.assertEquals(Short.MAX_VALUE, table1.getShort("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Short.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.propertyExists("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + try + { + table1.getShort("Rubbish"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException mfe) + { + //normal path + } + } + + + /** + * Set a double and check that we can only get it back as a double + * Check that attempting to lookup a non existent value returns null + */ + public void testDouble() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + table1.setDouble("value", Double.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + try + { + table1.getBoolean("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getByte("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getShort("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getFloat("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getInteger("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getLong("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + Assert.assertEquals(Double.MAX_VALUE, table1.getDouble("value")); + //... and a the string value of it. + Assert.assertEquals("" + Double.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.propertyExists("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + try + { + table1.getDouble("Rubbish"); + fail("Should throw NullPointerException as float.valueOf will try sunreadJavaFormatString"); + } + catch (NullPointerException mfe) + { + //normal path + } + + } + + + /** + * Set a float and check that we can only get it back as a float + * Check that attempting to lookup a non existent value returns null + */ + public void testFloat() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + table1.setFloat("value", Float.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + try + { + table1.getBoolean("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getByte("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getShort("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getInteger("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getLong("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + + Assert.assertEquals(Float.MAX_VALUE, table1.getFloat("value")); + Assert.assertEquals(Float.MAX_VALUE, (float) table1.getDouble("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Float.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.propertyExists("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + try + { + table1.getFloat("Rubbish"); + fail("Should throw NullPointerException as float.valueOf will try sunreadJavaFormatString"); + } + catch (NullPointerException mfe) + { + //normal path + } + } + + + /** + * Set an int and check that we can only get it back as an int + * Check that attempting to lookup a non existent value returns null + */ + public void testInt() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + table1.setInteger("value", Integer.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + try + { + table1.getBoolean("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getByte("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getShort("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getDouble("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getFloat("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + + Assert.assertEquals(Integer.MAX_VALUE, table1.getLong("value")); + + Assert.assertEquals(Integer.MAX_VALUE, table1.getInteger("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Integer.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.propertyExists("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + try + { + table1.getInteger("Rubbish"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException mfe) + { + //normal path + } + } + + + /** + * Set a long and check that we can only get it back as a long + * Check that attempting to lookup a non existent value returns null + */ + public void testLong() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + table1.setLong("value", Long.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + try + { + table1.getBoolean("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getByte("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getShort("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getDouble("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getFloat("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + try + { + table1.getInteger("value"); + fail("Should throw MessageFormatException"); + } + catch (MessageFormatException mfs) + { + //normal Execution + } + + + Assert.assertEquals(Long.MAX_VALUE, table1.getLong("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Long.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.propertyExists("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value + try + { + table1.getLong("Rubbish"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException mfs) + { + //normal Execution + } + + } + + + /** + * Calls all methods that can be used to check the table is empty + * - getEncodedSize + * - isEmpty + * - size + * + * @param table to check is empty + */ + private void checkEmpty(JMSPropertyFieldTable table) + { + Assert.assertFalse(table.getPropertyNames().hasMoreElements()); + } + + + /** + * Set a String and check that we can only get it back as a String + * Check that attempting to lookup a non existent value returns null + */ + public void testString() throws JMSException + { + JMSPropertyFieldTable table1 = new JMSPropertyFieldTable(); + table1.setString("value", "Hello"); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(false, table1.getBoolean("value")); + + try + { + table1.getByte("value"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException nfs) + { + //normal Execution + } + try + { + table1.getShort("value"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException nfs) + { + //normal Execution + } + try + { + table1.getDouble("value"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException nfs) + { + //normal Execution + } + try + { + table1.getFloat("value"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException nfs) + { + //normal Execution + } + try + { + table1.getInteger("value"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException nfs) + { + //normal Execution + } + try + { + table1.getLong("value"); + fail("Should throw NumberFormatException"); + } + catch (NumberFormatException nfs) + { + //normal Execution + } + + Assert.assertEquals("Hello", table1.getString("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.propertyExists("value")); + + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getString("Rubbish")); + + //Additional Test that haven't been covered for string + table1.setObject("value", "Hello"); + //Check that it was set correctly + Assert.assertEquals("Hello", table1.getString("value")); + } + + + public void testValues() throws JMSException + { + JMSPropertyFieldTable table = new JMSPropertyFieldTable(); + table.setBoolean("bool", true); + 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); + table.setString("string", "Hello"); + table.setString("nullstring", null); + + table.setObject("objectbool", true); + table.setObject("objectdouble", Double.MAX_VALUE); + table.setObject("objectfloat", Float.MAX_VALUE); + table.setObject("objectint", Integer.MAX_VALUE); + table.setObject("objectlong", Long.MAX_VALUE); + table.setObject("objectshort", Short.MAX_VALUE); + table.setObject("objectstring", "Hello"); + + + Assert.assertEquals(true, table.getBoolean("bool")); + + Assert.assertEquals(Double.MAX_VALUE, table.getDouble("double")); + Assert.assertEquals(Float.MAX_VALUE, table.getFloat("float")); + Assert.assertEquals(Integer.MAX_VALUE, table.getInteger("int")); + Assert.assertEquals(Long.MAX_VALUE, table.getLong("long")); + Assert.assertEquals(Short.MAX_VALUE, table.getShort("short")); + Assert.assertEquals("Hello", table.getString("string")); + Assert.assertEquals(null, table.getString("null-string")); + + Assert.assertEquals(true, table.getObject("objectbool")); + Assert.assertEquals(Double.MAX_VALUE, table.getObject("objectdouble")); + Assert.assertEquals(Float.MAX_VALUE, table.getObject("objectfloat")); + Assert.assertEquals(Integer.MAX_VALUE, table.getObject("objectint")); + Assert.assertEquals(Long.MAX_VALUE, table.getObject("objectlong")); + Assert.assertEquals(Short.MAX_VALUE, table.getObject("objectshort")); + Assert.assertEquals("Hello", table.getObject("objectstring")); + } + + /** + * Additional test checkPropertyName doesn't accept Null + */ + public void testCheckPropertyNameasNull() throws JMSException + { + JMSPropertyFieldTable table = new JMSPropertyFieldTable(); + + try + { + table.setObject(null, "String"); + fail("Null property name is not allowed"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + checkEmpty(table); + } + + + /** + * Additional test checkPropertyName doesn't accept an empty String + */ + public void testCheckPropertyNameasEmptyString() throws JMSException + { + JMSPropertyFieldTable table = new JMSPropertyFieldTable(); + + try + { + table.setObject("", "String"); + fail("empty property name is not allowed"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + checkEmpty(table); + } + + + /** + * Additional test checkPropertyName doesn't accept an empty String + */ + public void testCheckPropertyNamehasMaxLength() throws JMSException + { + JMSPropertyFieldTable table = new JMSPropertyFieldTable(); + + StringBuffer longPropertyName = new StringBuffer(129); + + for (int i = 0; i < 129; i++) + { + longPropertyName.append("x"); + } + + try + { + table.setObject(longPropertyName.toString(), "String"); + fail("property name must be < 128 characters"); + } + catch (IllegalArgumentException iae) + { + _logger.warn("JMS requires infinite property names AMQP limits us to 128 characters"); + } + + checkEmpty(table); + } + + + /** + * Additional test checkPropertyName starts with a letter + */ + public void testCheckPropertyNameStartCharacterIsLetter() throws JMSException + { + JMSPropertyFieldTable table = new JMSPropertyFieldTable(); + + //Try a name that starts with a number + try + { + table.setObject("1", "String"); + fail("property name must start with a letter"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + + checkEmpty(table); + } + + /** + * Additional test checkPropertyName starts with a letter + */ + public void testCheckPropertyNameContainsInvalidCharacter() throws JMSException + { + JMSPropertyFieldTable table = new JMSPropertyFieldTable(); + + //Try a name that starts with a number + try + { + table.setObject("hello there", "String"); + fail("property name cannot contain spaces"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + + checkEmpty(table); + } + + + /** + * Additional test checkPropertyName starts with a letter + */ + public void testCheckPropertyNameIsInvalid() throws JMSException + { + JMSPropertyFieldTable table = new JMSPropertyFieldTable(); + + //Try a name that starts with a number + try + { + table.setObject("ESCAPE", "String"); + fail("property name must not contains spaces"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + + checkEmpty(table); + } + + /** + * Additional test checkPropertyName starts with a hash or a dollar + */ + public void testCheckPropertyNameStartCharacterIsHashorDollar() throws JMSException + { + _logger.warn("Test:testCheckPropertyNameStartCharacterIsHashorDollar will fail JMS compilance as # and $ are not valid in a jms identifier"); +// JMSPropertyFieldTable table = new JMSPropertyFieldTable(); +// +// //Try a name that starts with a number +// try +// { +// table.setObject("#", "String"); +// table.setObject("$", "String"); +// } +// catch (IllegalArgumentException iae) +// { +// fail("property name are allowed to start with # and $s in AMQP"); +// } + } + + /** + * Test the contents of the sets + */ + public void testSets() + { + + JMSPropertyFieldTable table = new JMSPropertyFieldTable(); + + table.put("n1", "1"); + table.put("n2", "2"); + table.put("n3", "3"); + + Enumeration enumerator = table.getPropertyNames(); + Assert.assertEquals("n1", enumerator.nextElement()); + Assert.assertEquals("n2", enumerator.nextElement()); + Assert.assertEquals("n3", enumerator.nextElement()); + Assert.assertFalse(enumerator.hasMoreElements()); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(JMSPropertyFieldTableTest.class); + } + +} 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 0b6820b8a9..5256c62054 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 @@ -24,16 +24,22 @@ import junit.framework.Assert; import junit.framework.TestCase; import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.ByteBufferProxy; -import org.apache.mina.common.support.BaseByteBuffer; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQPInvalidClassException; public class PropertyFieldTableTest extends TestCase { - //Test byte modification + private static final Logger _logger = Logger.getLogger(PropertyFieldTableTest.class); + /** + * Test that modifying a byte[] after setting property doesn't change property + */ public void testByteModification() { PropertyFieldTable table = new PropertyFieldTable(); @@ -48,141 +54,518 @@ public class PropertyFieldTableTest extends TestCase assertBytesNotEqual(bytes, table.getBytes("bytes")); } - //Test replacement - + /** + * Test that setting a similar named value replaces any previous value set on that name + */ public void testReplacement() { PropertyFieldTable table1 = new PropertyFieldTable(); + //Set a boolean value table1.setBoolean("value", true); + //Check size of table is correct (<Value length> + <type> + <Boolean length>) + int size = EncodingUtils.encodedShortStringLength("value") + 1 + EncodingUtils.encodedBooleanLength(); + Assert.assertEquals(size, table1.getEncodedSize()); + + // reset value to an integer table1.setInteger("value", Integer.MAX_VALUE); + + // Check the size has changed accordingly (<Value length> + <type> + <Integer length>) + size = EncodingUtils.encodedShortStringLength("value") + 1 + EncodingUtils.encodedIntegerLength(); + Assert.assertEquals(size, table1.getEncodedSize()); + + //Check boolean value is null Assert.assertEquals(null, table1.getBoolean("value")); + // ... and integer value is good Assert.assertEquals((Integer) Integer.MAX_VALUE, table1.getInteger("value")); } - //Test Lookups - public void testBooleanLookup() + /** + * Set a boolean and check that we can only get it back as a boolean and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testBoolean() { PropertyFieldTable table1 = new PropertyFieldTable(); table1.setBoolean("value", true); + Assert.assertTrue(table1.propertyExists("value")); + + //Test Getting right value back Assert.assertEquals((Boolean) true, table1.getBoolean("value")); + + //Check we don't get anything back for other gets + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + //except value as a string + Assert.assertEquals("true", table1.getString("value")); + + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_BOOLEAN_PROPERTY_PREFIX, "value", null); + + // Should be able to get the null back + Assert.assertEquals(null, table1.getBoolean("value")); + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getBoolean("Rubbish")); } - public void testByteLookup() + /** + * Set a byte and check that we can only get it back as a byte and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testByte() { PropertyFieldTable table1 = new PropertyFieldTable(); - table1.setByte("value", (byte) 1); - Assert.assertEquals((Byte) (byte) 1, table1.getByte("value")); + table1.setByte("value", Byte.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(Byte.MAX_VALUE, (byte) table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Byte.MAX_VALUE, table1.getString("value")); + + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_BYTE_PROPERTY_PREFIX, "value", null); + + // Should be able to get the null back + Assert.assertEquals(null, table1.getByte("value")); + + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getByte("Rubbish")); } - public void testShortLookup() + /** + * Set a short and check that we can only get it back as a short and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testShort() { PropertyFieldTable table1 = new PropertyFieldTable(); table1.setShort("value", Short.MAX_VALUE); - Assert.assertEquals((Short) Short.MAX_VALUE, table1.getShort("value")); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(Short.MAX_VALUE, (short) table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Short.MAX_VALUE, table1.getString("value")); + + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_SHORT_PROPERTY_PREFIX, "value", null); + + // Should be able to get the null back + Assert.assertEquals(null, table1.getShort("value")); + + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getShort("Rubbish")); } - public void testCharLookup() + /** + * Set a char and check that we can only get it back as a char + * Check that attempting to lookup a non existent value returns null + */ + public void testChar() { PropertyFieldTable table1 = new PropertyFieldTable(); - table1.setChar("value", 'b'); - Assert.assertEquals((Character) 'b', table1.getCharacter("value")); + table1.setChar("value", 'c'); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals('c', (char) table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + //... and a the string value of it. + Assert.assertEquals("c", table1.getString("value")); + + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_ASCII_CHARACTER_PROPERTY_PREFIX, "value", null); + + try + { + table1.getString("value"); + fail("Should throw NullPointerException"); + } + catch (NullPointerException npe) + { + //Normal Path + } + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getCharacter("Rubbish")); } - public void testDoubleLookup() + + /** + * Set a double and check that we can only get it back as a double + * Check that attempting to lookup a non existent value returns null + */ + public void testDouble() { PropertyFieldTable table1 = new PropertyFieldTable(); table1.setDouble("value", Double.MAX_VALUE); - Assert.assertEquals(Double.MAX_VALUE, table1.getDouble("value")); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(Double.MAX_VALUE, (double) table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Double.MAX_VALUE, table1.getString("value")); + + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_DOUBLE_PROPERTY_PREFIX, "value", null); + + Assert.assertEquals(null, table1.getDouble("value")); + + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getDouble("Rubbish")); } - public void testFloatLookup() + + /** + * Set a float and check that we can only get it back as a float + * Check that attempting to lookup a non existent value returns null + */ + public void testFloat() { PropertyFieldTable table1 = new PropertyFieldTable(); table1.setFloat("value", Float.MAX_VALUE); - Assert.assertEquals(Float.MAX_VALUE, table1.getFloat("value")); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(Float.MAX_VALUE, (float) table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Float.MAX_VALUE, table1.getString("value")); + + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_FLOAT_PROPERTY_PREFIX, "value", null); + + Assert.assertEquals(null, table1.getFloat("value")); + + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getFloat("Rubbish")); } - public void testIntLookup() + + /** + * Set an int and check that we can only get it back as an int + * Check that attempting to lookup a non existent value returns null + */ + public void testInt() { PropertyFieldTable table1 = new PropertyFieldTable(); table1.setInteger("value", Integer.MAX_VALUE); - Assert.assertEquals((Integer) Integer.MAX_VALUE, table1.getInteger("value")); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(Integer.MAX_VALUE, (int) table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + //... and a the string value of it. + Assert.assertEquals("" + Integer.MAX_VALUE, table1.getString("value")); + + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_INT_PROPERTY_PREFIX, "value", null); + + Assert.assertEquals(null, table1.getInteger("value")); + + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getInteger("Rubbish")); } - public void testLongLookup() + + /** + * Set a long and check that we can only get it back as a long + * Check that attempting to lookup a non existent value returns null + */ + public void testLong() { PropertyFieldTable table1 = new PropertyFieldTable(); table1.setLong("value", Long.MAX_VALUE); - Assert.assertEquals((Long) Long.MAX_VALUE, table1.getLong("value")); - } + Assert.assertTrue(table1.propertyExists("value")); - public void testBytesLookup() - { - PropertyFieldTable table1 = new PropertyFieldTable(); - byte[] bytes = {99, 98, 97, 96, 95}; - table1.setBytes("bytes", bytes); - assertBytesEqual(bytes, table1.getBytes("bytes")); - } + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(Long.MAX_VALUE, (long) table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); - // Failed Lookups + //... and a the string value of it. + Assert.assertEquals("" + Long.MAX_VALUE, table1.getString("value")); - public void testFailedBooleanLookup() - { - PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getBoolean("int")); - } + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_LONG_PROPERTY_PREFIX, "value", null); - public void testFailedByteLookup() - { - PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getByte("int")); - } + Assert.assertEquals(null, table1.getLong("value")); - public void testFailedBytesLookup() - { - PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getBytes("int")); - } + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); - public void testFailedCharLookup() - { - PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getCharacter("int")); - } + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); - public void testFailedDoubleLookup() - { - PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getDouble("int")); - } + // Table should now have zero size for encoding + checkEmpty(table1); - public void testFailedFloatLookup() - { - PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getFloat("int")); + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getLong("Rubbish")); } - public void testFailedIntLookup() + + /** + * Set a double and check that we can only get it back as a double + * Check that attempting to lookup a non existent value returns null + */ + public void testBytes() { + byte[] bytes = {99, 98, 97, 96, 95}; + PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getInteger("int")); + table1.setBytes("value", bytes); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + assertBytesEqual(bytes, table1.getBytes("value")); + + //... and a the string value of it is null + Assert.assertEquals(null, table1.getString("value")); + + //Try setting a null value and read it back + table1.put(PropertyFieldTable.Prefix.AMQP_BINARY_PROPERTY_PREFIX, "value", null); + + Assert.assertEquals(null, table1.getBytes("value")); + + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero size for encoding + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getBytes("Rubbish")); } - public void testFailedLongLookup() + /** + * Calls all methods that can be used to check the table is empty + * - getEncodedSize + * - isEmpty + * - size + * + * @param table to check is empty + */ + private void checkEmpty(PropertyFieldTable table) { - PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getLong("int")); + Assert.assertEquals(0, table.getEncodedSize()); + Assert.assertTrue(table.isEmpty()); + Assert.assertEquals(0, table.size()); + + Assert.assertEquals(0, table.keySet().size()); + Assert.assertEquals(0, table.values().size()); + Assert.assertEquals(0, table.entrySet().size()); } - public void testFailedShortLookup() + + /** + * Set a String and check that we can only get it back as a String + * Check that attempting to lookup a non existent value returns null + */ + public void testString() { PropertyFieldTable table1 = new PropertyFieldTable(); - Assert.assertEquals(null, table1.getShort("int")); + table1.setString("value", "Hello"); + Assert.assertTrue(table1.propertyExists("value")); + + //Tets lookups we shouldn't get anything back for other gets + //we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + Assert.assertEquals("Hello", table1.getString("value")); + + //Try setting a null value and read it back + table1.setString("value", null); + + Assert.assertEquals(null, table1.getString("value")); + + //but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + //but after a remove it doesn't + Assert.assertFalse(table1.containsKey("value")); + + checkEmpty(table1); + + //Looking up an invalid value returns null + Assert.assertEquals(null, table1.getString("Rubbish")); + + //Additional Test that haven't been covered for string + table1.setObject("value", "Hello"); + //Check that it was set correctly + Assert.assertEquals("Hello", table1.getString("value")); } - public void testXML() + + /** + * Test that the generated XML can be used to create a field table with the same values. + */ + public void testValidXML() { PropertyFieldTable table1 = new PropertyFieldTable(); table1.setBoolean("bool", true); @@ -195,6 +578,8 @@ public class PropertyFieldTableTest extends TestCase table1.setInteger("int", Integer.MAX_VALUE); table1.setLong("long", Long.MAX_VALUE); table1.setShort("short", Short.MAX_VALUE); + table1.setString("string", "Hello"); + table1.setString("null-string", null); table1.setObject("object-bool", true); table1.setObject("object-byte", Byte.MAX_VALUE); @@ -205,14 +590,48 @@ public class PropertyFieldTableTest extends TestCase table1.setObject("object-int", Integer.MAX_VALUE); table1.setObject("object-long", Long.MAX_VALUE); table1.setObject("object-short", Short.MAX_VALUE); + table1.setObject("object-string", "Hello"); + + Assert.assertEquals(21, table1.size()); String table1XML = table1.toString(); PropertyFieldTable table2 = new PropertyFieldTable(table1XML); Assert.assertEquals(table1XML, table2.toString()); + + //Check that when bytes is written out as a string with no new line between items that it is read in ok. + } + /** + * Test that invalid input throws the correct Exception + */ + public void testInvalidXML() + { + try + { + _logger.warn("Testing Invalid XML expecting IllegalArgumentException"); + new PropertyFieldTable("Rubbish"); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + try + { + _logger.warn("Testing Invalid XML expecting IllegalArgumentException"); + new PropertyFieldTable(""); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + } + + public void testKeyEnumeration() { PropertyFieldTable table = new PropertyFieldTable(); @@ -244,6 +663,8 @@ public class PropertyFieldTableTest extends TestCase table.setInteger("int", Integer.MAX_VALUE); table.setLong("long", Long.MAX_VALUE); table.setShort("short", Short.MAX_VALUE); + table.setString("string", "Hello"); + table.setString("null-string", null); table.setObject("object-bool", true); table.setObject("object-byte", Byte.MAX_VALUE); @@ -254,6 +675,7 @@ public class PropertyFieldTableTest extends TestCase table.setObject("object-int", Integer.MAX_VALUE); table.setObject("object-long", Long.MAX_VALUE); table.setObject("object-short", Short.MAX_VALUE); + table.setObject("object-string", "Hello"); Assert.assertEquals((Boolean) true, table.getBoolean("bool")); @@ -265,6 +687,8 @@ public class PropertyFieldTableTest extends TestCase Assert.assertEquals((Integer) Integer.MAX_VALUE, table.getInteger("int")); Assert.assertEquals((Long) Long.MAX_VALUE, table.getLong("long")); Assert.assertEquals((Short) Short.MAX_VALUE, table.getShort("short")); + Assert.assertEquals("Hello", table.getString("string")); + Assert.assertEquals(null, table.getString("null-string")); Assert.assertEquals(true, table.getObject("object-bool")); Assert.assertEquals(Byte.MAX_VALUE, table.getObject("object-byte")); @@ -275,6 +699,7 @@ public class PropertyFieldTableTest extends TestCase Assert.assertEquals(Integer.MAX_VALUE, table.getObject("object-int")); Assert.assertEquals(Long.MAX_VALUE, table.getObject("object-long")); Assert.assertEquals(Short.MAX_VALUE, table.getObject("object-short")); + Assert.assertEquals("Hello", table.getObject("object-string")); } @@ -293,6 +718,8 @@ public class PropertyFieldTableTest extends TestCase table.setInteger("int", Integer.MAX_VALUE); table.setLong("long", Long.MAX_VALUE); table.setShort("short", Short.MAX_VALUE); + table.setString("string", "hello"); + table.setString("null-string", null); final ByteBuffer buffer = ByteBuffer.allocate((int) table.getEncodedSize()); // FIXME XXX: Is cast a problem? @@ -316,6 +743,9 @@ public class PropertyFieldTableTest extends TestCase 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")); + Assert.assertEquals("hello", table2.getString("string")); + Assert.assertEquals(null, table2.getString("null-string")); + } catch (AMQFrameDecodingException e) { @@ -326,68 +756,384 @@ public class PropertyFieldTableTest extends TestCase public void testEncodingSize() { - FieldTable result = FieldTableFactory.newFieldTable(); + PropertyFieldTable result = new PropertyFieldTable(); 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(); + result.setBoolean("boolean", true); + size += 1 + EncodingUtils.encodedShortStringLength("boolean") + EncodingUtils.encodedBooleanLength(); + Assert.assertEquals(size, result.getEncodedSize()); - long length = buffer.getUnsignedInt(); + + result.setByte("byte", (byte) Byte.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("byte") + EncodingUtils.encodedByteLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + + byte[] _bytes = {99, 98, 97, 96, 95}; + + result.setBytes("bytes", _bytes); + size += 1 + EncodingUtils.encodedShortStringLength("bytes") + 1 + EncodingUtils.encodedByteLength() * _bytes.length; + Assert.assertEquals(size, result.getEncodedSize()); + + result.setChar("char", (char) 'c'); + size += 1 + EncodingUtils.encodedShortStringLength("char") + EncodingUtils.encodedCharLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setDouble("double", (double) Double.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("double") + EncodingUtils.encodedDoubleLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setFloat("float", (float) Float.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("float") + EncodingUtils.encodedFloatLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setInteger("int", (int) Integer.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("int") + EncodingUtils.encodedIntegerLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + + result.setLong("long", (long) Long.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("long") + EncodingUtils.encodedLongLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setShort("short", (short) Short.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("short") + EncodingUtils.encodedShortLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setString("result", "Hello"); + size += 1 + EncodingUtils.encodedShortStringLength("result") + EncodingUtils.encodedLongStringLength("Hello"); + Assert.assertEquals(size, result.getEncodedSize()); + + + result.setObject("object-bool", true); + size += 1 + EncodingUtils.encodedShortStringLength("object-bool") + EncodingUtils.encodedBooleanLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-byte", Byte.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-byte") + EncodingUtils.encodedByteLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-bytes", _bytes); + size += 1 + EncodingUtils.encodedShortStringLength("object-bytes") + 1 + EncodingUtils.encodedByteLength() * _bytes.length; + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-char", 'c'); + size += 1 + EncodingUtils.encodedShortStringLength("object-char") + EncodingUtils.encodedCharLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-double", Double.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-double") + EncodingUtils.encodedDoubleLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-float", Float.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-float") + EncodingUtils.encodedFloatLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-int", Integer.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-int") + EncodingUtils.encodedIntegerLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + + result.setObject("object-long", Long.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-long") + EncodingUtils.encodedLongLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-short", Short.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-short") + EncodingUtils.encodedShortLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + } + +// public void testEncodingSize1() +// { +// PropertyFieldTable table = new PropertyFieldTable(); +// int size = 0; +// result.put("one", 1L); +// size = EncodingUtils.encodedShortStringLength("one"); +// size += 1 + EncodingUtils.encodedLongLength(); +// assertEquals(size, result.getEncodedSize()); +// +// result.put("two", 2L); +// size += EncodingUtils.encodedShortStringLength("two"); +// size += 1 + EncodingUtils.encodedLongLength(); +// assertEquals(size, result.getEncodedSize()); +// +// result.put("three", 3L); +// size += EncodingUtils.encodedShortStringLength("three"); +// size += 1 + EncodingUtils.encodedLongLength(); +// assertEquals(size, result.getEncodedSize()); +// +// result.put("four", 4L); +// size += EncodingUtils.encodedShortStringLength("four"); +// size += 1 + EncodingUtils.encodedLongLength(); +// assertEquals(size, result.getEncodedSize()); +// +// result.put("five", 5L); +// size += EncodingUtils.encodedShortStringLength("five"); +// size += 1 + EncodingUtils.encodedLongLength(); +// 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()); +// } +// +// } + + + /** + * Additional test for setObject + */ + public void testSetObject() + { + PropertyFieldTable table = new PropertyFieldTable(); + + //Try setting a non primative object try { - PropertyFieldTable table2 = new PropertyFieldTable(buffer, length); + table.setObject("value", this); + fail("Only primative values allowed in setObject"); + } + catch (AMQPInvalidClassException iae) + { + //normal path + } + // so size should be zero + Assert.assertEquals(0, table.getEncodedSize()); + } - 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")); + /** + * Additional test checkPropertyName doesn't accept Null + */ + public void testCheckPropertyNameasNull() + { + PropertyFieldTable table = new PropertyFieldTable(); + + try + { + table.setObject(null, "String"); + fail("Null property name is not allowed"); } - catch (AMQFrameDecodingException e) + catch (IllegalArgumentException iae) { - e.printStackTrace(); - fail("PFT should be instantiated from bytes." + e.getCause()); + //normal path } + // so size should be zero + Assert.assertEquals(0, table.getEncodedSize()); + } + + + /** + * Additional test checkPropertyName doesn't accept an empty String + */ + public void testCheckPropertyNameasEmptyString() + { + PropertyFieldTable table = new PropertyFieldTable(); + try + { + table.setObject("", "String"); + fail("empty property name is not allowed"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + // so size should be zero + Assert.assertEquals(0, table.getEncodedSize()); } + + /** + * Additional test checkPropertyName doesn't accept an empty String + */ + public void testCheckPropertyNamehasMaxLength() + { + PropertyFieldTable table = new PropertyFieldTable(); + + StringBuffer longPropertyName = new StringBuffer(129); + + for (int i = 0; i < 129; i++) + { + longPropertyName.append("x"); + } + + try + { + table.setObject(longPropertyName.toString(), "String"); + fail("property name must be < 128 characters"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + // so size should be zero + Assert.assertEquals(0, table.getEncodedSize()); + } + + + /** + * Additional test checkPropertyName starts with a letter + */ + public void testCheckPropertyNameStartCharacterIsLetter() + { + PropertyFieldTable table = new PropertyFieldTable(); + + //Try a name that starts with a number + try + { + table.setObject("1", "String"); + fail("property name must start with a letter"); + } + catch (IllegalArgumentException iae) + { + //normal path + } + // so size should be zero + Assert.assertEquals(0, table.getEncodedSize()); + } + + + /** + * Additional test checkPropertyName starts with a hash or a dollar + */ + public void testCheckPropertyNameStartCharacterIsHashorDollar() + { + PropertyFieldTable table = new PropertyFieldTable(); + + //Try a name that starts with a number + try + { + table.setObject("#", "String"); + table.setObject("$", "String"); + } + catch (IllegalArgumentException iae) + { + fail("property name are allowed to start with # and $s"); + } + } + + + /** + * Additional test to test the contents of the table + */ + public void testContents() + { + PropertyFieldTable table = new PropertyFieldTable(); + + table.put("StringProperty", "String"); + + Assert.assertTrue(table.containsValue("String")); + + Assert.assertEquals("String", table.get("StringProperty")); + + //Test Clear + + table.clear(); + + checkEmpty(table); + } + + /** + * Test the contents of the sets + */ + public void testSets() + { + + PropertyFieldTable table = new PropertyFieldTable(); + + table.put("n1", "1"); + table.put("n2", "2"); + table.put("n3", "3"); + + Iterator iterator = table.keySet().iterator(); + Assert.assertEquals("n1", iterator.next()); + Assert.assertEquals("n2", iterator.next()); + Assert.assertEquals("n3", iterator.next()); + Assert.assertFalse(iterator.hasNext()); + + + iterator = table.values().iterator(); + Assert.assertEquals("1", iterator.next()); + Assert.assertEquals("2", iterator.next()); + Assert.assertEquals("3", iterator.next()); + Assert.assertFalse(iterator.hasNext()); + + + iterator = table.entrySet().iterator(); + Map.Entry entry = (Map.Entry) iterator.next(); + Assert.assertEquals("n1", entry.getKey()); + Assert.assertEquals("1", entry.getValue()); + entry = (Map.Entry) iterator.next(); + Assert.assertEquals("n2", entry.getKey()); + Assert.assertEquals("2", entry.getValue()); + entry = (Map.Entry) iterator.next(); + Assert.assertEquals("n3", entry.getKey()); + Assert.assertEquals("3", entry.getValue()); + Assert.assertFalse(iterator.hasNext()); + + + } + + + /** + * Test that all the values are preserved after a putAll + */ + public void testPutAll() + { + Map map = new HashMap(); + + map.put("char", 'c'); + map.put("double", Double.MAX_VALUE); + map.put("float", Float.MAX_VALUE); + map.put("int", Integer.MAX_VALUE); + map.put("long", Long.MAX_VALUE); + map.put("short", Short.MAX_VALUE); + + PropertyFieldTable table = new PropertyFieldTable(); + + table.putAll(map); + + Assert.assertEquals(6, table.size()); + + Assert.assertTrue(table.containsKey("char")); + Assert.assertEquals('c', (char) table.getCharacter("char")); + Assert.assertTrue(table.containsKey("double")); + Assert.assertEquals(Double.MAX_VALUE, table.getDouble("double")); + Assert.assertTrue(table.containsKey("float")); + Assert.assertEquals(Float.MAX_VALUE, table.getFloat("float")); + Assert.assertTrue(table.containsKey("int")); + Assert.assertEquals(Integer.MAX_VALUE, (int) table.getInteger("int")); + Assert.assertTrue(table.containsKey("long")); + Assert.assertEquals(Long.MAX_VALUE, (long) table.getLong("long")); + Assert.assertTrue(table.containsKey("short")); + Assert.assertEquals(Short.MAX_VALUE, (short) table.getShort("short")); + Assert.assertEquals(Short.MAX_VALUE, (short) table.getShort("short")); + } + + private void assertBytesEqual(byte[] expected, byte[] actual) { Assert.assertEquals(expected.length, actual.length); diff --git a/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java b/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java new file mode 100644 index 0000000000..972a935257 --- /dev/null +++ b/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java @@ -0,0 +1,104 @@ +/* + * 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.pool; + +import junit.framework.TestCase; +import junit.framework.Assert; +import org.apache.qpid.session.TestSession; +import org.apache.mina.common.IoFilter; +import org.apache.mina.common.IoSession; +import org.apache.mina.common.IdleStatus; + +import java.util.concurrent.RejectedExecutionException; + +public class PoolingFilterTest extends TestCase +{ + private PoolingFilter _pool; + ReferenceCountingExecutorService _executorService; + + public void setUp() + { + //Create Pool + _executorService = ReferenceCountingExecutorService.getInstance(); + _executorService.acquireExecutorService(); + _pool = new PoolingFilter(_executorService, PoolingFilter.WRITE_EVENTS, + "AsynchronousWriteFilter"); + + } + + public void testRejectedExecution() throws Exception + { + _pool.filterWrite(new NoOpFilter(), new TestSession(), new IoFilter.WriteRequest("Message")); + + //Shutdown the pool + _executorService.getPool().shutdownNow(); + + try + { + //prior to fix for QPID-172 this would throw RejectedExecutionException + _pool.filterWrite(null, new TestSession(), null); + } + catch (RejectedExecutionException rje) + { + Assert.fail("RejectedExecutionException should not occur after pool has shutdown:" + rje); + } + } + + private static class NoOpFilter implements IoFilter.NextFilter + { + + public void sessionOpened(IoSession session) + { + } + + public void sessionClosed(IoSession session) + { + } + + public void sessionIdle(IoSession session, IdleStatus status) + { + } + + public void exceptionCaught(IoSession session, Throwable cause) + { + } + + public void messageReceived(IoSession session, Object message) + { + } + + public void messageSent(IoSession session, Object message) + { + } + + public void filterWrite(IoSession session, IoFilter.WriteRequest writeRequest) + { + } + + public void filterClose(IoSession session) + { + } + + public void sessionCreated(IoSession session) + { + } + } +} diff --git a/java/common/src/test/java/org/apache/qpid/session/TestSession.java b/java/common/src/test/java/org/apache/qpid/session/TestSession.java new file mode 100644 index 0000000000..f10d55e9d0 --- /dev/null +++ b/java/common/src/test/java/org/apache/qpid/session/TestSession.java @@ -0,0 +1,273 @@ +/* + * + * 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.session; + +import org.apache.mina.common.*; + +import java.net.SocketAddress; +import java.util.Set; + +public class TestSession implements IoSession +{ + public TestSession() + { + } + + public IoService getService() + { + return null; //TODO + } + + public IoServiceConfig getServiceConfig() + { + return null; //TODO + } + + public IoHandler getHandler() + { + return null; //TODO + } + + public IoSessionConfig getConfig() + { + return null; //TODO + } + + public IoFilterChain getFilterChain() + { + return null; //TODO + } + + public WriteFuture write(Object message) + { + return null; //TODO + } + + public CloseFuture close() + { + return null; //TODO + } + + public Object getAttachment() + { + return null; //TODO + } + + public Object setAttachment(Object attachment) + { + return null; //TODO + } + + public Object getAttribute(String key) + { + return null; //TODO + } + + public Object setAttribute(String key, Object value) + { + return null; //TODO + } + + public Object setAttribute(String key) + { + return null; //TODO + } + + public Object removeAttribute(String key) + { + return null; //TODO + } + + public boolean containsAttribute(String key) + { + return false; //TODO + } + + public Set getAttributeKeys() + { + return null; //TODO + } + + public TransportType getTransportType() + { + return null; //TODO + } + + public boolean isConnected() + { + return false; //TODO + } + + public boolean isClosing() + { + return false; //TODO + } + + public CloseFuture getCloseFuture() + { + return null; //TODO + } + + public SocketAddress getRemoteAddress() + { + return null; //TODO + } + + public SocketAddress getLocalAddress() + { + return null; //TODO + } + + public SocketAddress getServiceAddress() + { + return null; //TODO + } + + public int getIdleTime(IdleStatus status) + { + return 0; //TODO + } + + public long getIdleTimeInMillis(IdleStatus status) + { + return 0; //TODO + } + + public void setIdleTime(IdleStatus status, int idleTime) + { + //TODO + } + + public int getWriteTimeout() + { + return 0; //TODO + } + + public long getWriteTimeoutInMillis() + { + return 0; //TODO + } + + public void setWriteTimeout(int writeTimeout) + { + //TODO + } + + public TrafficMask getTrafficMask() + { + return null; //TODO + } + + public void setTrafficMask(TrafficMask trafficMask) + { + //TODO + } + + public void suspendRead() + { + //TODO + } + + public void suspendWrite() + { + //TODO + } + + public void resumeRead() + { + //TODO + } + + public void resumeWrite() + { + //TODO + } + + public long getReadBytes() + { + return 0; //TODO + } + + public long getWrittenBytes() + { + return 0; //TODO + } + + public long getReadMessages() + { + return 0; + } + + public long getWrittenMessages() + { + return 0; + } + + public long getWrittenWriteRequests() + { + return 0; //TODO + } + + public int getScheduledWriteRequests() + { + return 0; //TODO + } + + public int getScheduledWriteBytes() + { + return 0; //TODO + } + + public long getCreationTime() + { + return 0; //TODO + } + + public long getLastIoTime() + { + return 0; //TODO + } + + public long getLastReadTime() + { + return 0; //TODO + } + + public long getLastWriteTime() + { + return 0; //TODO + } + + public boolean isIdle(IdleStatus status) + { + return false; //TODO + } + + public int getIdleCount(IdleStatus status) + { + return 0; //TODO + } + + public long getLastIdleTime(IdleStatus status) + { + return 0; //TODO + } +} |