You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2014/09/23 20:20:30 UTC
[06/27] Initial drop of donated AMQP Client Code.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageHeaderSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageHeaderSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageHeaderSectionMatcher.java
new file mode 100644
index 0000000..eed6826
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageHeaderSectionMatcher.java
@@ -0,0 +1,118 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessageListSectionMatcher;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-message-section-matchers.xsl, which resides in this package.
+ */
+public class MessageHeaderSectionMatcher extends MessageListSectionMatcher
+{
+
+ public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:header:list");
+ public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000070L);
+
+ /** Note that the ordinals of the Field enums match the order specified in the AMQP spec */
+ public enum Field
+ {
+ DURABLE,
+ PRIORITY,
+ TTL,
+ FIRST_ACQUIRER,
+ DELIVERY_COUNT,
+ }
+
+ public MessageHeaderSectionMatcher(boolean expectTrailingBytes)
+ {
+ super(DESCRIPTOR_CODE,
+ DESCRIPTOR_SYMBOL,
+ new HashMap<Object, Matcher<?>>(),
+ expectTrailingBytes);
+ }
+
+
+ public MessageHeaderSectionMatcher withDurable(Matcher<?> m)
+ {
+ getMatchers().put(Field.DURABLE, m);
+ return this;
+ }
+
+ public MessageHeaderSectionMatcher withPriority(Matcher<?> m)
+ {
+ getMatchers().put(Field.PRIORITY, m);
+ return this;
+ }
+
+ public MessageHeaderSectionMatcher withTtl(Matcher<?> m)
+ {
+ getMatchers().put(Field.TTL, m);
+ return this;
+ }
+
+ public MessageHeaderSectionMatcher withFirstAcquirer(Matcher<?> m)
+ {
+ getMatchers().put(Field.FIRST_ACQUIRER, m);
+ return this;
+ }
+
+ public MessageHeaderSectionMatcher withDeliveryCount(Matcher<?> m)
+ {
+ getMatchers().put(Field.DELIVERY_COUNT, m);
+ return this;
+ }
+
+ public Object getReceivedDurable()
+ {
+ return getReceivedFields().get(Field.DURABLE);
+ }
+
+ public Object getReceivedPriority()
+ {
+ return getReceivedFields().get(Field.PRIORITY);
+ }
+
+ public Object getReceivedTtl()
+ {
+ return getReceivedFields().get(Field.TTL);
+ }
+
+ public Object getReceivedFirstAcquirer()
+ {
+ return getReceivedFields().get(Field.FIRST_ACQUIRER);
+ }
+
+ public Object getReceivedDeliveryCount()
+ {
+ return getReceivedFields().get(Field.DELIVERY_COUNT);
+ }
+
+ @Override
+ protected Enum<?> getField(int fieldIndex)
+ {
+ return Field.values()[fieldIndex];
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageListSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageListSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageListSectionMatcher.java
new file mode 100644
index 0000000..01d8ab0
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageListSectionMatcher.java
@@ -0,0 +1,58 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+
+public abstract class MessageListSectionMatcher extends AbstractMessageSectionMatcher
+{
+ public MessageListSectionMatcher(UnsignedLong numericDescriptor,
+ Symbol symbolicDescriptor,
+ Map<Object, Matcher<?>> fieldMatchers,
+ boolean expectTrailingBytes)
+ {
+ super(numericDescriptor, symbolicDescriptor, fieldMatchers, expectTrailingBytes);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void verifyReceivedDescribedObject(Object described)
+ {
+ if(!(described instanceof List))
+ {
+ throw new IllegalArgumentException("Unexpected section contents. Expected List, but got: "
+ + (described == null ? "null" : described.getClass()));
+ }
+
+ int fieldNumber = 0;
+ Map<Object, Object> valueMap = new HashMap<Object, Object>();
+ for(Object value : (List<Object>)described)
+ {
+ valueMap.put(getField(fieldNumber++), value);
+ }
+
+ verifyReceivedFields(valueMap);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageMapSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageMapSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageMapSectionMatcher.java
new file mode 100644
index 0000000..be3f0a4
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageMapSectionMatcher.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+
+public abstract class MessageMapSectionMatcher extends AbstractMessageSectionMatcher
+{
+ public MessageMapSectionMatcher(UnsignedLong numericDescriptor,
+ Symbol symbolicDescriptor,
+ Map<Object, Matcher<?>> fieldMatchers,
+ boolean expectTrailingBytes)
+ {
+ super(numericDescriptor, symbolicDescriptor, fieldMatchers, expectTrailingBytes);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void verifyReceivedDescribedObject(Object described)
+ {
+ if(!(described instanceof Map))
+ {
+ throw new IllegalArgumentException("Unexpected section contents. Expected Map, but got: "
+ + (described == null ? "null" : described.getClass()));
+ }
+
+ verifyReceivedFields((Map<Object,Object>) described);
+ }
+
+ public MessageMapSectionMatcher withEntry(Object key, Matcher<?> m)
+ {
+ getMatchers().put(key, m);
+ return this;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessagePropertiesSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessagePropertiesSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessagePropertiesSectionMatcher.java
new file mode 100644
index 0000000..35a523a
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessagePropertiesSectionMatcher.java
@@ -0,0 +1,214 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessageListSectionMatcher;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-message-section-matchers.xsl, which resides in this package.
+ */
+public class MessagePropertiesSectionMatcher extends MessageListSectionMatcher
+{
+
+ public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:properties:list");
+ public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000073L);
+
+ /** Note that the ordinals of the Field enums match the order specified in the AMQP spec */
+ public enum Field
+ {
+ MESSAGE_ID,
+ USER_ID,
+ TO,
+ SUBJECT,
+ REPLY_TO,
+ CORRELATION_ID,
+ CONTENT_TYPE,
+ CONTENT_ENCODING,
+ ABSOLUTE_EXPIRY_TIME,
+ CREATION_TIME,
+ GROUP_ID,
+ GROUP_SEQUENCE,
+ REPLY_TO_GROUP_ID,
+ }
+
+ public MessagePropertiesSectionMatcher(boolean expectTrailingBytes)
+ {
+ super(DESCRIPTOR_CODE,
+ DESCRIPTOR_SYMBOL,
+ new HashMap<Object, Matcher<?>>(),
+ expectTrailingBytes);
+ }
+
+
+ public MessagePropertiesSectionMatcher withMessageId(Matcher<?> m)
+ {
+ getMatchers().put(Field.MESSAGE_ID, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withUserId(Matcher<?> m)
+ {
+ getMatchers().put(Field.USER_ID, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withTo(Matcher<?> m)
+ {
+ getMatchers().put(Field.TO, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withSubject(Matcher<?> m)
+ {
+ getMatchers().put(Field.SUBJECT, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withReplyTo(Matcher<?> m)
+ {
+ getMatchers().put(Field.REPLY_TO, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withCorrelationId(Matcher<?> m)
+ {
+ getMatchers().put(Field.CORRELATION_ID, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withContentType(Matcher<?> m)
+ {
+ getMatchers().put(Field.CONTENT_TYPE, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withContentEncoding(Matcher<?> m)
+ {
+ getMatchers().put(Field.CONTENT_ENCODING, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withAbsoluteExpiryTime(Matcher<?> m)
+ {
+ getMatchers().put(Field.ABSOLUTE_EXPIRY_TIME, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withCreationTime(Matcher<?> m)
+ {
+ getMatchers().put(Field.CREATION_TIME, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withGroupId(Matcher<?> m)
+ {
+ getMatchers().put(Field.GROUP_ID, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withGroupSequence(Matcher<?> m)
+ {
+ getMatchers().put(Field.GROUP_SEQUENCE, m);
+ return this;
+ }
+
+ public MessagePropertiesSectionMatcher withReplyToGroupId(Matcher<?> m)
+ {
+ getMatchers().put(Field.REPLY_TO_GROUP_ID, m);
+ return this;
+ }
+
+ public Object getReceivedMessageId()
+ {
+ return getReceivedFields().get(Field.MESSAGE_ID);
+ }
+
+ public Object getReceivedUserId()
+ {
+ return getReceivedFields().get(Field.USER_ID);
+ }
+
+ public Object getReceivedTo()
+ {
+ return getReceivedFields().get(Field.TO);
+ }
+
+ public Object getReceivedSubject()
+ {
+ return getReceivedFields().get(Field.SUBJECT);
+ }
+
+ public Object getReceivedReplyTo()
+ {
+ return getReceivedFields().get(Field.REPLY_TO);
+ }
+
+ public Object getReceivedCorrelationId()
+ {
+ return getReceivedFields().get(Field.CORRELATION_ID);
+ }
+
+ public Object getReceivedContentType()
+ {
+ return getReceivedFields().get(Field.CONTENT_TYPE);
+ }
+
+ public Object getReceivedContentEncoding()
+ {
+ return getReceivedFields().get(Field.CONTENT_ENCODING);
+ }
+
+ public Object getReceivedAbsoluteExpiryTime()
+ {
+ return getReceivedFields().get(Field.ABSOLUTE_EXPIRY_TIME);
+ }
+
+ public Object getReceivedCreationTime()
+ {
+ return getReceivedFields().get(Field.CREATION_TIME);
+ }
+
+ public Object getReceivedGroupId()
+ {
+ return getReceivedFields().get(Field.GROUP_ID);
+ }
+
+ public Object getReceivedGroupSequence()
+ {
+ return getReceivedFields().get(Field.GROUP_SEQUENCE);
+ }
+
+ public Object getReceivedReplyToGroupId()
+ {
+ return getReceivedFields().get(Field.REPLY_TO_GROUP_ID);
+ }
+
+ @Override
+ protected Enum<?> getField(int fieldIndex)
+ {
+ return Field.values()[fieldIndex];
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/TransferPayloadCompositeMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/TransferPayloadCompositeMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/TransferPayloadCompositeMatcher.java
new file mode 100644
index 0000000..a49b8a4
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/TransferPayloadCompositeMatcher.java
@@ -0,0 +1,224 @@
+/*
+ *
+ * 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.jms.test.testpeer.matchers.sections;
+
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.StringDescription;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Used to verify the Transfer frame payload, i.e the sections of the AMQP message
+ * such as the header, properties, and body sections.
+ */
+public class TransferPayloadCompositeMatcher extends TypeSafeMatcher<Binary>
+{
+ private MessageHeaderSectionMatcher _msgHeadersMatcher;
+ private String _msgHeaderMatcherFailureDescription;
+
+ private MessageAnnotationsSectionMatcher _msgAnnotationsMatcher;
+ private String _msgAnnotationsMatcherFailureDescription;
+ private MessagePropertiesSectionMatcher _propsMatcher;
+ private String _propsMatcherFailureDescription;
+ private Matcher<Binary> _msgContentMatcher;
+ private String _msgContentMatcherFailureDescription;
+ private ApplicationPropertiesSectionMatcher _appPropsMatcher;
+ private String _appPropsMatcherFailureDescription;
+
+ public TransferPayloadCompositeMatcher()
+ {
+ }
+
+ @Override
+ protected boolean matchesSafely(final Binary receivedBinary)
+ {
+ int origLength = receivedBinary.getLength();
+ int bytesConsumed = 0;
+
+ //MessageHeader Section
+ if(_msgHeadersMatcher != null)
+ {
+ Binary msgHeaderEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+ try
+ {
+ bytesConsumed += _msgHeadersMatcher.verify(msgHeaderEtcSubBinary);
+ }
+ catch(Throwable t)
+ {
+ _msgHeaderMatcherFailureDescription = "\nActual encoded form of remaining bytes passed to MessageHeaderMatcher: " + msgHeaderEtcSubBinary;
+ _msgHeaderMatcherFailureDescription += "\nMessageHeaderMatcher generated throwable: " + t;
+
+ return false;
+ }
+ }
+
+ //MessageAnnotations Section
+ if(_msgAnnotationsMatcher != null)
+ {
+ Binary msgAnnotationsEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+ try
+ {
+ bytesConsumed += _msgAnnotationsMatcher.verify(msgAnnotationsEtcSubBinary);
+ }
+ catch(Throwable t)
+ {
+ _msgAnnotationsMatcherFailureDescription = "\nActual encoded form of remaining bytes passed to MessageAnnotationsMatcher: " + msgAnnotationsEtcSubBinary;
+ _msgAnnotationsMatcherFailureDescription += "\nMessageAnnotationsMatcher generated throwable: " + t;
+
+ return false;
+ }
+ }
+
+ //Properties Section
+ if(_propsMatcher != null)
+ {
+ Binary propsEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+ try
+ {
+ bytesConsumed += _propsMatcher.verify(propsEtcSubBinary);
+ }
+ catch(Throwable t)
+ {
+ _propsMatcherFailureDescription = "\nActual encoded form of remaining bytes passed to PropertiesMatcher: " + propsEtcSubBinary;
+ _propsMatcherFailureDescription += "\nPropertiesMatcher generated throwable: " + t;
+
+ return false;
+ }
+ }
+
+ //Application Properties Section
+ if(_appPropsMatcher != null)
+ {
+ Binary appPropsEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+ try
+ {
+ bytesConsumed += _appPropsMatcher.verify(appPropsEtcSubBinary);
+ }
+ catch(Throwable t)
+ {
+ _appPropsMatcherFailureDescription = "\nActual encoded form of remaining bytes passed to ApplicationPropertiesMatcher: " + appPropsEtcSubBinary;
+ _appPropsMatcherFailureDescription += "\nApplicationPropertiesMatcher generated throwable: " + t;
+
+ return false;
+ }
+ }
+ //Message Content Body Section, already a Matcher<Binary>
+ if(_msgContentMatcher != null)
+ {
+ Binary msgContentBodyEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+ boolean contentMatches = _msgContentMatcher.matches(msgContentBodyEtcSubBinary);
+ if(!contentMatches)
+ {
+ Description desc = new StringDescription();
+ _msgContentMatcher.describeTo(desc);
+ _msgContentMatcher.describeMismatch(msgContentBodyEtcSubBinary, desc);
+
+ _msgContentMatcherFailureDescription = "\nMessageContentMatcher mismatch Description:";
+ _msgContentMatcherFailureDescription += desc.toString();
+
+ return false;
+ }
+ }
+
+ //TODO: we will need figure out a way to determine how many bytes the
+ //MessageContentMatcher did/should consume when it comes time to handle footers
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description)
+ {
+ description.appendText("a Binary encoding of a Transfer frames payload, containing an AMQP message");
+ }
+
+ @Override
+ protected void describeMismatchSafely(Binary item, Description mismatchDescription)
+ {
+ mismatchDescription.appendText("\nActual encoded form of the full Transfer frame payload: ").appendValue(item);
+
+ //MessageHeaders Section
+ if(_msgHeaderMatcherFailureDescription != null)
+ {
+ mismatchDescription.appendText("\nMessageHeadersMatcherFailed!");
+ mismatchDescription.appendText(_msgHeaderMatcherFailureDescription);
+ return;
+ }
+
+ //MessageAnnotations Section
+ if(_msgAnnotationsMatcherFailureDescription != null)
+ {
+ mismatchDescription.appendText("\nMessageAnnotationsMatcherFailed!");
+ mismatchDescription.appendText(_msgAnnotationsMatcherFailureDescription);
+ return;
+ }
+
+ //Properties Section
+ if(_propsMatcherFailureDescription != null)
+ {
+ mismatchDescription.appendText("\nPropertiesMatcherFailed!");
+ mismatchDescription.appendText(_propsMatcherFailureDescription);
+ return;
+ }
+
+ //Application Properties Section
+ if(_appPropsMatcherFailureDescription != null)
+ {
+ mismatchDescription.appendText("\nApplicationPropertiesMatcherFailed!");
+ mismatchDescription.appendText(_appPropsMatcherFailureDescription);
+ return;
+ }
+
+ //Message Content Body Section
+ if(_msgContentMatcherFailureDescription != null)
+ {
+ mismatchDescription.appendText("\nContentMatcherFailed!");
+ mismatchDescription.appendText(_msgContentMatcherFailureDescription);
+ return;
+ }
+ }
+
+ public void setHeadersMatcher(MessageHeaderSectionMatcher msgHeadersMatcher)
+ {
+ _msgHeadersMatcher = msgHeadersMatcher;
+ }
+
+ public void setMessageAnnotationsMatcher(MessageAnnotationsSectionMatcher msgAnnotationsMatcher)
+ {
+ _msgAnnotationsMatcher = msgAnnotationsMatcher;
+ }
+
+ public void setPropertiesMatcher(MessagePropertiesSectionMatcher propsMatcher)
+ {
+ _propsMatcher = propsMatcher;
+ }
+
+ public void setApplicationPropertiesMatcher(ApplicationPropertiesSectionMatcher appPropsMatcher)
+ {
+ _appPropsMatcher = appPropsMatcher;
+ }
+
+ public void setMessageContentMatcher(Matcher<Binary> msgContentMatcher)
+ {
+ _msgContentMatcher = msgContentMatcher;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/generate-message-section-matchers.xsl
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/generate-message-section-matchers.xsl b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/generate-message-section-matchers.xsl
new file mode 100644
index 0000000..22277d3
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/generate-message-section-matchers.xsl
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="exsl">
+
+<!-- Used to generate the Java classes in this package.
+ Changes to these classes should be effected by modifying this stylesheet then re-running it,
+ using a stylesheet processor that understands the exsl directives such as xsltproc -->
+
+<xsl:template match="/">
+ <xsl:variable name="license">/*
+ * 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.
+ *
+ */
+</xsl:variable>
+
+ <xsl:for-each select="descendant-or-self::node()[name()='type']">
+ <xsl:variable name="classname">Message<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>SectionMatcher</xsl:variable>
+ <xsl:variable name="superclass">
+ <xsl:choose>
+ <xsl:when test="@name = 'header' or @name='properties'">MessageListSectionMatcher</xsl:when>
+ <xsl:otherwise>NotYetImplemented</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:if test="@provides = 'section'">
+ <xsl:if test="@name = 'header' or @name='properties'">
+ <xsl:call-template name="typeClass">
+ <xsl:with-param name="license" select="$license"/>
+ <xsl:with-param name="classname" select="$classname"/>
+ <xsl:with-param name="superclass" select="$superclass"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:if>
+
+ </xsl:for-each>
+</xsl:template>
+
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="typeClass">
+ <xsl:param name="license"/>
+ <xsl:param name="classname"/>
+ <xsl:param name="superclass"/>
+ <exsl:document href="{$classname}.java" method="text">
+ <xsl:value-of select="$license"/>
+package org.apache.qpid.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.<xsl:value-of select="$superclass"/>;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-message-section-matchers.xsl, which resides in this package.
+ */
+public class <xsl:value-of select="$classname"/> extends <xsl:value-of select="$superclass"/>
+{
+
+ public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("<xsl:value-of select="descendant::node()[name()='descriptor']/@name"/>");
+ public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(<xsl:value-of select="concat(substring(descendant::node()[name()='descriptor']/@code,1,10),substring(descendant::node()[name()='descriptor']/@code,14))"/>L);
+
+ /** Note that the ordinals of the Field enums match the order specified in the AMQP spec */
+ public enum Field
+ {
+<xsl:for-each select="descendant::node()[name()='field']">
+<xsl:text> </xsl:text><xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>,
+</xsl:for-each> }
+
+ public <xsl:value-of select="$classname"/>(boolean expectTrailingBytes)
+ {
+ super(DESCRIPTOR_CODE,
+ DESCRIPTOR_SYMBOL,
+ new HashMap<Object, Matcher<?>>(),
+ expectTrailingBytes);
+ }
+
+<xsl:for-each select="descendant::node()[name()='field']">
+ public <xsl:value-of select="$classname"/> with<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>(Matcher<?> m)
+ {
+ getMatchers().put(Field.<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>, m);
+ return this;
+ }
+</xsl:for-each>
+<xsl:for-each select="descendant::node()[name()='field']">
+ public Object getReceived<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>()
+ {
+ return getReceivedFields().get(Field.<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>);
+ }
+</xsl:for-each>
+ @Override
+ protected Enum<?> getField(int fieldIndex)
+ {
+ return Field.values()[fieldIndex];
+ }
+}
+
+</exsl:document>
+
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="constructFromLiteral">
+ <xsl:param name="type"/>
+ <xsl:param name="value"/>
+ <xsl:choose>
+ <xsl:when test="$type = 'string'">"<xsl:value-of select="$value"/></xsl:when>
+ <xsl:when test="$type = 'symbol'">Symbol.valueOf("<xsl:value-of select="$value"/>")</xsl:when>
+ <xsl:when test="$type = 'ubyte'">UnsignedByte.valueOf((byte) <xsl:value-of select="$value"/>)</xsl:when>
+ <xsl:when test="$type = 'ushort'">UnsignedShort.valueOf((short) <xsl:value-of select="$value"/>)</xsl:when>
+ <xsl:when test="$type = 'uint'">UnsignedInteger.valueOf(<xsl:value-of select="$value"/>)</xsl:when>
+ <xsl:when test="$type = 'ulong'">UnsignedLong.valueOf(<xsl:value-of select="$value"/>L)</xsl:when>
+ <xsl:when test="$type = 'long'"><xsl:value-of select="$value"/>L</xsl:when>
+ <xsl:when test="$type = 'short'">(short)<xsl:value-of select="$value"/></xsl:when>
+ <xsl:when test="$type = 'short'">(byte)<xsl:value-of select="$value"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+<xsl:template name="substringAfterLast"><xsl:param name="input"/><xsl:param name="arg"/>
+ <xsl:choose>
+ <xsl:when test="contains($input,$arg)"><xsl:call-template name="substringAfterLast"><xsl:with-param name="input"><xsl:value-of select="substring-after($input,$arg)"/></xsl:with-param><xsl:with-param name="arg"><xsl:value-of select="$arg"/></xsl:with-param></xsl:call-template></xsl:when>
+ <xsl:otherwise><xsl:value-of select="$input"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="initCap"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+ <xsl:template name="initLower"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+ <xsl:template name="toUpper"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:template>
+
+ <xsl:template name="toUpperDashToUnderscore"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz-','ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/></xsl:template>
+
+ <xsl:template name="dashToCamel">
+ <xsl:param name="input"/>
+ <xsl:choose>
+ <xsl:when test="contains($input,'-')"><xsl:call-template name="initCap"><xsl:with-param name="input" select="substring-before($input,'-')"/></xsl:call-template><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="substring-after($input,'-')"/></xsl:call-template></xsl:when>
+ <xsl:otherwise><xsl:call-template name="initCap"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="dashToLowerCamel">
+ <xsl:param name="input"/>
+ <xsl:call-template name="initLower"><xsl:with-param name="input"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:with-param></xsl:call-template>
+ </xsl:template>
+</xsl:stylesheet>
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpTypeMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpTypeMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpTypeMatcher.java
new file mode 100644
index 0000000..797ee4a
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpTypeMatcher.java
@@ -0,0 +1,114 @@
+/*
+ * 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.jms.test.testpeer.matchers.types;
+
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.proton.codec.Data;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+
+public abstract class EncodedAmqpTypeMatcher extends TypeSafeMatcher<Binary>
+{
+ private final Symbol _descriptorSymbol;
+ private final UnsignedLong _descriptorCode;
+ private final Object _expectedValue;
+ private boolean _permitTrailingBytes;
+ private DescribedType _decodedDescribedType;
+ private boolean _unexpectedTrailingBytes;
+
+ public EncodedAmqpTypeMatcher(Symbol symbol, UnsignedLong code, Object expectedValue)
+ {
+ this(symbol, code, expectedValue, false);
+ }
+
+ public EncodedAmqpTypeMatcher(Symbol symbol, UnsignedLong code, Object expectedValue, boolean permitTrailingBytes)
+ {
+ _descriptorSymbol = symbol;
+ _descriptorCode = code;
+ _expectedValue = expectedValue;
+ _permitTrailingBytes = permitTrailingBytes;
+ }
+
+ protected Object getExpectedValue()
+ {
+ return _expectedValue;
+ }
+
+ @Override
+ protected boolean matchesSafely(Binary receivedBinary)
+ {
+ int length = receivedBinary.getLength();
+ Data data = Proton.data(length);
+ long decoded = data.decode(receivedBinary.asByteBuffer());
+ _decodedDescribedType = data.getDescribedType();
+ Object descriptor = _decodedDescribedType.getDescriptor();
+
+ if(!(_descriptorCode.equals(descriptor) || _descriptorSymbol.equals(descriptor)))
+ {
+ return false;
+ }
+
+ if(_expectedValue == null && _decodedDescribedType.getDescribed() != null)
+ {
+ return false;
+ }
+ else if(_expectedValue != null && !_expectedValue.equals(_decodedDescribedType.getDescribed()))
+ {
+ return false;
+ }
+
+ if(decoded < length && !_permitTrailingBytes)
+ {
+ _unexpectedTrailingBytes = true;
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ protected void describeMismatchSafely(Binary item, Description mismatchDescription)
+ {
+ mismatchDescription.appendText("\nActual encoded form: ").appendValue(item);
+
+ if(_decodedDescribedType != null)
+ {
+ mismatchDescription.appendText("\nExpected descriptor: ")
+ .appendValue(_descriptorSymbol)
+ .appendText(" / ")
+ .appendValue(_descriptorCode);
+
+ mismatchDescription.appendText("\nActual described type: ").appendValue(_decodedDescribedType);
+ }
+
+ if(_unexpectedTrailingBytes)
+ {
+ mismatchDescription.appendText("\nUnexpected trailing bytes in provided bytes after decoding!");
+ }
+ }
+
+ /**
+ * Provide a description of this matcher.
+ */
+ public abstract void describeTo(Description description);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpValueMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpValueMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpValueMatcher.java
new file mode 100644
index 0000000..93dcc36
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpValueMatcher.java
@@ -0,0 +1,56 @@
+/*
+ * 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.jms.test.testpeer.matchers.types;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Description;
+
+public class EncodedAmqpValueMatcher extends EncodedAmqpTypeMatcher
+{
+ private static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:amqp-value:*");
+ private static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000077L);
+
+ /**
+ * @param expectedValue the value that is expected to be IN the
+ * received {@link AmqpValue}
+ */
+ public EncodedAmqpValueMatcher(Object expectedValue)
+ {
+ this(expectedValue,false);
+ }
+
+ /**
+ * @param expectedValue the value that is expected to be IN the
+ * received {@link AmqpValue}
+ * @param permitTrailingBytes if it is permitted for bytes to be left in the Binary after consuming the {@link AmqpValue}
+ */
+ public EncodedAmqpValueMatcher(Object expectedValue, boolean permitTrailingBytes)
+ {
+ super(DESCRIPTOR_SYMBOL, DESCRIPTOR_CODE, expectedValue, permitTrailingBytes);
+ }
+
+ @Override
+ public void describeTo(Description description)
+ {
+ description
+ .appendText("a Binary encoding of an AmqpValue that wraps: ")
+ .appendValue(getExpectedValue());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedDataMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedDataMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedDataMatcher.java
new file mode 100644
index 0000000..94cea5e
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedDataMatcher.java
@@ -0,0 +1,58 @@
+/*
+ * 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.jms.test.testpeer.matchers.types;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Description;
+
+public class EncodedDataMatcher extends EncodedAmqpTypeMatcher
+{
+ private static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:data:binary");
+ private static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000075L);
+
+ /**
+ * @param expectedValue the value that is expected to be IN the
+ * received {@link org.apache.qpid.proton.amqp.messaging.Data}
+ */
+ public EncodedDataMatcher(Binary expectedValue)
+ {
+ this(expectedValue, false);
+ }
+
+ /**
+ * @param expectedValue the value that is expected to be IN the
+ * received {@link org.apache.qpid.proton.amqp.messaging.Data}
+ * @param permitTrailingBytes if it is permitted for bytes to be left in the Binary after consuming the {@link AmqpValue}
+ */
+ public EncodedDataMatcher(Binary expectedValue, boolean permitTrailingBytes)
+ {
+ super(DESCRIPTOR_SYMBOL, DESCRIPTOR_CODE, expectedValue, permitTrailingBytes);
+ }
+
+ @Override
+ public void describeTo(Description description)
+ {
+ description
+ .appendText("a Binary encoding of a Data that wraps a Binary containing: ")
+ .appendValue(getExpectedValue());
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
new file mode 100644
index 0000000..7459e82
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
@@ -0,0 +1,216 @@
+/**
+ * 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.jms.util;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.jms.util.PropertyUtil;
+import org.apache.qpid.jms.util.URISupport;
+import org.apache.qpid.jms.util.URISupport.CompositeData;
+
+import junit.framework.TestCase;
+
+public class URISupportTest extends TestCase {
+
+ public void testEmptyCompositePath() throws Exception {
+ CompositeData data = URISupport.parseComposite(new URI("broker:()/localhost?persistent=false"));
+ assertEquals(0, data.getComponents().length);
+ }
+
+ public void testCompositePath() throws Exception {
+ CompositeData data = URISupport.parseComposite(new URI("test:(path)/path"));
+ assertEquals("path", data.getPath());
+ data = URISupport.parseComposite(new URI("test:path"));
+ assertNull(data.getPath());
+ }
+
+ public void testSimpleComposite() throws Exception {
+ CompositeData data = URISupport.parseComposite(new URI("test:part1"));
+ assertEquals(1, data.getComponents().length);
+ }
+
+ public void testComposite() throws Exception {
+ URI uri = new URI("test:(part1://host,part2://(sub1://part,sube2:part))");
+ CompositeData data = URISupport.parseComposite(uri);
+ assertEquals(2, data.getComponents().length);
+ }
+
+ public void testEmptyCompositeWithParenthesisInParam() throws Exception {
+ URI uri = new URI("failover://()?updateURIsURL=file:/C:/Dir(1)/a.csv");
+ CompositeData data = URISupport.parseComposite(uri);
+ assertEquals(0, data.getComponents().length);
+ assertEquals(1, data.getParameters().size());
+ assertTrue(data.getParameters().containsKey("updateURIsURL"));
+ assertEquals("file:/C:/Dir(1)/a.csv", data.getParameters().get("updateURIsURL"));
+ }
+
+ public void testCompositeWithParenthesisInParam() throws Exception {
+ URI uri = new URI("failover://(test)?updateURIsURL=file:/C:/Dir(1)/a.csv");
+ CompositeData data = URISupport.parseComposite(uri);
+ assertEquals(1, data.getComponents().length);
+ assertEquals(1, data.getParameters().size());
+ assertTrue(data.getParameters().containsKey("updateURIsURL"));
+ assertEquals("file:/C:/Dir(1)/a.csv", data.getParameters().get("updateURIsURL"));
+ }
+
+ public void testCompositeWithComponentParam() throws Exception {
+ CompositeData data = URISupport.parseComposite(new URI("test:(part1://host?part1=true)?outside=true"));
+ assertEquals(1, data.getComponents().length);
+ assertEquals(1, data.getParameters().size());
+ Map<String, String> part1Params = URISupport.parseParameters(data.getComponents()[0]);
+ assertEquals(1, part1Params.size());
+ assertTrue(part1Params.containsKey("part1"));
+ }
+
+ public void testParsingURI() throws Exception {
+ URI source = new URI("tcp://localhost:61626/foo/bar?cheese=Edam&x=123");
+
+ Map<String, String> map = PropertyUtil.parseParameters(source);
+
+ assertEquals("Size: " + map, 2, map.size());
+ assertMapKey(map, "cheese", "Edam");
+ assertMapKey(map, "x", "123");
+
+ URI result = URISupport.removeQuery(source);
+
+ assertEquals("result", new URI("tcp://localhost:61626/foo/bar"), result);
+ }
+
+ protected void assertMapKey(Map<String, String> map, String key, Object expected) {
+ assertEquals("Map key: " + key, map.get(key), expected);
+ }
+
+ public void testParsingCompositeURI() throws URISyntaxException {
+ CompositeData data = URISupport.parseComposite(new URI("broker://(tcp://localhost:61616)?name=foo"));
+ assertEquals("one component", 1, data.getComponents().length);
+ assertEquals("Size: " + data.getParameters(), 1, data.getParameters().size());
+ }
+
+ public void testCheckParenthesis() throws Exception {
+ String str = "fred:(((ddd))";
+ assertFalse(URISupport.checkParenthesis(str));
+ str += ")";
+ assertTrue(URISupport.checkParenthesis(str));
+ }
+
+ public void testCreateWithQuery() throws Exception {
+ URI source = new URI("vm://localhost");
+ URI dest = PropertyUtil.replaceQuery(source, "network=true&one=two");
+
+ assertEquals("correct param count", 2, URISupport.parseParameters(dest).size());
+ assertEquals("same uri, host", source.getHost(), dest.getHost());
+ assertEquals("same uri, scheme", source.getScheme(), dest.getScheme());
+ assertFalse("same uri, ssp", dest.getQuery().equals(source.getQuery()));
+ }
+
+ public void testParsingParams() throws Exception {
+ URI uri = new URI("static:(http://localhost:61617?proxyHost=jo&proxyPort=90)?proxyHost=localhost&proxyPort=80");
+ Map<String,String>parameters = URISupport.parseParameters(uri);
+ verifyParams(parameters);
+ uri = new URI("static://http://localhost:61617?proxyHost=localhost&proxyPort=80");
+ parameters = URISupport.parseParameters(uri);
+ verifyParams(parameters);
+ uri = new URI("http://0.0.0.0:61616");
+ parameters = URISupport.parseParameters(uri);
+ }
+
+ public void testCompositeCreateURIWithQuery() throws Exception {
+ String queryString = "query=value";
+ URI originalURI = new URI("outerscheme:(innerscheme:innerssp)");
+ URI querylessURI = originalURI;
+ assertEquals(querylessURI, PropertyUtil.eraseQuery(originalURI));
+ assertEquals(querylessURI, PropertyUtil.replaceQuery(originalURI, ""));
+ assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
+ originalURI = new URI("outerscheme:(innerscheme:innerssp)?outerquery=0");
+ assertEquals(querylessURI, PropertyUtil.eraseQuery(originalURI));
+ assertEquals(querylessURI, PropertyUtil.replaceQuery(originalURI, ""));
+ assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
+ originalURI = new URI("outerscheme:(innerscheme:innerssp?innerquery=0)");
+ querylessURI = originalURI;
+ assertEquals(querylessURI, PropertyUtil.eraseQuery(originalURI));
+ assertEquals(querylessURI, PropertyUtil.replaceQuery(originalURI, ""));
+ assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
+ originalURI = new URI("outerscheme:(innerscheme:innerssp?innerquery=0)?outerquery=0");
+ assertEquals(querylessURI, PropertyUtil.eraseQuery(originalURI));
+ assertEquals(querylessURI, PropertyUtil.replaceQuery(originalURI, ""));
+ assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
+ }
+
+ public void testApplyParameters() throws Exception {
+
+ URI uri = new URI("http://0.0.0.0:61616");
+ Map<String,String> parameters = new HashMap<String, String>();
+ parameters.put("t.proxyHost", "localhost");
+ parameters.put("t.proxyPort", "80");
+
+ uri = URISupport.applyParameters(uri, parameters);
+ Map<String,String> appliedParameters = URISupport.parseParameters(uri);
+ assertEquals("all params applied with no prefix", 2, appliedParameters.size());
+
+ // strip off params again
+ uri = PropertyUtil.eraseQuery(uri);
+
+ uri = URISupport.applyParameters(uri, parameters, "joe");
+ appliedParameters = URISupport.parseParameters(uri);
+ assertTrue("no params applied as none match joe", appliedParameters.isEmpty());
+
+ uri = URISupport.applyParameters(uri, parameters, "t.");
+ verifyParams(URISupport.parseParameters(uri));
+ }
+
+ private void verifyParams(Map<String,String> parameters) {
+ assertEquals(parameters.get("proxyHost"), "localhost");
+ assertEquals(parameters.get("proxyPort"), "80");
+ }
+
+ public void testIsCompositeURIWithQueryNoSlashes() throws URISyntaxException {
+ URI[] compositeURIs = new URI[] { new URI("test:(part1://host?part1=true)?outside=true"), new URI("broker:(tcp://localhost:61616)?name=foo") };
+ for (URI uri : compositeURIs) {
+ assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
+ }
+ }
+
+ public void testIsCompositeURIWithQueryAndSlashes() throws URISyntaxException {
+ URI[] compositeURIs = new URI[] { new URI("test://(part1://host?part1=true)?outside=true"), new URI("broker://(tcp://localhost:61616)?name=foo") };
+ for (URI uri : compositeURIs) {
+ assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
+ }
+ }
+
+ public void testIsCompositeURINoQueryNoSlashes() throws URISyntaxException {
+ URI[] compositeURIs = new URI[] { new URI("test:(part1://host,part2://(sub1://part,sube2:part))"), new URI("test:(path)/path") };
+ for (URI uri : compositeURIs) {
+ assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
+ }
+ }
+
+ public void testIsCompositeURINoQueryNoSlashesNoParentheses() throws URISyntaxException {
+ assertFalse("test:part1" + " must be detected as non-composite URI", URISupport.isCompositeURI(new URI("test:part1")));
+ }
+
+ public void testIsCompositeURINoQueryWithSlashes() throws URISyntaxException {
+ URI[] compositeURIs = new URI[] { new URI("failover://(tcp://bla:61616,tcp://bla:61617)"),
+ new URI("failover://(tcp://localhost:61616,ssl://anotherhost:61617)") };
+ for (URI uri : compositeURIs) {
+ assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/resources/keystore
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/resources/keystore b/qpid-jms-client/src/test/resources/keystore
new file mode 100644
index 0000000..9ee6adf
Binary files /dev/null and b/qpid-jms-client/src/test/resources/keystore differ
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/resources/log4j.properties b/qpid-jms-client/src/test/resources/log4j.properties
new file mode 100644
index 0000000..8df5a9e
--- /dev/null
+++ b/qpid-jms-client/src/test/resources/log4j.properties
@@ -0,0 +1,38 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, out, stdout
+
+log4j.logger.org.apache.qpid.jms=DEBUG
+
+# Tune the TestPeer as needed for debugging.
+log4j.logger.org.apache.qpid.jms.test.testpeer=TRACE
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/activemq-test.log
+log4j.appender.out.append=true
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/.gitignore
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/.gitignore b/qpid-jms-discovery/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/qpid-jms-discovery/.gitignore
@@ -0,0 +1 @@
+/target
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/pom.xml
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/pom.xml b/qpid-jms-discovery/pom.xml
new file mode 100644
index 0000000..58204cf
--- /dev/null
+++ b/qpid-jms-discovery/pom.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.qpid</groupId>
+ <artifactId>qpid-jms-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>qpid-jms-discovery</artifactId>
+ <name>QpidJMS Discovery Library</name>
+ <description>The Broker Discovery module for QpidJMS</description>
+ <packaging>jar</packaging>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <!-- =================================== -->
+ <!-- Required Dependencies -->
+ <!-- =================================== -->
+ <dependency>
+ <groupId>org.apache.qpid</groupId>
+ <artifactId>qpid-jms-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <!-- =================================== -->
+ <!-- Testing Dependencies -->
+ <!-- =================================== -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>activemq-broker</artifactId>
+ <version>${activemq-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>activemq-kahadb-store</artifactId>
+ <version>${activemq-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>activemq-amqp</artifactId>
+ <version>${activemq-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>activemq-jaas</artifactId>
+ <version>${activemq-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>activemq-spring</artifactId>
+ <version>${activemq-version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgent.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgent.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgent.java
new file mode 100644
index 0000000..051f567
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgent.java
@@ -0,0 +1,63 @@
+/**
+ * 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.jms.provider.discovery;
+
+import java.io.IOException;
+
+/**
+ * Interface for all agents used to detect instances of remote peers on the network.
+ */
+public interface DiscoveryAgent {
+
+ /**
+ * Sets the discovery listener
+ *
+ * @param listener
+ * the listener to notify on discovery events, or null to clear.
+ */
+ void setDiscoveryListener(DiscoveryListener listener);
+
+ /**
+ * Starts the agent after which new remote peers can start to be found.
+ *
+ * @throws IOException if an IO error occurs while starting the agent.
+ * @throws IllegalStateException if the agent is not properly configured.
+ */
+ void start() throws IOException, IllegalStateException;
+
+ /**
+ * Stops the agent after which no new remote peers will be found. This
+ * method should attempt to close any agent resources and if an error occurs
+ * it should handle it and not re-throw to the calling entity.
+ */
+ void close();
+
+ /**
+ * Suspends the Agent which suppresses any new attempts to discover remote
+ * peers until the agent is resumed. If the service is not able to be suspended
+ * then this method should not throw an Exception, simply return as if successful.
+ */
+ void suspend();
+
+ /**
+ * Resumes discovery by this agent if it was previously suspended. If the agent
+ * does not support being suspended or is closed this method should simply return
+ * without throwing any exceptions.
+ */
+ void resume();
+
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgentFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgentFactory.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgentFactory.java
new file mode 100644
index 0000000..f37745c
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgentFactory.java
@@ -0,0 +1,112 @@
+/**
+ * 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.jms.provider.discovery;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.qpid.jms.util.FactoryFinder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory used to find and create instances of DiscoveryAgent using the name
+ * of the desired agent to locate it's factory class definition file.
+ */
+public abstract class DiscoveryAgentFactory {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DiscoveryAgentFactory.class);
+
+ private static final FactoryFinder<DiscoveryAgentFactory> AGENT_FACTORY_FINDER =
+ new FactoryFinder<DiscoveryAgentFactory>(DiscoveryAgentFactory.class,
+ "META-INF/services/org/apache/qpid/jms/provider/agents/");
+
+ /**
+ * Creates an instance of the given DiscoveryAgent and configures it using the
+ * properties set on the given remote broker URI.
+ *
+ * @param remoteURI
+ * The URI used to configure remote discovery.
+ *
+ * @return a new DiscoveryAgent instance.
+ *
+ * @throws Exception if an error occurs while creating the DiscoveryAgent instance.
+ */
+ public abstract DiscoveryAgent createDiscoveryAgent(URI remoteURI) throws Exception;
+
+ /**
+ * @return the name of this discovery agent, e.g. Multicast, Zeroconf, etc.
+ */
+ public abstract String getName();
+
+ /**
+ * Static create method that performs the DiscoveryAgent search and handles the
+ * configuration and setup.
+ *
+ * @param remoteURI
+ * the URI used to configure the discovery mechanism.
+ *
+ * @return a new DiscoveryAgent instance that is ready for use.
+ *
+ * @throws Exception if an error occurs while creating the DiscoveryAgent instance.
+ */
+ public static DiscoveryAgent createAgent(URI remoteURI) throws Exception {
+ DiscoveryAgent result = null;
+
+ try {
+ DiscoveryAgentFactory factory = findAgentFactory(remoteURI);
+ result = factory.createDiscoveryAgent(remoteURI);
+ } catch (Exception ex) {
+ LOG.error("Failed to create DiscoveryAgent instance for: {}", remoteURI.getScheme());
+ LOG.trace("Error: ", ex);
+ throw ex;
+ }
+
+ return result;
+ }
+
+ /**
+ * Searches for a DiscoveryAgentFactory by using the scheme from the given URI.
+ *
+ * The search first checks the local cache of discovery agent factories before moving on
+ * to search in the classpath.
+ *
+ * @param location
+ * The URI whose scheme will be used to locate a DiscoveryAgentFactory.
+ *
+ * @return a DiscoveryAgentFactory instance matching the URI's scheme.
+ *
+ * @throws IOException if an error occurs while locating the factory.
+ */
+ protected static DiscoveryAgentFactory findAgentFactory(URI location) throws IOException {
+ String scheme = location.getScheme();
+ if (scheme == null) {
+ throw new IOException("No Discovery Agent scheme specified: [" + location + "]");
+ }
+
+ DiscoveryAgentFactory factory = null;
+ if (factory == null) {
+ try {
+ factory = AGENT_FACTORY_FINDER.newInstance(scheme);
+ } catch (Throwable e) {
+ throw new IOException("Discovery Agent scheme NOT recognized: [" + scheme + "]", e);
+ }
+ }
+
+ return factory;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryEvent.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryEvent.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryEvent.java
new file mode 100644
index 0000000..0fc2f29
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryEvent.java
@@ -0,0 +1,45 @@
+/**
+ * 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.jms.provider.discovery;
+
+/**
+ * Event class used to convey discovered remote peer information to the
+ * DiscoveryProvider.
+ */
+public class DiscoveryEvent {
+
+ public enum EventType {
+ ALIVE,
+ SHUTDOWN
+ };
+
+ private final String peerUri;
+ private final EventType type;
+
+ public DiscoveryEvent(String peerUri, EventType type) {
+ this.peerUri = peerUri;
+ this.type = type;
+ }
+
+ public String getPeerUri() {
+ return peerUri;
+ }
+
+ public EventType getType() {
+ return type;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryListener.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryListener.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryListener.java
new file mode 100644
index 0000000..07e9895
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryListener.java
@@ -0,0 +1,40 @@
+/**
+ * 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.jms.provider.discovery;
+
+/**
+ * A listener of services being added or removed from a network
+ */
+public interface DiscoveryListener {
+
+ /**
+ * Called when a DiscoveryAgent becomes aware of a new remote peer.
+ *
+ * @param event
+ * the event data which contains the peer address and optional name.
+ */
+ void onServiceAdd(DiscoveryEvent event);
+
+ /**
+ * Called when a DiscoveryAgent can no longer detect a previously known remote peer.
+ *
+ * @param event
+ * the event data which contains the peer address and optional name.
+ */
+ void onServiceRemove(DiscoveryEvent event);
+
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProvider.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProvider.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProvider.java
new file mode 100644
index 0000000..1d3a0f0
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProvider.java
@@ -0,0 +1,139 @@
+/**
+ * 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.jms.provider.discovery;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.qpid.jms.provider.ProviderWrapper;
+import org.apache.qpid.jms.provider.failover.FailoverProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An AsyncProvider instance that wraps the FailoverProvider and listens for
+ * events about discovered remote peers using a configured DiscoveryAgent
+ * instance.
+ */
+public class DiscoveryProvider extends ProviderWrapper<FailoverProvider> implements DiscoveryListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DiscoveryProviderFactory.class);
+
+ private final URI discoveryUri;
+ private DiscoveryAgent discoveryAgent;
+ private final ConcurrentHashMap<String, URI> serviceURIs = new ConcurrentHashMap<String, URI>();
+
+ /**
+ * Creates a new instance of the DiscoveryProvider.
+ *
+ * The Provider is created and initialized with the original URI used to create it,
+ * and an instance of a FailoverProcider which it will use to initiate and maintain
+ * connections to the discovered peers.
+ *
+ * @param discoveryUri
+ * @param next
+ */
+ public DiscoveryProvider(URI discoveryUri, FailoverProvider next) {
+ super(next);
+ this.discoveryUri = discoveryUri;
+ }
+
+ @Override
+ public void start() throws IOException, IllegalStateException {
+ if (this.discoveryAgent == null) {
+ throw new IllegalStateException("No DiscoveryAgent configured.");
+ }
+
+ discoveryAgent.setDiscoveryListener(this);
+ discoveryAgent.start();
+
+ super.start();
+ }
+
+ @Override
+ public void close() {
+ discoveryAgent.close();
+ super.close();
+ }
+
+ //------------------- Property Accessors ---------------------------------//
+
+ /**
+ * @return the original URI used to configure this DiscoveryProvider.
+ */
+ public URI getDiscoveryURI() {
+ return this.discoveryUri;
+ }
+
+ /**
+ * @return the configured DiscoveryAgent instance used by this DiscoveryProvider.
+ */
+ public DiscoveryAgent getDiscoveryAgent() {
+ return this.discoveryAgent;
+ }
+
+ /**
+ * Sets the discovery agent used by this provider to locate remote peer instance.
+ *
+ * @param agent
+ * the agent to use to discover remote peers
+ */
+ public void setDiscoveryAgent(DiscoveryAgent agent) {
+ this.discoveryAgent = agent;
+ }
+
+ //------------------- Discovery Event Handlers ---------------------------//
+
+ @Override
+ public void onServiceAdd(DiscoveryEvent event) {
+ String url = event.getPeerUri();
+ if (url != null) {
+ try {
+ URI uri = new URI(url);
+ LOG.info("Adding new peer connection URL: {}", uri);
+ serviceURIs.put(event.getPeerUri(), uri);
+ next.add(uri);
+ } catch (URISyntaxException e) {
+ LOG.warn("Could not add remote URI: {} due to bad URI syntax: {}", url, e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public void onServiceRemove(DiscoveryEvent event) {
+ URI uri = serviceURIs.get(event.getPeerUri());
+ if (uri != null) {
+ next.remove(uri);
+ }
+ }
+
+ //------------------- Connection State Handlers --------------------------//
+
+ @Override
+ public void onConnectionInterrupted(URI remoteURI) {
+ this.discoveryAgent.resume();
+ super.onConnectionInterrupted(remoteURI);
+ }
+
+ @Override
+ public void onConnectionRestored(URI remoteURI) {
+ this.discoveryAgent.suspend();
+ super.onConnectionRestored(remoteURI);
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProviderFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProviderFactory.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProviderFactory.java
new file mode 100644
index 0000000..cd2ab5a
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProviderFactory.java
@@ -0,0 +1,65 @@
+/**
+ * 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.jms.provider.discovery;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFactory;
+import org.apache.qpid.jms.provider.failover.FailoverProvider;
+import org.apache.qpid.jms.util.PropertyUtil;
+import org.apache.qpid.jms.util.URISupport;
+import org.apache.qpid.jms.util.URISupport.CompositeData;
+
+/**
+ * Factory for creating the Discovery Provider
+ */
+public class DiscoveryProviderFactory extends ProviderFactory {
+
+ private static final String DISCOVERED_OPTION_PREFIX = "discovered.";
+
+ @Override
+ public Provider createAsyncProvider(URI remoteURI) throws Exception {
+
+ CompositeData composite = URISupport.parseComposite(remoteURI);
+ Map<String, String> options = composite.getParameters();
+
+ // Failover will apply the nested options to each URI while attempting to connect.
+ Map<String, String> nested = PropertyUtil.filterProperties(options, DISCOVERED_OPTION_PREFIX);
+ FailoverProvider failover = new FailoverProvider(nested);
+ PropertyUtil.setProperties(failover, options);
+
+ // TODO - Revisit URI options setting and enhance the ProperyUtils to provide a
+ // means of setting some properties on a object and obtaining the leftovers
+ // so we can pass those along to the next until we consume them all or we
+ // have leftovers which implies a bad URI.
+
+ DiscoveryProvider discovery = new DiscoveryProvider(remoteURI, failover);
+ PropertyUtil.setProperties(discovery, options);
+
+ DiscoveryAgent agent = DiscoveryAgentFactory.createAgent(composite.getComponents()[0]);
+ discovery.setDiscoveryAgent(agent);
+
+ return discovery;
+ }
+
+ @Override
+ public String getName() {
+ return "Discovery";
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org