| /* |
| * |
| * 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.client; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.Serializable; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import javax.jms.Destination; |
| import javax.jms.Queue; |
| import javax.jms.Topic; |
| |
| import org.apache.qpid.test.utils.QpidTestCase; |
| |
| public class AMQDestinationTest extends QpidTestCase |
| { |
| public void testEqualsAndHashCodeForAddressBasedDestinations() throws Exception |
| { |
| AMQDestination dest = new AMQQueue("ADDR:Foo; {node :{type:queue}}"); |
| AMQDestination dest1 = new AMQTopic("ADDR:Foo; {node :{type:topic}}"); |
| AMQDestination dest10 = new AMQTopic("ADDR:Foo; {node :{type:topic}, link:{name:my-topic}}"); |
| AMQDestination dest2 = new AMQQueue("ADDR:Foo; {create:always,node :{type:queue}}"); |
| String bUrl = "BURL:direct://amq.direct/test-route/Foo?routingkey='Foo'"; |
| AMQDestination dest3 = new AMQQueue(bUrl); |
| |
| assertTrue(dest.equals(dest)); |
| assertFalse(dest.equals(dest1)); |
| assertTrue(dest.equals(dest2)); |
| assertFalse(dest.equals(dest3)); |
| assertTrue(dest1.equals(dest10)); |
| |
| assertTrue(dest.hashCode() == dest.hashCode()); |
| assertTrue(dest.hashCode() != dest1.hashCode()); |
| assertTrue(dest.hashCode() == dest2.hashCode()); |
| assertTrue(dest.hashCode() != dest3.hashCode()); |
| assertTrue(dest1.hashCode() == dest10.hashCode()); |
| |
| AMQDestination dest4 = new AMQQueue("ADDR:Foo/Bar; {node :{type:queue}}"); |
| AMQDestination dest5 = new AMQQueue("ADDR:Foo/Bar2; {node :{type:queue}}"); |
| assertFalse(dest4.equals(dest5)); |
| assertTrue(dest4.hashCode() != dest5.hashCode()); |
| |
| AMQDestination dest6 = new AMQAnyDestination("ADDR:Foo; {node :{type:queue}}"); |
| AMQDestination dest7 = new AMQAnyDestination("ADDR:Foo; {create: always, node :{type:queue}, link:{capacity: 10}}"); |
| AMQDestination dest8 = new AMQAnyDestination("ADDR:Foo; {create: always, link:{capacity: 10}}"); |
| AMQDestination dest9 = new AMQAnyDestination("ADDR:Foo/bar"); |
| assertTrue(dest6.equals(dest7)); |
| assertFalse(dest6.equals(dest8)); //dest8 type unknown, could be a topic |
| assertFalse(dest7.equals(dest8)); //dest8 type unknown, could be a topic |
| assertFalse(dest6.equals(dest9)); |
| assertTrue(dest6.hashCode() == dest7.hashCode()); |
| assertTrue(dest6.hashCode() != dest8.hashCode()); |
| assertTrue(dest7.hashCode() != dest8.hashCode()); |
| assertTrue(dest6.hashCode() != dest9.hashCode()); |
| } |
| |
| /** |
| * Tests that destinations created with the same options string will share the same address options map. |
| */ |
| public void testCacheAddressOptionsMaps() throws Exception |
| { |
| // Create destinations 1 and 3 with the same options string, and destinations 2 and 4 with a different one |
| String optionsStringA = "{create: always, node: {type: topic}}"; |
| String optionsStringB = "{}"; // empty options |
| AMQDestination dest1 = createDestinationWithOptions("testDest1", optionsStringA); |
| AMQDestination dest2 = createDestinationWithOptions("testDest2", optionsStringB); |
| AMQDestination dest3 = createDestinationWithOptions("testDest3", optionsStringA); |
| AMQDestination dest4 = createDestinationWithOptions("testDest4", optionsStringB); |
| |
| // Destinations 1 and 3 should refer to the same address options map |
| assertSame("Destinations 1 and 3 were created with the same options and should refer to the same options map.", |
| dest1.getAddress().getOptions(), dest3.getAddress().getOptions()); |
| // Destinations 2 and 4 should refer to the same address options map |
| assertSame("Destinations 2 and 4 were created with the same options and should refer to the same options map.", |
| dest2.getAddress().getOptions(), dest4.getAddress().getOptions()); |
| // Destinations 1 and 2 should have a different options map |
| assertNotSame("Destinations 1 and 2 should not have the same options map.", |
| dest1.getAddress().getOptions(), dest2.getAddress().getOptions()); |
| |
| // Verify the contents of the shared map are as expected |
| Map<String, Object> optionsA = new HashMap<String, Object>(); |
| optionsA.put("create", "always"); |
| optionsA.put("node", Collections.singletonMap("type", "topic")); |
| assertEquals("Contents of the shared address options map are not as expected.", |
| optionsA, dest1.getAddress().getOptions()); |
| assertEquals("Contents of the empty shared address options map are not as expected.", |
| Collections.emptyMap(), dest2.getAddress().getOptions()); |
| |
| // Verify that address options map is immutable |
| try |
| { |
| dest1.getAddress().getOptions().put("testKey", "testValue"); |
| fail("Should not be able able to modify an address's options map."); |
| } |
| catch (UnsupportedOperationException e) |
| { |
| // expected |
| } |
| } |
| |
| private AMQDestination createDestinationWithOptions(String destName, String optionsString) throws Exception |
| { |
| String addr = "ADDR:" + destName + "; " + optionsString; |
| return new AMQAnyDestination(addr); |
| } |
| |
| /** |
| * Tests that when a queue has no link subscription arguments and no link bindings, its Subscription |
| * arguments and its bindings list refer to constant empty collections. |
| */ |
| public void testEmptyLinkBindingsAndSubscriptionArgs() throws Exception |
| { |
| // no link properties |
| assertEmptyLinkBindingsAndSubscriptionArgs(new AMQAnyDestination("ADDR:testQueue")); |
| |
| // has link properties but no x-bindings; has link x-subscribes but no arguments |
| String xSubscribeAddr = "ADDR:testQueueWithXSubscribes; {link: {x-subscribes: {exclusive: true}}}"; |
| assertEmptyLinkBindingsAndSubscriptionArgs(new AMQAnyDestination(xSubscribeAddr)); |
| } |
| |
| private void assertEmptyLinkBindingsAndSubscriptionArgs(AMQDestination dest) |
| { |
| assertEquals("Default link subscription arguments should be the constant Collections empty map.", |
| Collections.emptyMap(), dest.getLink().getSubscription().getArgs()); |
| assertSame("Defaultl link bindings should be the constant Collections empty list.", |
| Collections.emptyList(), dest.getLink().getBindings()); |
| } |
| |
| /** |
| * Tests that when a node has no bindings specified, its bindings list refers to a constant empty list, |
| * so that we are not consuming extra memory unnecessarily. |
| */ |
| public void testEmptyNodeBindings() throws Exception |
| { |
| // no node properties |
| assertEmptyNodeBindings(new AMQAnyDestination("ADDR:testDest1")); |
| // has node properties but no x-bindings |
| assertEmptyNodeBindings(new AMQAnyDestination("ADDR:testDest2; {node: {type: queue}}")); |
| assertEmptyNodeBindings(new AMQAnyDestination("ADDR:testDest3; {node: {type: topic}}")); |
| } |
| |
| public void testSimple_BURL() throws Exception |
| { |
| AMQQueue queue = new AMQQueue("BURL:direct://amq.direct/test-route/Foo"); |
| |
| assertEquals("direct", queue.getExchangeClass()); |
| assertEquals("amq.direct", queue.getExchangeName()); |
| assertEquals("Foo", queue.getQueueName()); |
| assertEquals(queue.getQueueName(), queue.getRoutingKey()); |
| assertFalse(queue.isDurable()); |
| } |
| |
| public void testAnonymousExchange_BURL() throws Exception |
| { |
| AMQQueue queue = new AMQQueue("BURL:direct:///Foo?durable='true'"); |
| |
| assertEquals("direct", queue.getExchangeClass()); |
| assertEquals("", queue.getExchangeName()); |
| assertEquals("Foo", queue.getQueueName()); |
| assertEquals(queue.getQueueName(), queue.getRoutingKey()); |
| assertTrue(queue.isDurable()); |
| } |
| |
| public void testNonDurableExchange_BURL() throws Exception |
| { |
| AMQQueue queue = new AMQQueue("BURL:direct://mynondurableexch//Foo?exchangeautodelete='true'"); |
| |
| assertEquals("direct", queue.getExchangeClass()); |
| assertEquals("mynondurableexch", queue.getExchangeName()); |
| assertEquals("Foo", queue.getQueueName()); |
| assertEquals("Foo", queue.getRoutingKey()); |
| assertTrue(queue.isExchangeAutoDelete()); |
| } |
| |
| public void testSerializeAMQQueue_BURL() throws Exception |
| { |
| Queue queue = new AMQQueue("BURL:direct://amq.direct/test-route/Foo?routingkey='Foo'"); |
| assertTrue(queue instanceof Serializable); |
| |
| Queue deserialisedQueue = (Queue) serialiseDeserialiseDestination(queue); |
| |
| assertEquals(queue, deserialisedQueue); |
| assertEquals(queue.hashCode(), deserialisedQueue.hashCode()); |
| } |
| |
| public void testSerializeAMQQueue_ADDR() throws Exception |
| { |
| Queue queue = new AMQQueue("ADDR:testDest2; {node: {type: queue}}"); |
| assertTrue(queue instanceof Serializable); |
| |
| Queue deserialisedQueue = (Queue) serialiseDeserialiseDestination(queue); |
| |
| assertEquals(queue, deserialisedQueue); |
| assertEquals(queue.hashCode(), deserialisedQueue.hashCode()); |
| } |
| |
| public void testSerializeAMQTopic_BURL() throws Exception |
| { |
| Topic topic = new AMQTopic("BURL:topic://amq.topic/mytopic/?routingkey='mytopic'"); |
| assertTrue(topic instanceof Serializable); |
| |
| Topic deserialisedTopic = (Topic) serialiseDeserialiseDestination(topic); |
| |
| assertEquals(topic, deserialisedTopic); |
| assertEquals(topic.hashCode(), deserialisedTopic.hashCode()); |
| } |
| |
| public void testSerializeAMQTopic_ADDR() throws Exception |
| { |
| Topic topic = new AMQTopic("ADDR:my-topic; {assert: always, node:{ type: topic }}"); |
| assertTrue(topic instanceof Serializable); |
| |
| Topic deserialisedTopic = (Topic) serialiseDeserialiseDestination(topic); |
| |
| assertEquals(topic, deserialisedTopic); |
| assertEquals(topic.hashCode(), deserialisedTopic.hashCode()); |
| } |
| |
| private void assertEmptyNodeBindings(AMQDestination dest) |
| { |
| assertSame("Empty node bindings should refer to the constant Collections empty list.", |
| Collections.emptyList(), dest.getNode().getBindings()); |
| } |
| |
| private Destination serialiseDeserialiseDestination(final Destination dest) throws Exception |
| { |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| ObjectOutputStream oos = new ObjectOutputStream(bos); |
| oos.writeObject(dest); |
| oos.close(); |
| |
| ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); |
| ObjectInputStream ois = new ObjectInputStream(bis); |
| Object deserializedObject = ois.readObject(); |
| ois.close(); |
| return (Destination)deserializedObject; |
| } |
| |
| |
| } |