Author: rajith
Date: Thu May 23 22:27:03 2013
New Revision: 1485878
URL: http://svn.apache.org/r1485878
Log:
QPID-4873 Commiting patch by Helen Kwong.
Modified:
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Node.java
qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java
Modified:
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java
URL:
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java?rev=1485878&r1=1485877&r2=1485878&view=diff
==============================================================================
---
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java
(original)
+++
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java
Thu May 23 22:27:03 2013
@@ -123,10 +123,10 @@ public class AddressHelper
@SuppressWarnings("unchecked")
public List<Binding> getBindings(Map props)
{
- List<Binding> bindings = new ArrayList<Binding>();
List<Map> bindingList = (props == null) ? Collections.EMPTY_LIST :
(List<Map>) props.get(X_BINDINGS);
- if (bindingList != null)
+ if (bindingList != null && !bindingList.isEmpty())
{
+ List<Binding> bindings = new
ArrayList<Binding>(bindingList.size());
for (Map bindingMap : bindingList)
{
Binding binding = new Binding(
@@ -138,8 +138,12 @@ public class AddressHelper
.get(ARGUMENTS));
bindings.add(binding);
}
+ return bindings;
+ }
+ else
+ {
+ return Collections.emptyList();
}
- return bindings;
}
public Map getDeclareArgs(Map props)
Modified:
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java
URL:
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java?rev=1485878&r1=1485877&r2=1485878&view=diff
==============================================================================
---
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java
(original)
+++
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java
Thu May 23 22:27:03 2013
@@ -20,7 +20,6 @@
*/
package org.apache.qpid.client.messaging.address;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -43,7 +42,7 @@ public class Link
private int _producerCapacity = 0;
private Subscription subscription;
private Reliability reliability = Reliability.AT_LEAST_ONCE;
- private List<Binding> _bindings = new ArrayList<Binding>();
+ private List<Binding> _bindings = Collections.emptyList();
private SubscriptionQueue _subscriptionQueue;
public Reliability getReliability()
@@ -206,7 +205,7 @@ public class Link
public static class Subscription
{
- private Map<String,Object> args = new HashMap<String,Object>();
+ private Map<String,Object> args = Collections.emptyMap();
private boolean exclusive = false;
public Map<String, Object> getArgs()
Modified:
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Node.java
URL:
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Node.java?rev=1485878&r1=1485877&r2=1485878&view=diff
==============================================================================
---
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Node.java
(original)
+++
qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Node.java
Thu May 23 22:27:03 2013
@@ -21,15 +21,14 @@
package org.apache.qpid.client.messaging.address;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQDestination.Binding;
-
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQDestination.Binding;
+
public class Node
{
private int _nodeType = AMQDestination.UNKNOWN_TYPE;
@@ -39,7 +38,7 @@ public class Node
private boolean _isExclusive;
private String _alternateExchange;
private String _exchangeType = "topic"; // used when node is an exchange
instead of a queue.
- private List<Binding> _bindings = new ArrayList<Binding>();
+ private List<Binding> _bindings = Collections.emptyList();
private Map<String,Object> _declareArgs = new HashMap<String,Object>();
protected Node(String name)
@@ -112,10 +111,6 @@ public class Node
_bindings = bindings;
}
- public void addBinding(Binding binding) {
- this._bindings.add(binding);
- }
-
public Map<String,Object> getDeclareArgs()
{
return _declareArgs;
Modified:
qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java
URL:
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java?rev=1485878&r1=1485877&r2=1485878&view=diff
==============================================================================
---
qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java
(original)
+++
qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java
Thu May 23 22:27:03 2013
@@ -20,6 +20,10 @@
*/
package org.apache.qpid.client;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
import junit.framework.TestCase;
public class AMQDestinationTest extends TestCase
@@ -63,4 +67,95 @@ public class AMQDestinationTest extends
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}}"));
+ }
+
+ private void assertEmptyNodeBindings(AMQDestination dest)
+ {
+ assertSame("Empty node bindings should refer to the constant
Collections empty list.",
+ Collections.emptyList(), dest.getNode().getBindings());
+ }
+
}
Modified:
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
URL:
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java?rev=1485878&r1=1485877&r2=1485878&view=diff
==============================================================================
---
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
(original)
+++
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
Thu May 23 22:27:03 2013
@@ -205,6 +205,8 @@ public class ClientProperties
public static final String QPID_DECLARE_EXCHANGES_PROP_NAME =
"qpid.declare_exchanges";
public static final String VERIFY_QUEUE_ON_SEND =
"qpid.verify_queue_on_send";
+ public static final String QPID_MAX_CACHED_ADDR_OPTION_STRINGS =
"qpid.max_cached_address_option_strings";
+ public static final int DEFAULT_MAX_CACHED_ADDR_OPTION_STRINGS = 10;
private ClientProperties()
{
Modified:
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java
URL:
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java?rev=1485878&r1=1485877&r2=1485878&view=diff
==============================================================================
---
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java
(original)
+++
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java
Thu May 23 22:27:03 2013
@@ -20,12 +20,17 @@
*/
package org.apache.qpid.messaging.util;
-import org.apache.qpid.messaging.Address;
-
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.qpid.configuration.ClientProperties;
+import org.apache.qpid.messaging.Address;
/**
@@ -58,6 +63,23 @@ public class AddressParser extends Parse
private static Lexer LEXER = lxi.compile();
+ private static final int MAX_CACHED_ENTRIES =
Integer.getInteger(ClientProperties.QPID_MAX_CACHED_ADDR_OPTION_STRINGS,
+
ClientProperties.DEFAULT_MAX_CACHED_ADDR_OPTION_STRINGS);
+
+ // stores address options maps for options strings that we have
encountered; using a synchronizedMap wrapper
+ // in case multiple threads are parsing addresses.
+ private static Map<String, Map<Object, Object>> optionsMaps =
+ Collections.synchronizedMap(
+ new LinkedHashMap<String, Map<Object,
Object>>(MAX_CACHED_ENTRIES +1,1.1f,true)
+ {
+ @Override
+ protected boolean
removeEldestEntry(Map.Entry<String,Map<Object, Object>> eldest)
+ {
+ return size() > MAX_CACHED_ENTRIES;
+ }
+
+ });
+
public static List<Token> lex(String input)
{
return LEXER.lex(input);
@@ -267,11 +289,27 @@ public class AddressParser extends Parse
subject = null;
}
- Map options;
+ Map<Object, Object> options;
if (matches(SEMI))
{
eat(SEMI);
- options = map();
+
+ // get the remaining string denoting the options and see if we've
already encountered an address
+ // with the same options before
+ String optionsString = toks2str(remainder());
+ Map<Object,Object> storedMap = optionsMaps.get(optionsString);
+ if (storedMap == null)
+ {
+ // if these are new options, construct a new map and store it
in the encountered collection
+ options = Collections.unmodifiableMap(map());
+ optionsMaps.put(optionsString, options);
+ }
+ else
+ {
+ // if we already have the map for these options, use the
stored map
+ options = storedMap;
+ eat_until(EOF);
+ }
}
else
{
Modified:
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java
URL:
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java?rev=1485878&r1=1485877&r2=1485878&view=diff
==============================================================================
---
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java
(original)
+++
qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java
Thu May 23 22:27:03 2013
@@ -74,7 +74,7 @@ class Parser
List<Token> eat_until(Token.Type ... types)
{
- List<Token> result = new ArrayList();
+ List<Token> result = new ArrayList<Token>();
while (!matches(types))
{
result.add(eat());
@@ -82,4 +82,16 @@ class Parser
return result;
}
+ /**
+ * Returns the remaining list of tokens, without eating them
+ */
+ List<Token> remainder()
+ {
+ List<Token> result = new ArrayList<Token>();
+ for (int i = idx; i < tokens.size(); i++)
+ {
+ result.add(tokens.get(i));
+ }
+ return result;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]