summaryrefslogtreecommitdiff
path: root/java/client/src
diff options
context:
space:
mode:
authorRafael H. Schloming <rhs@apache.org>2009-12-26 12:42:57 +0000
committerRafael H. Schloming <rhs@apache.org>2009-12-26 12:42:57 +0000
commit248f1fe188fe2307b9dcf2c87a83b653eaa1920c (patch)
treed5d0959a70218946ff72e107a6c106e32479a398 /java/client/src
parent3c83a0e3ec7cf4dc23e83a340b25f5fc1676f937 (diff)
downloadqpid-python-248f1fe188fe2307b9dcf2c87a83b653eaa1920c.tar.gz
synchronized with trunk except for ruby dir
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/qpid.rnr@893970 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/client/src')
-rwxr-xr-xjava/client/src/main/java/client.bnd7
-rw-r--r--java/client/src/main/java/log4j.xml36
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java56
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java5
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java28
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnection.java272
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java32
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java204
-rwxr-xr-xjava/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java8
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java88
-rwxr-xr-x[-rw-r--r--]java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_9_1.java (renamed from java/client/src/main/java/org/apache/qpid/nclient/ClosedListener.java)32
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java11
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java9
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQDestination.java26
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java68
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession.java509
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java318
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java63
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java45
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java138
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java20
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java38
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java54
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java22
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/Closeable.java18
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java24
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java11
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java31
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java32
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java33
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java91
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java14
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl_0_91.java158
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java8
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java122
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java70
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java151
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java52
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java7
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java16
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java47
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java7
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java4
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java125
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java547
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java124
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java16
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java7
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java24
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java71
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java48
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java17
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/url/URLParser.java44
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java18
-rw-r--r--java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java18
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java15
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java317
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java3
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java72
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java10
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/NoFailover.java62
-rw-r--r--java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java29
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/Client.java295
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/Connection.java86
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/DtxSession.java137
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/JMSTestCase.java115
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/Session.java544
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSession.java142
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSessionDelegate.java47
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/impl/Constants.java78
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/impl/DemoClient.java93
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/interop/BasicInteropTest.java155
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/FileMessage.java96
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/ReadOnlyMessage.java38
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/StreamingMessage.java68
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/AMQQueueTest.java42
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java94
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/message/AbstractJMSMessageTest.java36
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java289
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/protocol/MockIoSession.java312
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java7
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java16
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java12
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java2
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java2
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/jndi/ConnectionFactoryTest.java75
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDIPropertyFileTest.java70
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDITest.properties28
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java7
109 files changed, 4174 insertions, 3432 deletions
diff --git a/java/client/src/main/java/client.bnd b/java/client/src/main/java/client.bnd
new file mode 100755
index 0000000000..a8a33532fb
--- /dev/null
+++ b/java/client/src/main/java/client.bnd
@@ -0,0 +1,7 @@
+ver: 0.6.0
+
+Bundle-SymbolicName: qpid-client
+Bundle-Version: ${ver}
+Export-Package: *;version=${ver}
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+
diff --git a/java/client/src/main/java/log4j.xml b/java/client/src/main/java/log4j.xml
new file mode 100644
index 0000000000..c27acba818
--- /dev/null
+++ b/java/client/src/main/java/log4j.xml
@@ -0,0 +1,36 @@
+<!--
+
+ -
+ - 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.
+ -
+-->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="console" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
+ </layout>
+ </appender>
+
+ <logger name="org.apache.qpid">
+ <level value="warn"/>
+ <appender-ref ref="console" />
+ </logger>
+
+</log4j:configuration>
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java b/java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java
new file mode 100644
index 0000000000..4bb2c12cc8
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.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.client;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.url.BindingURL;
+
+/**
+ * In order to support JMS 1.0 the Qpid implementation maps the
+ * direct exchange to JMS Queue and topic exchange to JMS Topic.
+ *
+ * The JMS 1.1 spec provides a javax.Destination as an abstraction
+ * to represent any type of destination.
+ * The abstract class AMQDestination has most of the functionality
+ * to support any destination defined in AMQP 0-10 spec.
+ */
+public class AMQAnyDestination extends AMQDestination
+{
+ public AMQAnyDestination(BindingURL binding)
+ {
+ super(binding);
+ }
+
+ public AMQAnyDestination(AMQShortString exchangeName,AMQShortString exchangeClass,
+ AMQShortString routingKey,boolean isExclusive,
+ boolean isAutoDelete, AMQShortString queueName,
+ boolean isDurable, AMQShortString[] bindingKeys)
+ {
+ super(exchangeName, exchangeClass, routingKey, isExclusive, isAutoDelete, queueName, isDurable, bindingKeys);
+ }
+
+ @Override
+ public boolean isNameRequired()
+ {
+ return getAMQQueueName() == null;
+ }
+
+}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java b/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
index 05ac3dca9e..6bae0166d1 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
@@ -39,9 +39,4 @@ public class AMQAuthenticationException extends AMQException
{
super(error, msg, cause);
}
- public boolean isHardError()
- {
- return true;
- }
-
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java b/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
index f051450260..414638dea4 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
import org.apache.qpid.url.URLHelper;
import org.apache.qpid.url.URLSyntaxException;
@@ -35,18 +36,15 @@ public class AMQBrokerDetails implements BrokerDetails
private int _port;
private String _transport;
- private Map<String, String> _options;
+ private Map<String, String> _options = new HashMap<String, String>();
private SSLConfiguration _sslConfiguration;
- public AMQBrokerDetails()
- {
- _options = new HashMap<String, String>();
- }
-
+ public AMQBrokerDetails(){}
+
public AMQBrokerDetails(String url) throws URLSyntaxException
- {
- this();
+ {
+
// URL should be of format tcp://host:port?option='value',option='value'
try
{
@@ -81,6 +79,10 @@ public class AMQBrokerDetails implements BrokerDetails
}
}
}
+ else if (url.indexOf("//") == -1)
+ {
+ throw new URLSyntaxException(url, "Missing '//' after the transport In broker URL",transport.length()+1,1);
+ }
}
else
{
@@ -252,6 +254,16 @@ public class AMQBrokerDetails implements BrokerDetails
return BrokerDetails.DEFAULT_CONNECT_TIMEOUT;
}
+
+ public boolean useSSL()
+ {
+ if (_options.containsKey(ConnectionURL.OPTIONS_SSL))
+ {
+ return Boolean.parseBoolean(_options.get(ConnectionURL.OPTIONS_SSL));
+ }
+
+ return false;
+ }
public void setTimeout(long timeout)
{
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
index 27294562e5..0b9be5951f 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
@@ -20,24 +20,21 @@
*/
package org.apache.qpid.client;
-import org.apache.qpid.AMQConnectionFailureException;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQProtocolException;
-import org.apache.qpid.AMQUnresolvedAddressException;
-import org.apache.qpid.client.failover.FailoverException;
-import org.apache.qpid.client.protocol.AMQProtocolHandler;
-import org.apache.qpid.client.configuration.ClientProperties;
-import org.apache.qpid.exchange.ExchangeDefaults;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.jms.Connection;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.jms.ConnectionURL;
-import org.apache.qpid.jms.FailoverPolicy;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.url.URLSyntaxException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.ConnectException;
+import java.net.UnknownHostException;
+import java.nio.channels.UnresolvedAddressException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import javax.jms.ConnectionConsumer;
import javax.jms.ConnectionMetaData;
@@ -56,17 +53,34 @@ import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.net.ConnectException;
-import java.net.UnknownHostException;
-import java.nio.channels.UnresolvedAddressException;
-import java.text.MessageFormat;
-import java.util.*;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.qpid.AMQConnectionFailureException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQProtocolException;
+import org.apache.qpid.AMQUnresolvedAddressException;
+import org.apache.qpid.AMQDisconnectedException;
+import org.apache.qpid.client.configuration.ClientProperties;
+import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverProtectedOperation;
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicQosBody;
+import org.apache.qpid.framing.BasicQosOkBody;
+import org.apache.qpid.framing.ChannelOpenBody;
+import org.apache.qpid.framing.ChannelOpenOkBody;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.framing.TxSelectBody;
+import org.apache.qpid.framing.TxSelectOkBody;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.Connection;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.jms.FailoverPolicy;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.url.URLSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class AMQConnection extends Closeable implements Connection, QueueConnection, TopicConnection, Referenceable
{
@@ -76,6 +90,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
private final LinkedHashMap<Integer, AMQSession> _slowAccessSessions = new LinkedHashMap<Integer, AMQSession>();
private int _size = 0;
private static final int FAST_CHANNEL_ACCESS_MASK = 0xFFFFFFF0;
+ private AtomicInteger _idFactory = new AtomicInteger(0);
+ private int _maxChannelID;
+ private boolean _cycledIds;
public AMQSession get(int channelId)
{
@@ -165,11 +182,57 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
_fastAccessSessions[i] = null;
}
}
+
+ /*
+ * Synchronized on whole method so that we don't need to consider the
+ * increment-then-reset path in too much detail
+ */
+ public synchronized int getNextChannelId()
+ {
+ int id = 0;
+ if (!_cycledIds)
+ {
+ id = _idFactory.incrementAndGet();
+ if (id == _maxChannelID)
+ {
+ _cycledIds = true;
+ _idFactory.set(0); // Go back to the start
+ }
+ }
+ else
+ {
+ boolean done = false;
+ while (!done)
+ {
+ // Needs to work second time through
+ id = _idFactory.incrementAndGet();
+ if (id > _maxChannelID)
+ {
+ _idFactory.set(0);
+ id = _idFactory.incrementAndGet();
+ }
+ if ((id & FAST_CHANNEL_ACCESS_MASK) == 0)
+ {
+ done = (_fastAccessSessions[id] == null);
+ }
+ else
+ {
+ done = (!_slowAccessSessions.keySet().contains(id));
+ }
+ }
+ }
+
+ return id;
+ }
+
+ public void setMaxChannelID(int maxChannelID)
+ {
+ _maxChannelID = maxChannelID;
+ }
}
private static final Logger _logger = LoggerFactory.getLogger(AMQConnection.class);
- protected AtomicInteger _idFactory = new AtomicInteger(0);
/**
* This is the "root" mutex that must be held when doing anything that could be impacted by failover. This must be
@@ -245,16 +308,22 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
/** Thread Pool for executing connection level processes. Such as returning bounced messages. */
private final ExecutorService _taskPool = Executors.newCachedThreadPool();
private static final long DEFAULT_TIMEOUT = 1000 * 30;
- private ProtocolVersion _protocolVersion = ProtocolVersion.v0_9; // FIXME TGM, shouldn't need this
protected AMQConnectionDelegate _delegate;
// this connection maximum number of prefetched messages
- private long _maxPrefetch;
+ private int _maxPrefetch;
//Indicates whether persistent messages are synchronized
private boolean _syncPersistence;
+ //Indicates whether we need to sync on every message ack
+ private boolean _syncAck;
+
+ //Indicates the sync publish options (persistent|all)
+ //By default it's async publish
+ private String _syncPublish = "";
+
/**
* @param broker brokerdetails
* @param username username
@@ -335,37 +404,76 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public AMQConnection(ConnectionURL connectionURL, SSLConfiguration sslConfig) throws AMQException
{
// set this connection maxPrefetch
- if (connectionURL.getOption(ConnectionURL.AMQ_MAXPREFETCH) != null)
+ if (connectionURL.getOption(ConnectionURL.OPTIONS_MAXPREFETCH) != null)
{
- _maxPrefetch = Long.parseLong(connectionURL.getOption(ConnectionURL.AMQ_MAXPREFETCH));
+ _maxPrefetch = Integer.parseInt(connectionURL.getOption(ConnectionURL.OPTIONS_MAXPREFETCH));
}
else
{
// use the defaul value set for all connections
- _maxPrefetch = Long.valueOf(System.getProperties().getProperty(ClientProperties.MAX_PREFETCH_PROP_NAME,
- ClientProperties.MAX_PREFETCH_DEFAULT));
+ _maxPrefetch = Integer.parseInt(System.getProperties().getProperty(ClientProperties.MAX_PREFETCH_PROP_NAME,
+ ClientProperties.MAX_PREFETCH_DEFAULT));
}
- if (connectionURL.getOption(ConnectionURL.AMQ_SYNC_PERSISTENCE) != null)
+ if (connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PERSISTENCE) != null)
{
- _syncPersistence = Boolean.parseBoolean(connectionURL.getOption(ConnectionURL.AMQ_SYNC_PERSISTENCE));
+ _syncPersistence =
+ Boolean.parseBoolean(connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PERSISTENCE));
+ _logger.warn("sync_persistence is a deprecated property, " +
+ "please use sync_publish={persistent|all} instead");
}
else
{
// use the defaul value set for all connections
_syncPersistence = Boolean.getBoolean(ClientProperties.SYNC_PERSISTENT_PROP_NAME);
+ if (_syncPersistence)
+ {
+ _logger.warn("sync_persistence is a deprecated property, " +
+ "please use sync_publish={persistent|all} instead");
+ }
}
- _failoverPolicy = new FailoverPolicy(connectionURL);
- BrokerDetails brokerDetails = _failoverPolicy.getNextBrokerDetails();
- if (brokerDetails.getTransport().equals(BrokerDetails.VM))
+ if (connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_ACK) != null)
+ {
+ _syncAck = Boolean.parseBoolean(connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_ACK));
+ }
+ else
+ {
+ // use the defaul value set for all connections
+ _syncAck = Boolean.getBoolean(ClientProperties.SYNC_ACK_PROP_NAME);
+ }
+
+ if (connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PUBLISH) != null)
+ {
+ _syncPublish = connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PUBLISH);
+ }
+ else
+ {
+ // use the default value set for all connections
+ _syncPublish = System.getProperty((ClientProperties.SYNC_ACK_PROP_NAME),_syncPublish);
+ }
+
+ String amqpVersion = System.getProperty((ClientProperties.AMQP_VERSION), "0-10");
+
+ _failoverPolicy = new FailoverPolicy(connectionURL, this);
+ BrokerDetails brokerDetails = _failoverPolicy.getCurrentBrokerDetails();
+ if (brokerDetails.getTransport().equals(BrokerDetails.VM) || "0-8".equals(amqpVersion))
{
_delegate = new AMQConnectionDelegate_8_0(this);
+ }
+ else if ("0-9".equals(amqpVersion))
+ {
+ _delegate = new AMQConnectionDelegate_0_9(this);
+ }
+ else if ("0-91".equals(amqpVersion) || "0-9-1".equals(amqpVersion))
+ {
+ _delegate = new AMQConnectionDelegate_9_1(this);
}
else
{
_delegate = new AMQConnectionDelegate_0_10(this);
}
+ _sessions.setMaxChannelID(_delegate.getMaxChannelID());
if (_logger.isInfoEnabled())
{
@@ -413,7 +521,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
boolean retryAllowed = true;
Exception connectionException = null;
- while (!_connected && retryAllowed)
+ while (!_connected && retryAllowed && brokerDetails != null)
{
ProtocolVersion pe = null;
try
@@ -439,7 +547,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
}
else if (!_connected)
{
- retryAllowed = _failoverPolicy.failoverAllowed();
+ retryAllowed = _failoverPolicy.failoverAllowed();
brokerDetails = _failoverPolicy.getNextBrokerDetails();
}
}
@@ -458,7 +566,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
if (connectionException.getCause() != null)
{
message = connectionException.getCause().getMessage();
- connectionException.getCause().printStackTrace();
}
else
{
@@ -518,6 +625,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
Class partypes[] = new Class[1];
partypes[0] = AMQConnection.class;
_delegate = (AMQConnectionDelegate) c.getConstructor(partypes).newInstance(this);
+ _sessions.setMaxChannelID(_delegate.getMaxChannelID());
}
catch (ClassNotFoundException e)
{
@@ -591,12 +699,12 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public boolean attemptReconnection()
{
- while (_failoverPolicy.failoverAllowed())
+ BrokerDetails broker = null;
+ while (_failoverPolicy.failoverAllowed() && (broker = _failoverPolicy.getNextBrokerDetails()) != null)
{
try
{
- makeBrokerConnection(_failoverPolicy.getNextBrokerDetails());
-
+ makeBrokerConnection(broker);
return true;
}
catch (Exception e)
@@ -628,6 +736,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
return _delegate.makeBrokerConnection(brokerDetail);
}
+ public <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E
+ {
+ return _delegate.executeRetrySupport(operation);
+ }
+
/**
* Get the details of the currently active broker
*
@@ -653,7 +766,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode) throws JMSException
{
- return createSession(transacted, acknowledgeMode, AMQSession.DEFAULT_PREFETCH_HIGH_MARK);
+ return createSession(transacted, acknowledgeMode, _maxPrefetch);
}
public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode, final int prefetch)
@@ -871,7 +984,12 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
{
if (!_closed.getAndSet(true))
{
- doClose(sessions, timeout);
+ _closing.set(true);
+ try{
+ doClose(sessions, timeout);
+ }finally{
+ _closing.set(false);
+ }
}
}
@@ -917,7 +1035,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
// adjust timeout
timeout = adjustTimeout(timeout, startCloseTime);
- _delegate.closeConneciton(timeout);
+ _delegate.closeConnection(timeout);
//If the taskpool hasn't shutdown by now then give it shutdownNow.
// This will interupt any running tasks.
@@ -932,6 +1050,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
}
catch (AMQException e)
{
+ _logger.error("error:", e);
JMSException jmse = new JMSException("Error closing connection: " + e);
jmse.setLinkedException(e);
throw jmse;
@@ -1191,6 +1310,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
return _failoverMutex;
}
+ public void failoverPrep()
+ {
+ _delegate.failoverPrep();
+ }
+
public void resubscribeSessions() throws JMSException, AMQException, FailoverException
{
_delegate.resubscribeSessions();
@@ -1245,6 +1369,17 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
else
{
//Should never get here as all AMQEs are required to have an ErrorCode!
+ // Other than AMQDisconnectedEx!
+
+ if (cause instanceof AMQDisconnectedException)
+ {
+ Exception last = _protocolHandler.getStateManager().getLastException();
+ if (last != null)
+ {
+ _logger.info("StateManager had an exception for us to use a cause of our Disconnected Exception");
+ cause = last;
+ }
+ }
je = new JMSException("Exception thrown against " + toString() + ": " + cause);
}
@@ -1259,8 +1394,10 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
// in the case of an IOException, MINA has closed the protocol session so we set _closed to true
// so that any generic client code that tries to close the connection will not mess up this error
// handling sequence
- if (cause instanceof IOException)
+ if (cause instanceof IOException || cause instanceof AMQDisconnectedException)
{
+ // If we have an IOE/AMQDisconnect there is no connection to close on.
+ _closing.set(false);
closer = !_closed.getAndSet(true);
_protocolHandler.getProtocolSession().notifyError(je);
@@ -1317,7 +1454,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
_sessions.put(channelId, session);
}
- void deregisterSession(int channelId)
+ public void deregisterSession(int channelId)
{
_sessions.remove(channelId);
}
@@ -1411,13 +1548,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public ProtocolVersion getProtocolVersion()
{
- return _protocolVersion;
- }
-
- public void setProtocolVersion(ProtocolVersion protocolVersion)
- {
- _protocolVersion = protocolVersion;
- _protocolHandler.getProtocolSession().setProtocolVersion(protocolVersion);
+ return _delegate.getProtocolVersion();
}
public boolean isFailingOver()
@@ -1444,4 +1575,27 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
{
return _syncPersistence;
}
+
+ /**
+ * Indicates whether we need to sync on every message ack
+ */
+ public boolean getSyncAck()
+ {
+ return _syncAck;
+ }
+
+ public String getSyncPublish()
+ {
+ return _syncPublish;
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ _delegate.setIdleTimeout(l);
+ }
+
+ public int getNextChannelID()
+ {
+ return _sessions.getNextChannelId();
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
index 7f36ec6e99..23dc244dee 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
@@ -27,20 +27,40 @@ import javax.jms.XASession;
import org.apache.qpid.AMQException;
import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverProtectedOperation;
import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.Session;
public interface AMQConnectionDelegate
{
- public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException;
+ ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException;
- public Session createSession(final boolean transacted, final int acknowledgeMode,
- final int prefetchHigh, final int prefetchLow) throws JMSException;
+ Session createSession(final boolean transacted, final int acknowledgeMode,
+ final int prefetchHigh, final int prefetchLow) throws JMSException;
- public XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException;
+ /**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException thrown if there is a problem creating the session.
+ */
+ XASession createXASession() throws JMSException;
- public void resubscribeSessions() throws JMSException, AMQException, FailoverException;
+ XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException;
- public void closeConneciton(long timeout) throws JMSException, AMQException;
+ void failoverPrep();
+
+ void resubscribeSessions() throws JMSException, AMQException, FailoverException;
+
+ void closeConnection(long timeout) throws JMSException, AMQException;
+
+ <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E;
+
+ void setIdleTimeout(long l);
+
+ int getMaxChannelID();
+
+ ProtocolVersion getProtocolVersion();
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
index a2df2f3cf2..af21eb7ed0 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
@@ -1,26 +1,52 @@
package org.apache.qpid.client;
+/*
+ *
+ * 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.
+ *
+ */
+
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.XASession;
import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQProtocolException;
-import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.client.configuration.ClientProperties;
import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverProtectedOperation;
import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.Session;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.ClosedListener;
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.QpidException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionClose;
+import org.apache.qpid.transport.ConnectionException;
+import org.apache.qpid.transport.ConnectionListener;
import org.apache.qpid.transport.ProtocolVersionException;
+import org.apache.qpid.transport.TransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, ClosedListener
+public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, ConnectionListener
{
/**
* This class logger.
@@ -35,12 +61,15 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Closed
/**
* The QpidConeection instance that is mapped with thie JMS connection.
*/
- org.apache.qpid.nclient.Connection _qpidConnection;
+ org.apache.qpid.transport.Connection _qpidConnection;
+ private ConnectionException exception = null;
//--- constructor
public AMQConnectionDelegate_0_10(AMQConnection conn)
{
_conn = conn;
+ _qpidConnection = new Connection();
+ _qpidConnection.setConnectionListener(this);
}
/**
@@ -50,7 +79,7 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Closed
throws JMSException
{
_conn.checkNotClosed();
- int channelId = _conn._idFactory.incrementAndGet();
+ int channelId = _conn.getNextChannelID();
AMQSession session;
try
{
@@ -71,12 +100,24 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Closed
}
/**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException
+ */
+ public XASession createXASession() throws JMSException
+ {
+ return createXASession((int) _conn.getMaxPrefetch(), (int) _conn.getMaxPrefetch() / 2);
+ }
+
+ /**
* create an XA Session and start it if required.
*/
public XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException
{
_conn.checkNotClosed();
- int channelId = _conn._idFactory.incrementAndGet();
+ int channelId = _conn.getNextChannelID();
XASessionImpl session;
try
{
@@ -104,70 +145,165 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Closed
*/
public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException
{
- _qpidConnection = Client.createConnection();
try
{
if (_logger.isDebugEnabled())
{
- _logger.debug("creating connection with broker " + " host: " + brokerDetail
- .getHost() + " port: " + brokerDetail.getPort() + " virtualhost: " + _conn
- .getVirtualHost() + "user name: " + _conn.getUsername() + "password: " + _conn.getPassword());
+ _logger.debug("connecting to host: " + brokerDetail.getHost() +
+ " port: " + brokerDetail.getPort() +
+ " vhost: " + _conn.getVirtualHost() +
+ " username: " + _conn.getUsername() +
+ " password: " + _conn.getPassword());
+ }
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_IDLE_TIMEOUT) != null)
+ {
+ this.setIdleTimeout(Long.parseLong(brokerDetail.getProperty(BrokerDetails.OPTIONS_IDLE_TIMEOUT)));
}
+ else
+ {
+ // use the default value set for all connections
+ this.setIdleTimeout(Long.getLong(ClientProperties.IDLE_TIMEOUT_PROP_NAME,0));
+ }
+
+ String saslMechs = brokerDetail.getProperty("sasl_mechs")!= null?
+ brokerDetail.getProperty("sasl_mechs"):
+ System.getProperty("qpid.sasl_mechs","PLAIN");
+
_qpidConnection.connect(brokerDetail.getHost(), brokerDetail.getPort(), _conn.getVirtualHost(),
- _conn.getUsername(), _conn.getPassword());
- _qpidConnection.setClosedListener(this);
+ _conn.getUsername(), _conn.getPassword(), brokerDetail.useSSL(),saslMechs);
_conn._connected = true;
+ _conn._failoverPolicy.attainedConnection();
}
catch(ProtocolVersionException pe)
{
return new ProtocolVersion(pe.getMajor(), pe.getMinor());
}
- catch (QpidException e)
- {
+ catch (ConnectionException e)
+ {
throw new AMQException(AMQConstant.CHANNEL_ERROR, "cannot connect to broker", e);
}
return null;
}
- /**
- * Not supported at this level.
- */
+ public void failoverPrep()
+ {
+ List<AMQSession> sessions = new ArrayList<AMQSession>(_conn.getSessions().values());
+ for (AMQSession s : sessions)
+ {
+ s.failoverPrep();
+ }
+ }
+
public void resubscribeSessions() throws JMSException, AMQException, FailoverException
{
- //NOT implemented as railover is handled at a lower level
- throw new FailoverException("failing to reconnect during failover, operation not supported.");
+ List<AMQSession> sessions = new ArrayList<AMQSession>(_conn.getSessions().values());
+ _logger.info(String.format("Resubscribing sessions = %s sessions.size=%s", sessions, sessions.size()));
+ for (AMQSession s : sessions)
+ {
+ ((AMQSession_0_10) s)._qpidConnection = _qpidConnection;
+ s.resubscribe();
+ }
}
- public void closeConneciton(long timeout) throws JMSException, AMQException
+ public void closeConnection(long timeout) throws JMSException, AMQException
{
try
{
_qpidConnection.close();
}
- catch (QpidException e)
+ catch (TransportException e)
+ {
+ throw new AMQException(e.getMessage(), e);
+ }
+ }
+
+ public void opened(Connection conn) {}
+
+ public void exception(Connection conn, ConnectionException exc)
+ {
+ if (exception != null)
{
- throw new AMQException(AMQConstant.CHANNEL_ERROR, "cannot close connection", e);
+ _logger.error("previous exception", exception);
}
+ exception = exc;
}
- public void onClosed(ErrorCode errorCode, String reason, Throwable t)
+ public void closed(Connection conn)
{
- if (_logger.isDebugEnabled())
+ ConnectionException exc = exception;
+ exception = null;
+
+ if (exc == null)
+ {
+ return;
+ }
+
+ ConnectionClose close = exc.getClose();
+ if (close == null)
+ {
+ try
+ {
+ if (_conn.firePreFailover(false) && _conn.attemptReconnection())
+ {
+ _conn.failoverPrep();
+ _qpidConnection.resume();
+ _conn.fireFailoverComplete();
+ return;
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.error("error during failover", e);
+ }
+ }
+
+ ExceptionListener listener = _conn._exceptionListener;
+ if (listener == null)
{
- _logger.debug("Received a connection close from the broker: Error code : " + errorCode.getCode(), t);
+ _logger.error("connection exception: " + conn, exc);
}
- if (_conn._exceptionListener != null)
+ else
{
- JMSException ex = new JMSException(reason,String.valueOf(errorCode.getCode()));
- if (t != null)
+ String code = null;
+ if (close != null)
{
- ex.initCause(t);
+ code = close.getReplyCode().toString();
}
- _conn._exceptionListener.onException(ex);
+ JMSException ex = new JMSException(exc.getMessage(), code);
+ ex.initCause(exc);
+ listener.onException(ex);
+ }
+ }
+
+ public <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E
+ {
+ try
+ {
+ return operation.execute();
}
+ catch (FailoverException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ _qpidConnection.setIdleTimeout(l);
+ }
+
+ public int getMaxChannelID()
+ {
+ return Integer.MAX_VALUE;
+ }
+
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.v0_10;
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java
index d95e2e3dff..70ecedfd8b 100755
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.client;
+import org.apache.qpid.framing.ProtocolVersion;
+
public class AMQConnectionDelegate_0_9 extends AMQConnectionDelegate_8_0
{
@@ -28,5 +30,11 @@ public class AMQConnectionDelegate_0_9 extends AMQConnectionDelegate_8_0
{
super(conn);
}
+
+ @Override
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.v0_9;
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
index 2ec8737d16..6f44f68b37 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
@@ -48,7 +48,6 @@ import org.apache.qpid.framing.TxSelectBody;
import org.apache.qpid.framing.TxSelectOkBody;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.ChannelLimitReachedException;
-import org.apache.qpid.transport.network.io.IoTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,7 +57,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
private AMQConnection _conn;
- public void closeConneciton(long timeout) throws JMSException, AMQException
+ public void closeConnection(long timeout) throws JMSException, AMQException
{
_conn.getProtocolHandler().closeConnection(timeout);
@@ -90,15 +89,15 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
StateWaiter waiter = _conn._protocolHandler.createWaiter(openOrClosedStates);
// TODO: use system property thingy for this
- if (System.getProperty("UseTransportIo", "false").equals("false"))
+ if (System.getProperty("UseTransportIo", "false").equals("false"))
{
TransportConnection.getInstance(brokerDetail).connect(_conn._protocolHandler, brokerDetail);
- }
- else
+ }
+ else
{
_conn.getProtocolHandler().createIoTransportSession(brokerDetail);
}
-
+ _conn._protocolHandler.getProtocolSession().init();
// this blocks until the connection has been set up or when an error
// has prevented the connection being set up
@@ -108,9 +107,13 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
{
_conn._failoverPolicy.attainedConnection();
_conn._connected = true;
+ return null;
+ }
+ else
+ {
+ return _conn._protocolHandler.getSuggestedProtocolVersion();
}
- return null;
}
public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode, final int prefetch)
@@ -139,7 +142,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
{
public org.apache.qpid.jms.Session execute() throws JMSException, FailoverException
{
- int channelId = _conn._idFactory.incrementAndGet();
+ int channelId = _conn.getNextChannelID();
if (_logger.isDebugEnabled())
{
@@ -192,6 +195,18 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
}, _conn).execute();
}
+ /**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException thrown if there is a problem creating the session.
+ */
+ public XASession createXASession() throws JMSException
+ {
+ return createXASession((int) _conn.getMaxPrefetch(), (int) _conn.getMaxPrefetch() / 2);
+ }
+
private void createChannelOverWire(int channelId, int prefetchHigh, int prefetchLow, boolean transacted)
throws AMQException, FailoverException
{
@@ -203,7 +218,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
// todo Be aware of possible changes to parameter order as versions change.
BasicQosBody basicQosBody = _conn.getProtocolHandler().getMethodRegistry().createBasicQosBody(0,prefetchHigh,false);
_conn._protocolHandler.syncWrite(basicQosBody.generateFrame(channelId),BasicQosOkBody.class);
-
+
if (transacted)
{
if (_logger.isDebugEnabled())
@@ -211,12 +226,17 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
_logger.debug("Issuing TxSelect for " + channelId);
}
TxSelectBody body = _conn.getProtocolHandler().getMethodRegistry().createTxSelectBody();
-
+
// TODO: Be aware of possible changes to parameter order as versions change.
_conn._protocolHandler.syncWrite(body.generateFrame(channelId), TxSelectOkBody.class);
}
}
+ public void failoverPrep()
+ {
+ // do nothing
+ }
+
/**
* For all sessions, and for all consumers in those sessions, resubscribe. This is called during failover handling.
* The caller must hold the failover mutex before calling this method.
@@ -247,4 +267,52 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
throw new AMQException(null, "Error reopening channel " + channelId + " after failover: " + e, e);
}
}
+
+ public <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E
+ {
+ while (true)
+ {
+ try
+ {
+ _conn.blockUntilNotFailingOver();
+ }
+ catch (InterruptedException e)
+ {
+ _logger.debug("Interrupted: " + e, e);
+
+ return null;
+ }
+
+ synchronized (_conn.getFailoverMutex())
+ {
+ try
+ {
+ return operation.execute();
+ }
+ catch (FailoverException e)
+ {
+ _logger.debug("Failover exception caught during operation: " + e, e);
+ }
+ catch (IllegalStateException e)
+ {
+ if (!(e.getMessage().startsWith("Fail-over interupted no-op failover support")))
+ {
+ throw e;
+ }
+ }
+ }
+ }
+ }
+
+ public void setIdleTimeout(long l){}
+
+ public int getMaxChannelID()
+ {
+ return (int) (Math.pow(2, 16)-1);
+ }
+
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.v8_0;
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/ClosedListener.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_9_1.java
index 4cf0cab1ec..442dd7b286 100644..100755
--- a/java/client/src/main/java/org/apache/qpid/nclient/ClosedListener.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_9_1.java
@@ -1,4 +1,5 @@
/*
+ *
* 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
@@ -15,25 +16,24 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
+ *
*/
-package org.apache.qpid.nclient;
+package org.apache.qpid.client;
-import org.apache.qpid.ErrorCode;
+import org.apache.qpid.framing.ProtocolVersion;
-/**
- * If the communication layer detects a serious problem with a <CODE>connection</CODE>, it
- * informs the connection's ExceptionListener
- */
-public interface ClosedListener
+public class AMQConnectionDelegate_9_1 extends AMQConnectionDelegate_8_0
{
- /**
- * If the communication layer detects a serious problem with a connection, it
- * informs the connection's ExceptionListener
- * @param errorCode TODO
- * @param reason TODO
- * @param t TODO
- * @see Connection
- */
- public void onClosed(ErrorCode errorCode, String reason, Throwable t);
+
+ public AMQConnectionDelegate_9_1(AMQConnection conn)
+ {
+ super(conn);
+ }
+
+ @Override
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.v0_91;
+ }
} \ No newline at end of file
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
index 01a915f2cc..2d6f4434fe 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
@@ -354,6 +354,17 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF
return _connectionDetails;
}
+ public String getConnectionURLString()
+ {
+ return _connectionDetails.toString();
+ }
+
+
+ public final void setConnectionURLString(String url) throws URLSyntaxException
+ {
+ _connectionDetails = new AMQConnectionURL(url);
+ }
+
/**
* JNDI interface to create objects from References.
*
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
index 21b63c1fdb..60e4a5960a 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
@@ -237,14 +237,7 @@ public class AMQConnectionURL implements ConnectionURL
if (_password != null)
{
sb.append(':');
- if (_logger.isDebugEnabled())
- {
- sb.append(_password);
- }
- else
- {
- sb.append("********");
- }
+ sb.append("********");
}
sb.append('@');
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
index 6c78b754bb..3f2c1af5c2 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
@@ -82,8 +82,8 @@ public abstract class AMQDestination implements Destination, Referenceable
_isExclusive = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_EXCLUSIVE));
_isAutoDelete = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_AUTODELETE));
_isDurable = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_DURABLE));
- _queueName = binding.getQueueName() == null ? null : new AMQShortString(binding.getQueueName());
- _routingKey = binding.getRoutingKey() == null ? null : new AMQShortString(binding.getRoutingKey());
+ _queueName = binding.getQueueName() == null ? null : binding.getQueueName();
+ _routingKey = binding.getRoutingKey() == null ? null : binding.getRoutingKey();
_bindingKeys = binding.getBindingKeys() == null || binding.getBindingKeys().length == 0 ? new AMQShortString[0] : binding.getBindingKeys();
}
@@ -122,10 +122,11 @@ public abstract class AMQDestination implements Destination, Referenceable
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
boolean isAutoDelete, AMQShortString queueName, boolean isDurable,AMQShortString[] bindingKeys)
{
- // If used with a fannout exchange, the routing key can be null
- if ( !ExchangeDefaults.FANOUT_EXCHANGE_CLASS.equals(exchangeClass) && routingKey == null)
+ if ( (ExchangeDefaults.DIRECT_EXCHANGE_CLASS.equals(exchangeClass) ||
+ ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(exchangeClass))
+ && routingKey == null)
{
- throw new IllegalArgumentException("routingKey exchange must not be null");
+ throw new IllegalArgumentException("routing/binding key must not be null");
}
if (exchangeName == null)
{
@@ -270,7 +271,7 @@ public abstract class AMQDestination implements Destination, Referenceable
sb.append("://");
sb.append(_exchangeName);
- sb.append("//");
+ sb.append("/"+_routingKey+"/");
if (_queueName != null)
{
@@ -472,11 +473,12 @@ public abstract class AMQDestination implements Destination, Referenceable
}
else
{
- throw new IllegalArgumentException("Unknown Exchange Class:" + exchangeClass);
+ return new AMQAnyDestination(exchangeName,exchangeClass,
+ routingKey,isExclusive,
+ isAutoDelete,queueName,
+ isDurable, new AMQShortString[0]);
}
-
-
}
public static Destination createDestination(BindingURL binding)
@@ -495,13 +497,9 @@ public abstract class AMQDestination implements Destination, Referenceable
{
return new AMQHeadersExchange(binding);
}
- else if (type.equals(ExchangeDefaults.FANOUT_EXCHANGE_CLASS))
- {
- return new AMQQueue(binding);
- }
else
{
- throw new IllegalArgumentException("Unknown Exchange Class:" + type + " in binding:" + binding);
+ return new AMQAnyDestination(binding);
}
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java b/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
index 08fd49286b..d96544adf8 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
@@ -22,14 +22,12 @@ package org.apache.qpid.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.qpid.AMQException;
import javax.jms.IllegalStateException;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
-
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -90,38 +88,11 @@ public class AMQQueueBrowser implements QueueBrowser
{
checkState();
final BasicMessageConsumer consumer =
- (BasicMessageConsumer) _session.createBrowserConsumer(_queue, _messageSelector, false);
+ (BasicMessageConsumer) _session.createBrowserConsumer(_queue, _messageSelector, false);
_consumers.add(consumer);
- return new Enumeration()
- {
-
- Message _nextMessage = consumer == null ? null : consumer.receive(1000);
-
- public boolean hasMoreElements()
- {
- _logger.info("QB:hasMoreElements:" + (_nextMessage != null));
- return (_nextMessage != null);
- }
-
- public Object nextElement()
- {
- Message msg = _nextMessage;
- try
- {
- _logger.info("QB:nextElement about to receive");
- _nextMessage = consumer.receive(1000);
- _logger.info("QB:nextElement received:" + _nextMessage);
- }
- catch (JMSException e)
- {
- _logger.warn("Exception caught while queue browsing", e);
- _nextMessage = null;
- }
- return msg;
- }
- };
+ return new QueueBrowserEnumeration(consumer);
}
public void close() throws JMSException
@@ -134,4 +105,39 @@ public class AMQQueueBrowser implements QueueBrowser
_consumers.clear();
}
+ private class QueueBrowserEnumeration implements Enumeration
+ {
+ Message _nextMessage;
+ private BasicMessageConsumer _consumer;
+
+ public QueueBrowserEnumeration(BasicMessageConsumer consumer) throws JMSException
+ {
+ _nextMessage = consumer == null ? null : consumer.receiveBrowse();
+ _logger.info("QB:created with first element:" + _nextMessage);
+ _consumer = consumer;
+ }
+
+ public boolean hasMoreElements()
+ {
+ _logger.info("QB:hasMoreElements:" + (_nextMessage != null));
+ return (_nextMessage != null);
+ }
+
+ public Object nextElement()
+ {
+ Message msg = _nextMessage;
+ try
+ {
+ _logger.info("QB:nextElement about to receive");
+ _nextMessage = _consumer.receiveBrowse();
+ _logger.info("QB:nextElement received:" + _nextMessage);
+ }
+ catch (JMSException e)
+ {
+ _logger.warn("Exception caught while queue browsing", e);
+ _nextMessage = null;
+ }
+ return msg;
+ }
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
index 5203a27f42..43f6fd8ad2 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
@@ -30,6 +30,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -58,25 +59,37 @@ import javax.jms.Topic;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
+import javax.jms.TransactionRolledBackException;
import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQInvalidArgumentException;
import org.apache.qpid.AMQInvalidRoutingKeyException;
+import org.apache.qpid.AMQChannelClosedException;
import org.apache.qpid.client.failover.FailoverException;
import org.apache.qpid.client.failover.FailoverNoopSupport;
import org.apache.qpid.client.failover.FailoverProtectedOperation;
import org.apache.qpid.client.failover.FailoverRetrySupport;
-import org.apache.qpid.client.message.*;
+import org.apache.qpid.client.message.AMQMessageDelegateFactory;
+import org.apache.qpid.client.message.AbstractJMSMessage;
+import org.apache.qpid.client.message.CloseConsumerMessage;
+import org.apache.qpid.client.message.JMSBytesMessage;
+import org.apache.qpid.client.message.JMSMapMessage;
+import org.apache.qpid.client.message.JMSObjectMessage;
+import org.apache.qpid.client.message.JMSStreamMessage;
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.client.message.MessageFactoryRegistry;
+import org.apache.qpid.client.message.UnprocessedMessage;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
-import org.apache.qpid.client.util.FlowControllingBlockingQueue;
-import org.apache.qpid.client.state.AMQStateManager;
import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.util.FlowControllingBlockingQueue;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.FieldTableFactory;
import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.jms.Session;
+import org.apache.qpid.thread.Threading;
import org.apache.qpid.url.AMQBindingURL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -100,7 +113,6 @@ import org.slf4j.LoggerFactory;
public abstract class AMQSession<C extends BasicMessageConsumer, P extends BasicMessageProducer> extends Closeable implements Session, QueueSession, TopicSession
{
-
public static final class IdToConsumerMap<C extends BasicMessageConsumer>
{
private final BasicMessageConsumer[] _fastAccessConsumers = new BasicMessageConsumer[16];
@@ -181,24 +193,38 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/** Used for debugging. */
private static final Logger _logger = LoggerFactory.getLogger(AMQSession.class);
-
- /** The default maximum number of prefetched message at which to suspend the channel. */
- public static final int DEFAULT_PREFETCH_HIGH_MARK = 5000;
-
- /** The default minimum number of prefetched messages at which to resume the channel. */
- public static final int DEFAULT_PREFETCH_LOW_MARK = 2500;
-
/**
* The default value for immediate flag used by producers created by this session is false. That is, a consumer does
* not need to be attached to a queue.
*/
- protected static final boolean DEFAULT_IMMEDIATE = false;
+ protected final boolean DEFAULT_IMMEDIATE = Boolean.parseBoolean(System.getProperty("qpid.default_immediate", "false"));
/**
* The default value for mandatory flag used by producers created by this session is true. That is, server will not
* silently drop messages where no queue is connected to the exchange for the message.
*/
- protected static final boolean DEFAULT_MANDATORY = true;
+ protected final boolean DEFAULT_MANDATORY = Boolean.parseBoolean(System.getProperty("qpid.default_mandatory", "true"));
+
+ protected final boolean DEFAULT_WAIT_ON_SEND = Boolean.parseBoolean(System.getProperty("qpid.default_wait_on_send", "false"));
+
+ /**
+ * The period to wait while flow controlled before sending a log message confirming that the session is still
+ * waiting on flow control being revoked
+ */
+ protected final long FLOW_CONTROL_WAIT_PERIOD = Long.getLong("qpid.flow_control_wait_notify_period",5000L);
+
+ /**
+ * The period to wait while flow controlled before declaring a failure
+ */
+ public static final long DEFAULT_FLOW_CONTROL_WAIT_FAILURE = 120000L;
+ protected final long FLOW_CONTROL_WAIT_FAILURE = Long.getLong("qpid.flow_control_wait_failure",
+ DEFAULT_FLOW_CONTROL_WAIT_FAILURE);
+
+ protected final boolean DECLARE_QUEUES =
+ Boolean.parseBoolean(System.getProperty("qpid.declare_queues", "true"));
+
+ protected final boolean DECLARE_EXCHANGES =
+ Boolean.parseBoolean(System.getProperty("qpid.declare_exchanges", "true"));
/** System property to enable strict AMQP compliance. */
public static final String STRICT_AMQP = "STRICT_AMQP";
@@ -233,10 +259,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private int _ticket;
/** Holds the high mark for prefetched message, at which the session is suspended. */
- private int _defaultPrefetchHighMark = DEFAULT_PREFETCH_HIGH_MARK;
+ private int _prefetchHighMark;
/** Holds the low mark for prefetched messages, below which the session is resumed. */
- private int _defaultPrefetchLowMark = DEFAULT_PREFETCH_LOW_MARK;
+ private int _prefetchLowMark;
/** Holds the message listener, if any, which is attached to this session. */
private MessageListener _messageListener = null;
@@ -268,6 +294,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/** Holds the highest received delivery tag. */
private final AtomicLong _highestDeliveryTag = new AtomicLong(-1);
+ private final AtomicLong _rollbackMark = new AtomicLong(-1);
/** All the not yet acknowledged message tags */
protected ConcurrentLinkedQueue<Long> _unacknowledgedMessageTags = new ConcurrentLinkedQueue<Long>();
@@ -278,6 +305,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/** Holds the dispatcher thread for this session. */
protected Dispatcher _dispatcher;
+ protected Thread _dispatcherThread;
+
/** Holds the message factory factory for this session. */
protected MessageFactoryRegistry _messageFactoryRegistry;
@@ -414,13 +443,13 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_channelId = channelId;
_messageFactoryRegistry = messageFactoryRegistry;
- _defaultPrefetchHighMark = defaultPrefetchHighMark;
- _defaultPrefetchLowMark = defaultPrefetchLowMark;
+ _prefetchHighMark = defaultPrefetchHighMark;
+ _prefetchLowMark = defaultPrefetchLowMark;
if (_acknowledgeMode == NO_ACKNOWLEDGE)
{
_queue =
- new FlowControllingBlockingQueue(_defaultPrefetchHighMark, _defaultPrefetchLowMark,
+ new FlowControllingBlockingQueue(_prefetchHighMark, _prefetchLowMark,
new FlowControllingBlockingQueue.ThresholdListener()
{
private final AtomicBoolean _suspendState = new AtomicBoolean();
@@ -428,7 +457,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void aboveThreshold(int currentValue)
{
_logger.debug(
- "Above threshold(" + _defaultPrefetchHighMark
+ "Above threshold(" + _prefetchHighMark
+ ") so suspending channel. Current value is " + currentValue);
_suspendState.set(true);
new Thread(new SuspenderRunner(_suspendState)).start();
@@ -438,7 +467,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void underThreshold(int currentValue)
{
_logger.debug(
- "Below threshold(" + _defaultPrefetchLowMark
+ "Below threshold(" + _prefetchLowMark
+ ") so unsuspending channel. Current value is " + currentValue);
_suspendState.set(false);
new Thread(new SuspenderRunner(_suspendState)).start();
@@ -448,7 +477,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
else
{
- _queue = new FlowControllingBlockingQueue(_defaultPrefetchHighMark, null);
+ _queue = new FlowControllingBlockingQueue(_prefetchHighMark, null);
}
}
@@ -568,12 +597,19 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void bindQueue(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
final AMQShortString exchangeName, final AMQDestination destination) throws AMQException
{
+ bindQueue(queueName, routingKey, arguments, exchangeName, destination, false);
+ }
+
+ public void bindQueue(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
+ final AMQShortString exchangeName, final AMQDestination destination,
+ final boolean nowait) throws AMQException
+ {
/*new FailoverRetrySupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()*/
new FailoverNoopSupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()
{
public Object execute() throws AMQException, FailoverException
{
- sendQueueBind(queueName, routingKey, arguments, exchangeName, destination);
+ sendQueueBind(queueName, routingKey, arguments, exchangeName, destination, nowait);
return null;
}
}, _connection).execute();
@@ -588,7 +624,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
public abstract void sendQueueBind(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
- final AMQShortString exchangeName, AMQDestination destination) throws AMQException, FailoverException;
+ final AMQShortString exchangeName, AMQDestination destination,
+ final boolean nowait) throws AMQException, FailoverException;
/**
* Closes the session.
@@ -608,6 +645,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
*/
public void close(long timeout) throws JMSException
{
+ close(timeout, true);
+ }
+
+ private void close(long timeout, boolean sendClose) throws JMSException
+ {
if (_logger.isInfoEnabled())
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
@@ -618,6 +660,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
// Ensure we only try and close an open session.
if (!_closed.getAndSet(true))
{
+ _closing.set(true);
synchronized (getFailoverMutex())
{
// We must close down all producers and consumers in an orderly fashion. This is the only method
@@ -629,7 +672,16 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
- sendClose(timeout);
+ // If the connection is open or we are in the process
+ // of closing the connection then send a cance
+ // no point otherwise as the connection will be gone
+ if (!_connection.isClosed() || _connection.isClosing())
+ {
+ if (sendClose)
+ {
+ sendClose(timeout);
+ }
+ }
}
catch (AMQException e)
{
@@ -674,31 +726,32 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
if (_dispatcher != null)
{
// Failover failed and ain't coming back. Knife the dispatcher.
- _dispatcher.interrupt();
+ _dispatcherThread.interrupt();
}
- }
+
+ }
+
+ //if we don't have an exception then we can perform closing operations
+ _closing.set(e == null);
if (!_closed.getAndSet(true))
{
- synchronized (getFailoverMutex())
+ synchronized (_messageDeliveryLock)
{
- synchronized (_messageDeliveryLock)
+ // An AMQException has an error code and message already and will be passed in when closure occurs as a
+ // result of a channel close request
+ AMQException amqe;
+ if (e instanceof AMQException)
{
- // An AMQException has an error code and message already and will be passed in when closure occurs as a
- // result of a channel close request
- AMQException amqe;
- if (e instanceof AMQException)
- {
- amqe = (AMQException) e;
- }
- else
- {
- amqe = new AMQException("Closing session forcibly", e);
- }
-
- _connection.deregisterSession(_channelId);
- closeProducersAndConsumers(amqe);
+ amqe = (AMQException) e;
}
+ else
+ {
+ amqe = new AMQException("Closing session forcibly", e);
+ }
+
+ _connection.deregisterSession(_channelId);
+ closeProducersAndConsumers(amqe);
}
}
}
@@ -721,8 +774,16 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
+ //Check that we are clean to commit.
+ if (_failedOverDirty)
+ {
+ rollback();
+
+ throw new TransactionRolledBackException("Connection failover has occured since last send. " +
+ "Forced rollback");
+ }
+
- // TGM FIXME: what about failover?
// Acknowledge all delivered messages
while (true)
{
@@ -740,7 +801,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (AMQException e)
{
- throw new JMSAMQException("Failed to commit: " + e.getMessage(), e);
+ throw new JMSAMQException("Failed to commit: " + e.getMessage() + ":" + e.getCause(), e);
}
catch (FailoverException e)
{
@@ -832,7 +893,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, false,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, false,
messageSelector, null, true, true);
}
@@ -840,7 +901,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, (destination instanceof Topic), null, null,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic), null, null,
false, false);
}
@@ -848,7 +909,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, true, null, null,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, true, null, null,
false, false);
}
@@ -856,7 +917,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, (destination instanceof Topic),
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic),
messageSelector, null, false, false);
}
@@ -865,7 +926,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, (destination instanceof Topic),
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, (destination instanceof Topic),
messageSelector, null, false, false);
}
@@ -874,7 +935,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, true,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, true,
messageSelector, null, false, false);
}
@@ -917,7 +978,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
throws JMSException
{
checkNotClosed();
- checkValidTopic(topic);
+ checkValidTopic(topic, true);
if (_subscriptions.containsKey(name))
{
_subscriptions.get(name).close();
@@ -1000,6 +1061,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (URISyntaxException urlse)
{
+ _logger.error("", urlse);
JMSException jmse = new JMSException(urlse.getReason());
jmse.setLinkedException(urlse);
@@ -1194,7 +1256,28 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
return new TopicSubscriberAdaptor(dest, (C) createExclusiveConsumer(dest, messageSelector, noLocal));
}
- public abstract TemporaryQueue createTemporaryQueue() throws JMSException;
+ public TemporaryQueue createTemporaryQueue() throws JMSException
+ {
+ checkNotClosed();
+ try
+ {
+ AMQTemporaryQueue result = new AMQTemporaryQueue(this);
+
+ // this is done so that we can produce to a temporary queue before we create a consumer
+ result.setQueueName(result.getRoutingKey());
+ createQueue(result.getAMQQueueName(), result.isAutoDelete(),
+ result.isDurable(), result.isExclusive());
+ bindQueue(result.getAMQQueueName(), result.getRoutingKey(),
+ new FieldTable(), result.getExchangeName(), result);
+ return result;
+ }
+ catch (Exception e)
+ {
+ JMSException ex = new JMSException("Cannot create temporary queue");
+ ex.setLinkedException(e);
+ throw ex;
+ }
+ }
public TemporaryTopic createTemporaryTopic() throws JMSException
{
@@ -1275,17 +1358,17 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public int getDefaultPrefetch()
{
- return _defaultPrefetchHighMark;
+ return _prefetchHighMark;
}
public int getDefaultPrefetchHigh()
{
- return _defaultPrefetchHighMark;
+ return _prefetchHighMark;
}
public int getDefaultPrefetchLow()
{
- return _defaultPrefetchLowMark;
+ return _prefetchLowMark;
}
public AMQShortString getDefaultQueueExchangeName()
@@ -1430,6 +1513,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
sendRecover();
+ markClean();
+
if (!isSuspended)
{
suspendChannel(false);
@@ -1498,6 +1583,14 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
suspendChannel(true);
}
+ // Let the dispatcher know that all the incomming messages
+ // should be rolled back(reject/release)
+ _rollbackMark.set(_highestDeliveryTag.get());
+
+ syncDispatchQueue();
+
+ _dispatcher.rollback();
+
releaseForRollback();
sendRollback();
@@ -1645,11 +1738,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
// if (rawSelector != null)
// ft.put("headers", rawSelector.getDataAsBytes());
// rawSelector is used by HeadersExchange and is not a JMS Selector
- if (rawSelector != null)
+ if (rawSelector != null)
{
ft.addAll(rawSelector);
}
-
+
if (messageSelector != null)
{
ft.put(new AMQShortString("x-filter-jms-selector"), messageSelector);
@@ -1682,6 +1775,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (AMQException e)
{
+ if (e instanceof AMQChannelClosedException)
+ {
+ close(-1, false);
+ }
+
JMSException ex = new JMSException("Error registering consumer: " + e);
ex.setLinkedException(e);
@@ -1783,6 +1881,63 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
+ void failoverPrep()
+ {
+ syncDispatchQueue();
+ }
+
+ void syncDispatchQueue()
+ {
+ if (Thread.currentThread() == _dispatcherThread)
+ {
+ while (!_closed.get() && !_queue.isEmpty())
+ {
+ Dispatchable disp;
+ try
+ {
+ disp = (Dispatchable) _queue.take();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ // Check just in case _queue becomes empty, it shouldn't but
+ // better than an NPE.
+ if (disp == null)
+ {
+ _logger.debug("_queue became empty during sync.");
+ break;
+ }
+
+ disp.dispatch(AMQSession.this);
+ }
+ }
+ else
+ {
+ startDispatcherIfNecessary();
+
+ final CountDownLatch signal = new CountDownLatch(1);
+
+ _queue.add(new Dispatchable()
+ {
+ public void dispatch(AMQSession ssn)
+ {
+ signal.countDown();
+ }
+ });
+
+ try
+ {
+ signal.await();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
/**
* Resubscribes all producers and consumers. This is called when performing failover.
*
@@ -1794,6 +1949,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
_failedOverDirty = true;
}
+
+ _rollbackMark.set(-1);
resubscribeProducers();
resubscribeConsumers();
}
@@ -1808,6 +1965,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_inRecovery = inRecovery;
}
+ boolean isStarted()
+ {
+ return _startedAtLeastOnce.get();
+ }
+
/**
* Starts the session, which ensures that it is not suspended and that its event dispatcher is running.
*
@@ -1834,7 +1996,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
void startDispatcherIfNecessary()
{
//If we are the dispatcher then we don't need to check we are started
- if (Thread.currentThread() == _dispatcher)
+ if (Thread.currentThread() == _dispatcherThread)
{
return;
}
@@ -1865,9 +2027,23 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
if (_dispatcher == null)
{
_dispatcher = new Dispatcher();
- _dispatcher.setDaemon(true);
+ try
+ {
+ _dispatcherThread = Threading.getThreadFactory().createThread(_dispatcher);
+
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating Dispatcher thread",e);
+ }
+ _dispatcherThread.setName("Dispatcher-Channel-" + _channelId);
+ _dispatcherThread.setDaemon(true);
_dispatcher.setConnectionStopped(initiallyStopped);
- _dispatcher.start();
+ _dispatcherThread.start();
+ if (_dispatcherLogger.isInfoEnabled())
+ {
+ _dispatcherLogger.info(_dispatcherThread.getName() + " created");
+ }
}
else
{
@@ -1967,7 +2143,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/*
* I could have combined the last 3 methods, but this way it improves readability
*/
- protected AMQTopic checkValidTopic(Topic topic) throws JMSException
+ protected AMQTopic checkValidTopic(Topic topic, boolean durable) throws JMSException
{
if (topic == null)
{
@@ -1980,6 +2156,12 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
"Cannot create a subscription on a temporary topic created in another session");
}
+ if ((topic instanceof TemporaryDestination) && durable)
+ {
+ throw new javax.jms.InvalidDestinationException
+ ("Cannot create a durable subscription with a temporary topic: " + topic);
+ }
+
if (!(topic instanceof AMQTopic))
{
throw new javax.jms.InvalidDestinationException(
@@ -1990,6 +2172,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
return (AMQTopic) topic;
}
+ protected AMQTopic checkValidTopic(Topic topic) throws JMSException
+ {
+ return checkValidTopic(topic, false);
+ }
+
/**
* Called to close message consumers cleanly. This may or may <b>not</b> be as a result of an error.
*
@@ -2110,7 +2297,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private P createProducerImpl(Destination destination, boolean mandatory, boolean immediate)
throws JMSException
{
- return createProducerImpl(destination, mandatory, immediate, false);
+ return createProducerImpl(destination, mandatory, immediate, DEFAULT_WAIT_ON_SEND);
}
private P createProducerImpl(final Destination destination, final boolean mandatory,
@@ -2216,7 +2403,13 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
* @todo Be aware of possible changes to parameter order as versions change.
*/
protected AMQShortString declareQueue(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
- final boolean noLocal)
+ final boolean noLocal) throws AMQException
+ {
+ return declareQueue(amqd, protocolHandler, noLocal, false);
+ }
+
+ protected AMQShortString declareQueue(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
+ final boolean noLocal, final boolean nowait)
throws AMQException
{
/*return new FailoverRetrySupport<AMQShortString, AMQException>(*/
@@ -2231,14 +2424,15 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
amqd.setQueueName(protocolHandler.generateQueueName());
}
- sendQueueDeclare(amqd, protocolHandler);
+ sendQueueDeclare(amqd, protocolHandler, nowait);
return amqd.getAMQQueueName();
}
}, _connection).execute();
}
- public abstract void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler) throws AMQException, FailoverException;
+ public abstract void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
+ final boolean nowait) throws AMQException, FailoverException;
/**
* Undeclares the specified queue.
@@ -2351,14 +2545,21 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
AMQProtocolHandler protocolHandler = getProtocolHandler();
- declareExchange(amqd, protocolHandler, false);
+ if (DECLARE_EXCHANGES)
+ {
+ declareExchange(amqd, protocolHandler, nowait);
+ }
- AMQShortString queueName = declareQueue(amqd, protocolHandler, consumer.isNoLocal());
+ if (DECLARE_QUEUES || amqd.isNameRequired())
+ {
+ declareQueue(amqd, protocolHandler, consumer.isNoLocal(), nowait);
+ }
+ AMQShortString queueName = amqd.getAMQQueueName();
// store the consumer queue name
consumer.setQueuename(queueName);
- bindQueue(queueName, amqd.getRoutingKey(), consumer.getArguments(), amqd.getExchangeName(), amqd);
+ bindQueue(queueName, amqd.getRoutingKey(), consumer.getArguments(), amqd.getExchangeName(), amqd, nowait);
// If IMMEDIATE_PREFETCH is not required then suspsend the channel to delay prefetch
if (!_immediatePrefetch)
@@ -2390,11 +2591,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
- consumeFromQueue(consumer, queueName, protocolHandler, nowait, consumer.getMessageSelector());
- }
- catch (JMSException e) // thrown by getMessageSelector
- {
- throw new AMQException(null, e.getMessage(), e);
+ consumeFromQueue(consumer, queueName, protocolHandler, nowait, consumer._messageSelector);
}
catch (FailoverException e)
{
@@ -2465,9 +2662,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_consumers.clear();
for (C consumer : consumers)
- {
- consumer.failedOver();
+ {
+ consumer.failedOverPre();
registerConsumer(consumer, true);
+ consumer.failedOverPost();
}
}
@@ -2570,50 +2768,67 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void setFlowControl(final boolean active)
{
_flowControl.setFlowControl(active);
+ _logger.warn("Broker enforced flow control " + (active ? "no longer in effect" : "has been enforced"));
}
- public void checkFlowControl() throws InterruptedException
+ public void checkFlowControl() throws InterruptedException, JMSException
{
+ long expiryTime = 0L;
synchronized (_flowControl)
{
- while (!_flowControl.getFlowControl())
+ while (!_flowControl.getFlowControl() &&
+ (expiryTime == 0L ? (expiryTime = System.currentTimeMillis() + FLOW_CONTROL_WAIT_FAILURE)
+ : expiryTime) >= System.currentTimeMillis() )
{
- _flowControl.wait();
+
+ _flowControl.wait(FLOW_CONTROL_WAIT_PERIOD);
+ _logger.warn("Message send delayed by " + (System.currentTimeMillis() + FLOW_CONTROL_WAIT_FAILURE - expiryTime)/1000 + "s due to broker enforced flow control");
}
+ if(!_flowControl.getFlowControl())
+ {
+ _logger.error("Message send failed due to timeout waiting on broker enforced flow control");
+ throw new JMSException("Unable to send message for " + FLOW_CONTROL_WAIT_FAILURE/1000 + " seconds due to broker enforced flow control");
+ }
+ }
+
+ }
+
+ public interface Dispatchable
+ {
+ void dispatch(AMQSession ssn);
+ }
+
+ public void dispatch(UnprocessedMessage message)
+ {
+ if (_dispatcher == null)
+ {
+ throw new java.lang.IllegalStateException("dispatcher is not started");
}
+ _dispatcher.dispatchMessage(message);
}
/** Used for debugging in the dispatcher. */
private static final Logger _dispatcherLogger = LoggerFactory.getLogger("org.apache.qpid.client.AMQSession.Dispatcher");
-
/** Responsible for decoding a message fragment and passing it to the appropriate message consumer. */
- class Dispatcher extends Thread
+ class Dispatcher implements Runnable
{
/** Track the 'stopped' state of the dispatcher, a session starts in the stopped state. */
private final AtomicBoolean _closed = new AtomicBoolean(false);
private final Object _lock = new Object();
- private final AtomicLong _rollbackMark = new AtomicLong(-1);
private String dispatcherID = "" + System.identityHashCode(this);
-
-
public Dispatcher()
{
- super("Dispatcher-Channel-" + _channelId);
- if (_dispatcherLogger.isInfoEnabled())
- {
- _dispatcherLogger.info(getName() + " created");
- }
}
public void close()
{
_closed.set(true);
- interrupt();
+ _dispatcherThread.interrupt();
// fixme awaitTermination
@@ -2692,7 +2907,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
if (_dispatcherLogger.isInfoEnabled())
{
- _dispatcherLogger.info(getName() + " started");
+ _dispatcherLogger.info(_dispatcherThread.getName() + " started");
}
UnprocessedMessage message;
@@ -2715,37 +2930,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
- while (!_closed.get() && ((message = (UnprocessedMessage) _queue.take()) != null))
+ Dispatchable disp;
+ while (!_closed.get() && ((disp = (Dispatchable) _queue.take()) != null))
{
- long deliveryTag = message.getDeliveryTag();
-
- synchronized (_lock)
- {
-
- while (connectionStopped())
- {
- _lock.wait();
- }
-
- if (!(message instanceof CloseConsumerMessage)
- && tagLE(deliveryTag, _rollbackMark.get()))
- {
- rejectMessage(message, true);
- }
- else
- {
- synchronized (_messageDeliveryLock)
- {
- dispatchMessage(message);
- }
- }
- }
-
- long current = _rollbackMark.get();
- if (updateRollbackMark(current, deliveryTag))
- {
- _rollbackMark.compareAndSet(current, deliveryTag);
- }
+ disp.dispatch(AMQSession.this);
}
}
catch (InterruptedException e)
@@ -2755,7 +2943,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
if (_dispatcherLogger.isInfoEnabled())
{
- _dispatcherLogger.info(getName() + " thread terminating for channel " + _channelId);
+ _dispatcherLogger.info(_dispatcherThread.getName() + " thread terminating for channel " + _channelId);
}
}
@@ -2786,11 +2974,47 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private void dispatchMessage(UnprocessedMessage message)
{
- //This if block is not needed anymore as bounce messages are handled separately
- //if (message.getDeliverBody() != null)
- //{
- final C consumer =
- _consumers.get(message.getConsumerTag());
+ long deliveryTag = message.getDeliveryTag();
+
+ synchronized (_lock)
+ {
+
+ try
+ {
+ while (connectionStopped())
+ {
+ _lock.wait();
+ }
+ }
+ catch (InterruptedException e)
+ {
+ // pass
+ }
+
+ if (!(message instanceof CloseConsumerMessage)
+ && tagLE(deliveryTag, _rollbackMark.get()))
+ {
+ rejectMessage(message, true);
+ }
+ else
+ {
+ synchronized (_messageDeliveryLock)
+ {
+ notifyConsumer(message);
+ }
+ }
+ }
+
+ long current = _rollbackMark.get();
+ if (updateRollbackMark(current, deliveryTag))
+ {
+ _rollbackMark.compareAndSet(current, deliveryTag);
+ }
+ }
+
+ private void notifyConsumer(UnprocessedMessage message)
+ {
+ final C consumer = _consumers.get(message.getConsumerTag());
if ((consumer == null) || consumer.isClosed())
{
@@ -2798,7 +3022,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
if (consumer == null)
{
- _dispatcherLogger.info("Dispatcher(" + dispatcherID + ")Received a message(" + System.identityHashCode(message) + ")" + "["
+ _dispatcherLogger.info("Dispatcher(" + dispatcherID + ")Received a message("
+ + System.identityHashCode(message) + ")" + "["
+ message.getDeliveryTag() + "] from queue "
+ message.getConsumerTag() + " )without a handler - rejecting(requeue)...");
}
@@ -2806,7 +3031,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
if (consumer.isNoConsume())
{
- _dispatcherLogger.info("Received a message(" + System.identityHashCode(message) + ")" + "["
+ _dispatcherLogger.info("Received a message("
+ + System.identityHashCode(message) + ")" + "["
+ message.getDeliveryTag() + "] from queue " + " consumer("
+ message.getConsumerTag() + ") is closed and a browser so dropping...");
//DROP MESSAGE
@@ -2815,7 +3041,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
else
{
- _dispatcherLogger.info("Received a message(" + System.identityHashCode(message) + ")" + "["
+ _dispatcherLogger.info("Received a message("
+ + System.identityHashCode(message) + ")" + "["
+ message.getDeliveryTag() + "] from queue " + " consumer("
+ message.getConsumerTag() + ") is closed rejecting(requeue)...");
}
@@ -2831,7 +3058,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
consumer.notifyMessage(message);
}
-
}
}
@@ -2889,4 +3115,27 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
}
}
+
+ /**
+ * Checks if the Session and its parent connection are closed
+ *
+ * @return <tt>true</tt> if this is closed, <tt>false</tt> otherwise.
+ */
+ @Override
+ public boolean isClosed()
+ {
+ return _closed.get() || _connection.isClosed();
+ }
+
+ /**
+ * Checks if the Session and its parent connection are capable of performing
+ * closing operations
+ *
+ * @return <tt>true</tt> if we are closing, <tt>false</tt> otherwise.
+ */
+ @Override
+ public boolean isClosing()
+ {
+ return _closing.get()|| _connection.isClosing();
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
index aa0ff66545..2324d441cc 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
@@ -28,31 +28,44 @@ import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.message.MessageFactoryRegistry;
import org.apache.qpid.client.message.FiledTableSupport;
import org.apache.qpid.client.message.AMQMessageDelegateFactory;
+import org.apache.qpid.client.message.UnprocessedMessage_0_10;
import org.apache.qpid.util.Serial;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.QpidException;
+import org.apache.qpid.transport.ExecutionException;
+import org.apache.qpid.transport.MessageAcceptMode;
+import org.apache.qpid.transport.MessageAcquireMode;
import org.apache.qpid.transport.MessageCreditUnit;
import org.apache.qpid.transport.MessageFlowMode;
+import org.apache.qpid.transport.MessageTransfer;
import org.apache.qpid.transport.RangeSet;
import org.apache.qpid.transport.Option;
import org.apache.qpid.transport.ExchangeBoundResult;
import org.apache.qpid.transport.Future;
+import org.apache.qpid.transport.Range;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionException;
+import org.apache.qpid.transport.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.apache.qpid.transport.Option.*;
+
import javax.jms.*;
import javax.jms.IllegalStateException;
+import java.lang.ref.WeakReference;
+
+import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
/**
* This is a 0.10 Session
*/
public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, BasicMessageProducer_0_10>
+ implements SessionListener
{
/**
@@ -60,6 +73,36 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
*/
private static final Logger _logger = LoggerFactory.getLogger(AMQSession_0_10.class);
+ private static Timer timer = new Timer("ack-flusher", true);
+ private static class Flusher extends TimerTask
+ {
+
+ private WeakReference<AMQSession_0_10> session;
+ public Flusher(AMQSession_0_10 session)
+ {
+ this.session = new WeakReference<AMQSession_0_10>(session);
+ }
+
+ public void run() {
+ AMQSession_0_10 ssn = session.get();
+ if (ssn == null)
+ {
+ cancel();
+ }
+ else
+ {
+ try
+ {
+ ssn.flushAcknowledgments(true);
+ }
+ catch (Throwable t)
+ {
+ _logger.error("error flushing acks", t);
+ }
+ }
+ }
+ }
+
/**
* The underlying QpidSession
@@ -70,11 +113,13 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* The latest qpid Exception that has been reaised.
*/
private Object _currentExceptionLock = new Object();
- private QpidException _currentException;
+ private SessionException _currentException;
// a ref on the qpid connection
- protected org.apache.qpid.nclient.Connection _qpidConnection;
+ protected org.apache.qpid.transport.Connection _qpidConnection;
+ private long maxAckDelay = Long.getLong("qpid.session.max_ack_delay", 1000);
+ private TimerTask flushTask = null;
private RangeSet unacked = new RangeSet();
private int unackedCount = 0;
@@ -97,7 +142,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* @param defaultPrefetchLowMark The number of prefetched messages at which to resume the session.
* @param qpidConnection The qpid connection
*/
- AMQSession_0_10(org.apache.qpid.nclient.Connection qpidConnection, AMQConnection con, int channelId,
+ AMQSession_0_10(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
boolean transacted, int acknowledgeMode, MessageFactoryRegistry messageFactoryRegistry,
int defaultPrefetchHighMark, int defaultPrefetchLowMark)
{
@@ -105,15 +150,18 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
super(con, channelId, transacted, acknowledgeMode, messageFactoryRegistry, defaultPrefetchHighMark,
defaultPrefetchLowMark);
_qpidConnection = qpidConnection;
- // create the qpid session with an expiry <= 0 so that the session does not expire
- _qpidSession = qpidConnection.createSession(0);
- // set the exception listnere for this session
- _qpidSession.setClosedListener(new QpidSessionExceptionListener());
- // set transacted if required
+ _qpidSession = _qpidConnection.createSession(1);
+ _qpidSession.setSessionListener(this);
if (_transacted)
{
_qpidSession.txSelect();
}
+
+ if (maxAckDelay > 0)
+ {
+ flushTask = new Flusher(this);
+ timer.schedule(flushTask, new Date(), maxAckDelay);
+ }
}
/**
@@ -127,7 +175,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* @param defaultPrefetchLow The number of prefetched messages at which to resume the session.
* @param qpidConnection The connection
*/
- AMQSession_0_10(org.apache.qpid.nclient.Connection qpidConnection, AMQConnection con, int channelId,
+ AMQSession_0_10(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
boolean transacted, int acknowledgeMode, int defaultPrefetchHigh, int defaultPrefetchLow)
{
@@ -137,18 +185,30 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
private void addUnacked(int id)
{
- unacked.add(id);
- unackedCount++;
+ synchronized (unacked)
+ {
+ unacked.add(id);
+ unackedCount++;
+ }
}
private void clearUnacked()
{
- unacked.clear();
- unackedCount = 0;
+ synchronized (unacked)
+ {
+ unacked.clear();
+ unackedCount = 0;
+ }
}
//------- overwritten methods of class AMQSession
+ void failoverPrep()
+ {
+ super.failoverPrep();
+ clearUnacked();
+ }
+
/**
* Acknowledge one or many messages.
*
@@ -185,7 +245,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
long prefetch = getAMQConnection().getMaxPrefetch();
- if (unackedCount >= prefetch/2)
+ if (unackedCount >= prefetch/2 || maxAckDelay <= 0)
{
flushAcknowledgments();
}
@@ -193,11 +253,38 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
void flushAcknowledgments()
{
- if (unackedCount > 0)
+ flushAcknowledgments(false);
+ }
+
+ void flushAcknowledgments(boolean setSyncBit)
+ {
+ synchronized (unacked)
+ {
+ if (unackedCount > 0)
+ {
+ messageAcknowledge
+ (unacked, _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE,setSyncBit);
+ clearUnacked();
+ }
+ }
+ }
+
+ void messageAcknowledge(RangeSet ranges, boolean accept)
+ {
+ messageAcknowledge(ranges,accept,false);
+ }
+
+ void messageAcknowledge(RangeSet ranges, boolean accept,boolean setSyncBit)
+ {
+ Session ssn = getQpidSession();
+ for (Range range : ranges)
+ {
+ ssn.processed(range);
+ }
+ ssn.flushProcessed(accept ? BATCH : NONE);
+ if (accept)
{
- getQpidSession().messageAcknowledge
- (unacked, _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE);
- clearUnacked();
+ ssn.messageAccept(ranges, UNRELIABLE,setSyncBit? SYNC : NONE);
}
}
@@ -212,7 +299,8 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* @param arguments 0_8 specific
*/
public void sendQueueBind(final AMQShortString queueName, final AMQShortString routingKey,
- final FieldTable arguments, final AMQShortString exchangeName, final AMQDestination destination)
+ final FieldTable arguments, final AMQShortString exchangeName,
+ final AMQDestination destination, final boolean nowait)
throws AMQException, FailoverException
{
Map args = FiledTableSupport.convertToMap(arguments);
@@ -227,9 +315,12 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
_logger.debug("Binding queue : " + queueName.toString() + " exchange: " + exchangeName.toString() + " using binding key " + rk.asString());
getQpidSession().exchangeBind(queueName.toString(), exchangeName.toString(), rk.toString(), args);
}
- // We need to sync so that we get notify of an error.
- getQpidSession().sync();
- getCurrentException();
+ if (!nowait)
+ {
+ // We need to sync so that we get notify of an error.
+ getQpidSession().sync();
+ getCurrentException();
+ }
}
@@ -242,6 +333,11 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
*/
public void sendClose(long timeout) throws AMQException, FailoverException
{
+ if (flushTask != null)
+ {
+ flushTask.cancel();
+ flushTask = null;
+ }
flushAcknowledgments();
getQpidSession().sync();
getQpidSession().close();
@@ -318,10 +414,6 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
public void releaseForRollback()
{
- if (_dispatcher != null)
- {
- _dispatcher.rollback();
- }
getQpidSession().messageRelease(_txRangeSet, Option.SET_REDELIVERED);
_txRangeSet.clear();
_txSize = 0;
@@ -376,7 +468,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
public boolean isQueueBound(final AMQShortString exchangeName, final AMQShortString queueName, final AMQShortString routingKey,AMQShortString[] bindingKeys)
throws JMSException
{
- String rk = "";
+ String rk = null;
boolean res;
if (bindingKeys != null && bindingKeys.length>0)
{
@@ -416,11 +508,11 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
preAcquire = ( ! consumer.isNoConsume() &&
(consumer.getMessageSelector() == null || consumer.getMessageSelector().equals("")) )
|| !(consumer.getDestination() instanceof AMQQueue);
- getQpidSession().messageSubscribe(queueName.toString(), String.valueOf(tag),
- getAcknowledgeMode() == NO_ACKNOWLEDGE ? Session.TRANSFER_CONFIRM_MODE_NOT_REQUIRED:Session.TRANSFER_CONFIRM_MODE_REQUIRED,
- preAcquire ? Session.TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE : Session.TRANSFER_ACQUIRE_MODE_NO_ACQUIRE,
- (BasicMessageConsumer_0_10) consumer, null,
- consumer.isExclusive() ? Option.EXCLUSIVE : Option.NONE);
+ getQpidSession().messageSubscribe
+ (queueName.toString(), String.valueOf(tag),
+ getAcknowledgeMode() == NO_ACKNOWLEDGE ? MessageAcceptMode.NONE : MessageAcceptMode.EXPLICIT,
+ preAcquire ? MessageAcquireMode.PRE_ACQUIRED : MessageAcquireMode.NOT_ACQUIRED, null, 0, null,
+ consumer.isExclusive() ? Option.EXCLUSIVE : Option.NONE);
}
catch (JMSException e)
{
@@ -437,18 +529,24 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
{
getQpidSession().messageSetFlowMode(consumerTag, MessageFlowMode.WINDOW);
}
- getQpidSession().messageFlow(consumerTag, MessageCreditUnit.BYTE, 0xFFFFFFFF);
+ getQpidSession().messageFlow(consumerTag, MessageCreditUnit.BYTE, 0xFFFFFFFF,
+ Option.UNRELIABLE);
// We need to sync so that we get notify of an error.
// only if not immediat prefetch
- if(prefetch() && (consumer.isStrated() || _immediatePrefetch))
+ if(prefetch() && (isStarted() || _immediatePrefetch))
{
// set the flow
getQpidSession().messageFlow(consumerTag,
MessageCreditUnit.MESSAGE,
- getAMQConnection().getMaxPrefetch());
+ getAMQConnection().getMaxPrefetch(),
+ Option.UNRELIABLE);
+ }
+
+ if (!nowait)
+ {
+ getQpidSession().sync();
+ getCurrentException();
}
- getQpidSession().sync();
- getCurrentException();
}
/**
@@ -470,19 +568,24 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
final AMQProtocolHandler protocolHandler, final boolean nowait)
throws AMQException, FailoverException
{
- getQpidSession().exchangeDeclare(name.toString(), type.toString(), null, null);
- // autoDelete --> false
- // durable --> false
- // passive -- false
+ getQpidSession().exchangeDeclare(name.toString(),
+ type.toString(),
+ null,
+ null,
+ name.toString().startsWith("amq.")? Option.PASSIVE:Option.NONE);
// We need to sync so that we get notify of an error.
- getQpidSession().sync();
- getCurrentException();
+ if (!nowait)
+ {
+ getQpidSession().sync();
+ getCurrentException();
+ }
}
/**
* Declare a queue with the given queueName
*/
- public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler)
+ public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
+ final boolean nowait)
throws AMQException, FailoverException
{
// do nothing this is only used by 0_8
@@ -492,7 +595,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* Declare a queue with the given queueName
*/
public AMQShortString send0_10QueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
- final boolean noLocal)
+ final boolean noLocal, final boolean nowait)
throws AMQException, FailoverException
{
AMQShortString res;
@@ -516,9 +619,12 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
amqd.isDurable() ? Option.DURABLE : Option.NONE,
!amqd.isDurable() && amqd.isExclusive() ? Option.EXCLUSIVE : Option.NONE);
// passive --> false
- // We need to sync so that we get notify of an error.
- getQpidSession().sync();
- getCurrentException();
+ if (!nowait)
+ {
+ // We need to sync so that we get notify of an error.
+ getQpidSession().sync();
+ getCurrentException();
+ }
return res;
}
@@ -544,7 +650,8 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
{
for (BasicMessageConsumer consumer : _consumers.values())
{
- getQpidSession().messageStop(String.valueOf(consumer.getConsumerTag()));
+ getQpidSession().messageStop(String.valueOf(consumer.getConsumerTag()),
+ Option.UNRELIABLE);
}
}
else
@@ -560,17 +667,20 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
if (consumer.getMessageListener() != null)
{
getQpidSession().messageFlow(consumerTag,
- MessageCreditUnit.MESSAGE, 1);
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
}
else
{
getQpidSession()
.messageFlow(consumerTag, MessageCreditUnit.MESSAGE,
- getAMQConnection().getMaxPrefetch());
+ getAMQConnection().getMaxPrefetch(),
+ Option.UNRELIABLE);
}
getQpidSession()
- .messageFlow(consumerTag, MessageCreditUnit.BYTE, 0xFFFFFFFF);
+ .messageFlow(consumerTag, MessageCreditUnit.BYTE, 0xFFFFFFFF,
+ Option.UNRELIABLE);
}
catch (Exception e)
{
@@ -598,7 +708,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
*
* @return The associated Qpid Session.
*/
- protected org.apache.qpid.nclient.Session getQpidSession()
+ protected Session getQpidSession()
{
return _qpidSession;
}
@@ -615,55 +725,56 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
{
if (_currentException != null)
{
- QpidException toBeThrown = _currentException;
+ SessionException se = _currentException;
_currentException = null;
- throw new AMQException(AMQConstant.getConstant(toBeThrown.getErrorCode().getCode()),
- toBeThrown.getMessage(), toBeThrown);
+ ExecutionException ee = se.getException();
+ int code;
+ if (ee == null)
+ {
+ code = 0;
+ }
+ else
+ {
+ code = ee.getErrorCode().getValue();
+ }
+ throw new AMQException
+ (AMQConstant.getConstant(code), se.getMessage(), se);
}
}
}
+ public void opened(Session ssn) {}
- public TemporaryQueue createTemporaryQueue() throws JMSException
+ public void resumed(Session ssn)
{
- checkNotClosed();
- AMQTemporaryQueue result = new AMQTemporaryQueue(this);
+ _qpidConnection = ssn.getConnection();
try
{
- // this is done so that we can produce to a temporary queue beofre we create a consumer
- sendCreateQueue(result.getRoutingKey(), result.isAutoDelete(), result.isDurable(), result.isExclusive(),null);
- sendQueueBind(result.getRoutingKey(), result.getRoutingKey(), new FieldTable(), result.getExchangeName(),result);
- result.setQueueName(result.getRoutingKey());
+ resubscribe();
}
- catch (Exception e)
+ catch (AMQException e)
{
- throw new JMSException("Cannot create temporary queue" );
+ throw new RuntimeException(e);
}
- return result;
}
+ public void message(Session ssn, MessageTransfer xfr)
+ {
+ messageReceived(new UnprocessedMessage_0_10(xfr));
+ }
-
-
- //------ Inner classes
- /**
- * Lstener for qpid protocol exceptions
- */
- private class QpidSessionExceptionListener implements org.apache.qpid.nclient.ClosedListener
+ public void exception(Session ssn, SessionException exc)
{
- public void onClosed(ErrorCode errorCode, String reason, Throwable t)
+ synchronized (_currentExceptionLock)
{
- synchronized (_currentExceptionLock)
- {
- // todo check the error code for finding out if we need to notify the
- // JMS connection exception listener
- _currentException = new QpidException(reason, errorCode, t);
- }
+ _currentException = exc;
}
}
+ public void closed(Session ssn) {}
+
protected AMQShortString declareQueue(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
- final boolean noLocal)
+ final boolean noLocal, final boolean nowait)
throws AMQException
{
/*return new FailoverRetrySupport<AMQShortString, AMQException>(*/
@@ -678,44 +789,21 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
String binddingKey = "";
for(AMQShortString key : amqd.getBindingKeys())
{
- binddingKey = binddingKey + "_" + key.toString();
+ binddingKey = binddingKey + "_" + key.toString();
}
amqd.setQueueName(new AMQShortString( binddingKey + "@"
+ amqd.getExchangeName().toString() + "_" + UUID.randomUUID()));
}
- return send0_10QueueDeclare(amqd, protocolHandler, noLocal);
+ return send0_10QueueDeclare(amqd, protocolHandler, noLocal, nowait);
}
}, _connection).execute();
}
-
- void start() throws AMQException
- {
- super.start();
- for(BasicMessageConsumer c: _consumers.values())
- {
- c.start();
- }
- }
-
-
- void stop() throws AMQException
- {
- super.stop();
- for(BasicMessageConsumer c: _consumers.values())
- {
- c.stop();
- }
- }
-
-
-
-
public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException
{
checkNotClosed();
- AMQTopic origTopic=checkValidTopic(topic);
+ AMQTopic origTopic=checkValidTopic(topic, true);
AMQTopic dest=AMQTopic.createDurable010Topic(origTopic, name, _connection);
TopicSubscriberAdaptor<BasicMessageConsumer_0_10> subscriber=_subscriptions.get(name);
@@ -786,19 +874,19 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
/**
* Store non committed messages for this session
* With 0.10 messages are consumed with window mode, we must send a completion
- * before the window size is reached so credits don't dry up.
+ * before the window size is reached so credits don't dry up.
* @param id
*/
@Override protected void addDeliveredMessage(long id)
{
_txRangeSet.add((int) id);
_txSize++;
- // this is a heuristic, we may want to have that configurable
+ // this is a heuristic, we may want to have that configurable
if (_connection.getMaxPrefetch() == 1 ||
_connection.getMaxPrefetch() != 0 && _txSize % (_connection.getMaxPrefetch() / 2) == 0)
{
// send completed so consumer credits don't dry up
- getQpidSession().messageAcknowledge(_txRangeSet, false);
+ messageAcknowledge(_txRangeSet, false);
}
}
@@ -809,7 +897,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
{
if( _txSize > 0 )
{
- getQpidSession().messageAcknowledge(_txRangeSet, true);
+ messageAcknowledge(_txRangeSet, true);
_txRangeSet.clear();
_txSize = 0;
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
index 2442b157f1..862e23385a 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
@@ -33,8 +33,10 @@ import org.apache.qpid.client.message.*;
import org.apache.qpid.client.message.AMQMessageDelegateFactory;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.state.listener.SpecificMethodFrameListener;
+import org.apache.qpid.client.state.AMQState;
import org.apache.qpid.common.AMQPFilterTypes;
import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
import org.apache.qpid.jms.Session;
import org.apache.qpid.protocol.AMQConstant;
@@ -102,10 +104,12 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
}
getProtocolHandler().writeFrame(ackFrame);
+ _unacknowledgedMessageTags.remove(deliveryTag);
}
public void sendQueueBind(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
- final AMQShortString exchangeName, final AMQDestination dest) throws AMQException, FailoverException
+ final AMQShortString exchangeName, final AMQDestination dest,
+ final boolean nowait) throws AMQException, FailoverException
{
getProtocolHandler().syncWrite(getProtocolHandler().getMethodRegistry().createQueueBindBody
(getTicket(),queueName,exchangeName,routingKey,false,arguments).
@@ -114,12 +118,23 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void sendClose(long timeout) throws AMQException, FailoverException
{
- getProtocolHandler().closeSession(this);
- getProtocolHandler().syncWrite(getProtocolHandler().getMethodRegistry().createChannelCloseBody(AMQConstant.REPLY_SUCCESS.getCode(),
- new AMQShortString("JMS client closing channel"), 0, 0).generateFrame(_channelId),
- ChannelCloseOkBody.class, timeout);
- // When control resumes at this point, a reply will have been received that
- // indicates the broker has closed the channel successfully.
+ // we also need to check the state manager for 08/09 as the
+ // _connection variable may not be updated in time by the error receiving
+ // thread.
+ // We can't close the session if we are alreadying in the process of
+ // closing/closed the connection.
+
+ if (!(getProtocolHandler().getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSED)
+ || getProtocolHandler().getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSING)))
+ {
+
+ getProtocolHandler().closeSession(this);
+ getProtocolHandler().syncWrite(getProtocolHandler().getMethodRegistry().createChannelCloseBody(AMQConstant.REPLY_SUCCESS.getCode(),
+ new AMQShortString("JMS client closing channel"), 0, 0).generateFrame(_channelId),
+ ChannelCloseOkBody.class, timeout);
+ // When control resumes at this point, a reply will have been received that
+ // indicates the broker has closed the channel successfully.
+ }
}
public void sendCommit() throws AMQException, FailoverException
@@ -172,6 +187,11 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
BasicRecoverSyncBody body = ((MethodRegistry_0_9)getMethodRegistry()).createBasicRecoverSyncBody(false);
_connection.getProtocolHandler().syncWrite(body.generateFrame(_channelId), BasicRecoverSyncOkBody.class);
}
+ else if(getProtocolVersion().equals(ProtocolVersion.v0_91))
+ {
+ BasicRecoverSyncBody body = ((MethodRegistry_0_91)getMethodRegistry()).createBasicRecoverSyncBody(false);
+ _connection.getProtocolHandler().syncWrite(body.generateFrame(_channelId), BasicRecoverSyncOkBody.class);
+ }
else
{
throw new RuntimeException("Unsupported version of the AMQP Protocol: " + getProtocolVersion());
@@ -181,6 +201,12 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void releaseForRollback()
{
+ // Reject all the messages that have been received in this session and
+ // have not yet been acknowledged. Should look to remove
+ // _deliveredMessageTags and use _txRangeSet as used by 0-10.
+ // Otherwise messages will be able to arrive out of order to a second
+ // consumer on the queue. Whilst this is within the JMS spec it is not
+ // user friendly and avoidable.
while (true)
{
Long tag = _deliveredMessageTags.poll();
@@ -191,11 +217,6 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
rejectMessage(tag, true);
}
-
- if (_dispatcher != null)
- {
- _dispatcher.rollback();
- }
}
public void rejectMessage(long deliveryTag, boolean requeue)
@@ -297,13 +318,16 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void sendExchangeDeclare(final AMQShortString name, final AMQShortString type, final AMQProtocolHandler protocolHandler,
final boolean nowait) throws AMQException, FailoverException
{
- ExchangeDeclareBody body = getMethodRegistry().createExchangeDeclareBody(getTicket(),name,type,false,false,false,false,nowait,null);
+ ExchangeDeclareBody body = getMethodRegistry().createExchangeDeclareBody(getTicket(),name,type,
+ name.toString().startsWith("amq."),
+ false,false,false,false,null);
AMQFrame exchangeDeclare = body.generateFrame(_channelId);
protocolHandler.syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class);
}
- public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler) throws AMQException, FailoverException
+ public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
+ final boolean nowait) throws AMQException, FailoverException
{
QueueDeclareBody body = getMethodRegistry().createQueueDeclareBody(getTicket(),amqd.getAMQQueueName(),false,amqd.isDurable(),amqd.isExclusive(),amqd.isAutoDelete(),false,null);
@@ -418,18 +442,11 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
getProtocolHandler().syncWrite(frame, TxRollbackOkBody.class);
}
- public TemporaryQueue createTemporaryQueue() throws JMSException
- {
- checkNotClosed();
-
- return new AMQTemporaryQueue(this);
- }
-
public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException
{
checkNotClosed();
- AMQTopic origTopic = checkValidTopic(topic);
+ AMQTopic origTopic = checkValidTopic(topic, true);
AMQTopic dest = AMQTopic.createDurableTopic(origTopic, name, _connection);
TopicSubscriberAdaptor<BasicMessageConsumer_0_8> subscriber = _subscriptions.get(name);
if (subscriber != null)
@@ -493,7 +510,7 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
- public void setPrefecthLimits(final int messagePrefetch, final long sizePrefetch) throws AMQException
+ public void setPrefetchLimits(final int messagePrefetch, final long sizePrefetch) throws AMQException
{
new FailoverRetrySupport<Object, AMQException>(
new FailoverProtectedOperation<Object, AMQException>()
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java b/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java
index f44f8414fa..ec482a8f79 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java
@@ -115,7 +115,7 @@ public class AMQTopicSessionAdaptor implements TopicSession, AMQSessionAdapter
public ObjectMessage createObjectMessage(Serializable serializable) throws JMSException
{
- return _session.createObjectMessage();
+ return _session.createObjectMessage(serializable);
}
public StreamMessage createStreamMessage() throws JMSException
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
index dfd228370c..bea43cc232 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
@@ -40,8 +40,9 @@ import java.util.SortedSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.TreeSet;
-import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -78,7 +79,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
* Used in the blocking receive methods to receive a message from the Session thread. <p/> Or to notify of errors
* <p/> Argument true indicates we want strict FIFO semantics
*/
- protected final ArrayBlockingQueue _synchronousQueue;
+ protected final BlockingQueue _synchronousQueue;
protected final MessageFactoryRegistry _messageFactory;
@@ -182,7 +183,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
_prefetchLow = prefetchLow;
_exclusive = exclusive;
- _synchronousQueue = new ArrayBlockingQueue(prefetchHigh, true);
+ _synchronousQueue = new LinkedBlockingQueue();
_autoClose = autoClose;
_noConsume = noConsume;
@@ -440,7 +441,9 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
o = _synchronousQueue.take();
}
return o;
- }
+ }
+
+ abstract Message receiveBrowse() throws JMSException;
public Message receiveNoWait() throws JMSException
{
@@ -540,6 +543,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
if (!_closed.getAndSet(true))
{
+ _closing.set(true);
if (_logger.isDebugEnabled())
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
@@ -560,7 +564,13 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
{
try
{
- sendCancel();
+ // If the session is open or we are in the process
+ // of closing the session then send a cance
+ // no point otherwise as the connection will be gone
+ if (!_session.isClosed() || _session.isClosing())
+ {
+ sendCancel();
+ }
}
catch (AMQException e)
{
@@ -769,15 +779,16 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
else
{
_session.addDeliveredMessage(msg.getDeliveryTag());
+ _session.markDirty();
}
break;
}
+
}
void postDeliver(AbstractJMSMessage msg) throws JMSException
{
- msg.setJMSDestination(_destination);
switch (_acknowledgeMode)
{
@@ -1036,23 +1047,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
_synchronousQueue.clear();
}
- public void start()
- {
- // do nothing as this is a 0_10 feature
- }
-
-
- public void stop()
- {
- // do nothing as this is a 0_10 feature
- }
-
- public boolean isStrated()
- {
- // do nothing as this is a 0_10 feature
- return false;
- }
-
public AMQShortString getQueuename()
{
return _queuename;
@@ -1069,10 +1063,13 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
}
/** to be called when a failover has occured */
- public void failedOver()
+ public void failedOverPre()
{
clearReceiveQueue();
// TGM FIXME: think this should just be removed
// clearUnackedMessages();
}
+
+ public void failedOverPost() {}
+
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
index 2a37298a43..1b2d6876bd 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
@@ -31,6 +31,7 @@ import org.apache.qpid.filter.JMSSelectorFilter;
import javax.jms.InvalidSelectorException;
import javax.jms.JMSException;
+import javax.jms.Message;
import javax.jms.MessageListener;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -39,7 +40,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
* This is a 0.10 message consumer.
*/
public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedMessage_0_10>
- implements org.apache.qpid.nclient.MessagePartListener
{
/**
@@ -114,9 +114,6 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
return _consumerTagString;
}
-
- // ----- Interface org.apache.qpid.client.util.MessageListener
-
/**
*
* This is invoked by the session thread when emptying the session message queue.
@@ -152,35 +149,14 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
if (isMessageListenerSet() && ! getSession().prefetch())
{
_0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
_logger.debug("messageOk, trying to notify");
super.notifyMessage(jmsMessage);
}
}
-
-
- /**
- * This method is invoked by the transport layer when a message is delivered for this
- * consumer. The message is transformed and pass to the session.
- * @param xfr an 0.10 message transfer
- */
- public void messageTransfer(MessageTransfer xfr)
-
- //public void onMessage(Message message)
- {
- int channelId = getSession().getChannelId();
- int consumerTag = getConsumerTag();
-
- UnprocessedMessage_0_10 newMessage =
- new UnprocessedMessage_0_10(consumerTag, xfr);
-
-
- getSession().messageReceived(newMessage);
- // else ignore this message
- }
-
//----- overwritten methods
/**
@@ -272,7 +248,8 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
if(! getSession().prefetch())
{
_0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
}
// now we need to acquire this message if needed
@@ -284,9 +261,7 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
_logger.debug("filterMessage - trying to acquire message");
}
messageOk = acquireMessage(message);
- _logger.debug("filterMessage - *************************************");
_logger.debug("filterMessage - message acquire status : " + messageOk);
- _logger.debug("filterMessage - *************************************");
}
return messageOk;
}
@@ -304,8 +279,9 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
{
RangeSet ranges = new RangeSet();
ranges.add((int) message.getDeliveryTag());
- _0_10session.getQpidSession().messageAcknowledge(ranges,
- _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE );
+ _0_10session.messageAcknowledge
+ (ranges,
+ _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE);
_0_10session.getCurrentException();
}
}
@@ -360,7 +336,8 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
if (messageListener != null && ! getSession().prefetch())
{
_0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
if (messageListener != null && !_synchronousQueue.isEmpty())
{
@@ -374,26 +351,16 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
}
}
- public boolean isStrated()
+ public void failedOverPost()
{
- return _isStarted;
- }
-
- public void start()
- {
- _isStarted = true;
- if (_syncReceive.get())
+ if (_0_10session.isStarted() && _syncReceive.get())
{
- _0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
+ _0_10session.getQpidSession().messageFlow
+ (getConsumerTagString(), MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
}
- public void stop()
- {
- _isStarted = false;
- }
-
/**
* When messages are not prefetched we need to request a message from the
* broker.
@@ -405,16 +372,35 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
*/
public Object getMessageFromQueue(long l) throws InterruptedException
{
- if (isStrated() && ! getSession().prefetch() && _synchronousQueue.isEmpty())
- {
- _0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
- }
if (! getSession().prefetch())
{
_syncReceive.set(true);
}
+ if (_0_10session.isStarted() && ! getSession().prefetch() && _synchronousQueue.isEmpty())
+ {
+ _0_10session.getQpidSession().messageFlow(getConsumerTagString(),
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
+ }
Object o = super.getMessageFromQueue(l);
+ if (o == null && _0_10session.isStarted())
+ {
+ _0_10session.getQpidSession().messageFlush
+ (getConsumerTagString(), Option.UNRELIABLE, Option.SYNC);
+ _0_10session.getQpidSession().sync();
+ _0_10session.getQpidSession().messageFlow
+ (getConsumerTagString(), MessageCreditUnit.BYTE,
+ 0xFFFFFFFF, Option.UNRELIABLE);
+ if (getSession().prefetch())
+ {
+ _0_10session.getQpidSession().messageFlow
+ (getConsumerTagString(), MessageCreditUnit.MESSAGE,
+ _0_10session.getAMQConnection().getMaxPrefetch(),
+ Option.UNRELIABLE);
+ }
+ _0_10session.syncDispatchQueue();
+ o = super.getMessageFromQueue(-1);
+ }
if (! getSession().prefetch())
{
_syncReceive.set(false);
@@ -425,10 +411,50 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
void postDeliver(AbstractJMSMessage msg) throws JMSException
{
super.postDeliver(msg);
- if(_acknowledgeMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE && !_session.isInRecovery())
+ if (_acknowledgeMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE && !_session.isInRecovery())
+ {
+ _session.acknowledgeMessage(msg.getDeliveryTag(), false);
+ }
+
+ if (_acknowledgeMode == org.apache.qpid.jms.Session.AUTO_ACKNOWLEDGE &&
+ !_session.isInRecovery() &&
+ _session.getAMQConnection().getSyncAck())
{
- _session.acknowledgeMessage(msg.getDeliveryTag(), false);
- }
+ ((AMQSession_0_10) getSession()).flushAcknowledgments();
+ ((AMQSession_0_10) getSession()).getQpidSession().sync();
+ }
+ }
+
+ Message receiveBrowse() throws JMSException
+ {
+ return receiveNoWait();
}
+ @Override public void rollbackPendingMessages()
+ {
+ if (_synchronousQueue.size() > 0)
+ {
+ RangeSet ranges = new RangeSet();
+ Iterator iterator = _synchronousQueue.iterator();
+ while (iterator.hasNext())
+ {
+
+ Object o = iterator.next();
+ if (o instanceof AbstractJMSMessage)
+ {
+ ranges.add((int) ((AbstractJMSMessage) o).getDeliveryTag());
+ iterator.remove();
+ }
+ else
+ {
+ _logger.error("Queue contained a :" + o.getClass()
+ + " unable to reject as it is not an AbstractJMSMessage. Will be cleared");
+ iterator.remove();
+ }
+ }
+
+ _0_10session.getQpidSession().messageRelease(ranges, Option.SET_REDELIVERED);
+ clearReceiveQueue();
+ }
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
index 494a8fb43d..308f04f082 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
@@ -22,6 +22,7 @@ package org.apache.qpid.client;
import javax.jms.InvalidSelectorException;
import javax.jms.JMSException;
+import javax.jms.Message;
import org.apache.qpid.AMQException;
import org.apache.qpid.QpidException;
@@ -38,9 +39,9 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe
protected final Logger _logger = LoggerFactory.getLogger(getClass());
protected BasicMessageConsumer_0_8(int channelId, AMQConnection connection, AMQDestination destination,
- String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session,
- AMQProtocolHandler protocolHandler, FieldTable arguments, int prefetchHigh, int prefetchLow,
- boolean exclusive, int acknowledgeMode, boolean noConsume, boolean autoClose) throws JMSException
+ String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session,
+ AMQProtocolHandler protocolHandler, FieldTable arguments, int prefetchHigh, int prefetchLow,
+ boolean exclusive, int acknowledgeMode, boolean noConsume, boolean autoClose) throws JMSException
{
super(channelId, connection, destination,messageSelector,noLocal,messageFactory,session,
protocolHandler, arguments, prefetchHigh, prefetchLow, exclusive,
@@ -73,13 +74,18 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe
}
}
- public AbstractJMSMessage createJMSMessageFromUnprocessedMessage(AMQMessageDelegateFactory delegateFactory, UnprocessedMessage_0_8 messageFrame)throws Exception
- {
+ public AbstractJMSMessage createJMSMessageFromUnprocessedMessage(AMQMessageDelegateFactory delegateFactory, UnprocessedMessage_0_8 messageFrame)throws Exception
+ {
return _messageFactory.createMessage(messageFrame.getDeliveryTag(),
- messageFrame.isRedelivered(), messageFrame.getExchange(),
- messageFrame.getRoutingKey(), messageFrame.getContentHeader(), messageFrame.getBodies());
+ messageFrame.isRedelivered(), messageFrame.getExchange(),
+ messageFrame.getRoutingKey(), messageFrame.getContentHeader(), messageFrame.getBodies());
+
+ }
+ Message receiveBrowse() throws JMSException
+ {
+ return receive();
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
index beaa47ed1e..df59be25d0 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
@@ -46,19 +46,21 @@ import org.slf4j.LoggerFactory;
public abstract class BasicMessageProducer extends Closeable implements org.apache.qpid.jms.MessageProducer
{
+ enum PublishMode { ASYNC_PUBLISH_ALL, SYNC_PUBLISH_PERSISTENT, SYNC_PUBLISH_ALL };
+
protected final Logger _logger = LoggerFactory.getLogger(getClass());
private AMQConnection _connection;
/**
- * If true, messages will not get a timestamp.
+ * If true, messages will not get a timestamp.
*/
protected boolean _disableTimestamps;
/**
* Priority of messages created by this producer.
*/
- private int _messagePriority;
+ private int _messagePriority = Message.DEFAULT_PRIORITY;
/**
* Time to live of messages. Specified in milliseconds but AMQ has 1 second resolution.
@@ -103,7 +105,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
private long _producerId;
/**
- * The session used to create this producer
+ * The session used to create this producer
*/
protected AMQSession _session;
@@ -117,8 +119,12 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
private UUIDGen _messageIdGenerator = UUIDs.newGenerator();
+ protected String _userID; // ref user id used in the connection.
+
private static final ContentBody[] NO_CONTENT_BODIES = new ContentBody[0];
+ protected PublishMode publishMode = PublishMode.ASYNC_PUBLISH_ALL;
+
protected BasicMessageProducer(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId,
AMQSession session, AMQProtocolHandler protocolHandler, long producerId, boolean immediate, boolean mandatory,
boolean waitUntilSent)
@@ -138,6 +144,27 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
_immediate = immediate;
_mandatory = mandatory;
_waitUntilSent = waitUntilSent;
+ _userID = connection.getUsername();
+ setPublishMode();
+ }
+
+ void setPublishMode()
+ {
+ // Publish mode could be configured at destination level as well.
+ // Will add support for this when we provide a more robust binding URL
+
+ String syncPub = _connection.getSyncPublish();
+ // Support for deprecated option sync_persistence
+ if (syncPub.equals("persistent") || _connection.getSyncPersistence())
+ {
+ publishMode = PublishMode.SYNC_PUBLISH_PERSISTENT;
+ }
+ else if (syncPub.equals("all"))
+ {
+ publishMode = PublishMode.SYNC_PUBLISH_ALL;
+ }
+
+ _logger.info("MessageProducer " + toString() + " using publish mode : " + publishMode);
}
void resubscribe() throws AMQException
@@ -250,6 +277,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
checkPreConditions();
checkInitialDestination();
+
synchronized (_connection.getFailoverMutex())
{
sendImpl(_destination, message, _deliveryMode, _messagePriority, _timeToLive, _mandatory, _immediate);
@@ -521,6 +549,10 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
{
throw new javax.jms.IllegalStateException("Invalid Session");
}
+ if(_session.getAMQConnection().isClosed())
+ {
+ throw new javax.jms.IllegalStateException("Connection closed");
+ }
}
private void checkInitialDestination()
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
index 02c5526e03..a1b5ce6f4c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
@@ -35,7 +35,7 @@ import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.url.AMQBindingURL;
-import org.apache.qpid.nclient.util.ByteBufferMessage;
+import org.apache.qpid.util.Strings;
import org.apache.qpid.njms.ExceptionHelper;
import org.apache.qpid.transport.*;
import static org.apache.qpid.transport.Option.*;
@@ -45,6 +45,7 @@ import static org.apache.qpid.transport.Option.*;
*/
public class BasicMessageProducer_0_10 extends BasicMessageProducer
{
+ private byte[] userIDBytes;
BasicMessageProducer_0_10(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId,
AMQSession session, AMQProtocolHandler protocolHandler, long producerId,
@@ -52,13 +53,18 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
{
super(connection, destination, transacted, channelId, session, protocolHandler, producerId, immediate,
mandatory, waitUntilSent);
+
+ userIDBytes = Strings.toUTF8(_userID);
}
void declareDestination(AMQDestination destination)
{
- ((AMQSession_0_10) getSession()).getQpidSession().exchangeDeclare(destination.getExchangeName().toString(),
- destination.getExchangeClass().toString(),
- null, null);
+ String name = destination.getExchangeName().toString();
+ ((AMQSession_0_10) getSession()).getQpidSession().exchangeDeclare
+ (name,
+ destination.getExchangeClass().toString(),
+ null, null,
+ name.startsWith("amq.") ? Option.PASSIVE : Option.NONE);
}
//--- Overwritten methods
@@ -77,6 +83,9 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
DeliveryProperties deliveryProp = delegate.getDeliveryProperties();
MessageProperties messageProps = delegate.getMessageProperties();
+ // On the receiving side, this will be read in to the JMSXUserID as well.
+ messageProps.setUserId(userIDBytes);
+
if (messageId != null)
{
messageProps.setMessageId(messageId);
@@ -86,20 +95,22 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
messageProps.clearMessageId();
}
+ long currentTime = 0;
+ if (timeToLive > 0 || !_disableTimestamps)
+ {
+ currentTime = System.currentTimeMillis();
+ }
+
+ if (timeToLive > 0)
+ {
+ deliveryProp.setTtl(timeToLive);
+ message.setJMSExpiration(currentTime + timeToLive);
+ }
+
if (!_disableTimestamps)
{
- final long currentTime = System.currentTimeMillis();
- deliveryProp.setTimestamp(currentTime);
- if (timeToLive > 0)
- {
- deliveryProp.setExpiration(currentTime + timeToLive);
- message.setJMSExpiration(currentTime + timeToLive);
- }
- else
- {
- deliveryProp.setExpiration(0);
- message.setJMSExpiration(0);
- }
+
+ deliveryProp.setTimestamp(currentTime);
message.setJMSTimestamp(currentTime);
}
@@ -145,9 +156,13 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
((AMQSession_0_10) getSession()).getQpidSession();
// if true, we need to sync the delivery of this message
- boolean sync = (deliveryMode == DeliveryMode.PERSISTENT &&
- getSession().getAMQConnection().getSyncPersistence());
+ boolean sync = false;
+ sync = ( (publishMode == PublishMode.SYNC_PUBLISH_ALL) ||
+ (publishMode == PublishMode.SYNC_PUBLISH_PERSISTENT &&
+ deliveryMode == DeliveryMode.PERSISTENT)
+ );
+
org.apache.mina.common.ByteBuffer data = message.getData();
ByteBuffer buffer = data == null ? ByteBuffer.allocate(0) : data.buf().slice();
@@ -159,11 +174,12 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
{
ssn.sync();
}
+
+
}
catch (RuntimeException rte)
{
JMSException ex = new JMSException("Exception when sending message");
- rte.printStackTrace();
ex.setLinkedException(rte);
throw ex;
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
index c547fcb488..f726cd02a2 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
@@ -24,6 +24,8 @@ import java.util.UUID;
import javax.jms.JMSException;
import javax.jms.Message;
+import javax.jms.Topic;
+import javax.jms.Queue;
import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.client.message.AbstractJMSMessage;
@@ -86,6 +88,26 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer
AMQMessageDelegate_0_8 delegate = (AMQMessageDelegate_0_8) message.getDelegate();
BasicContentHeaderProperties contentHeaderProperties = delegate.getContentHeaderProperties();
+ contentHeaderProperties.setUserId(_userID);
+
+ //Set the JMS_QPID_DESTTYPE for 0-8/9 messages
+ int type;
+ if (destination instanceof Topic)
+ {
+ type = AMQDestination.TOPIC_TYPE;
+ }
+ else if (destination instanceof Queue)
+ {
+ type = AMQDestination.QUEUE_TYPE;
+ }
+ else
+ {
+ type = AMQDestination.UNKNOWN_TYPE;
+ }
+
+ //Set JMS_QPID_DESTTYPE
+ delegate.getContentHeaderProperties().getHeaders().setInteger(CustomJMSXProperty.JMS_QPID_DESTTYPE.getShortStringName(), type);
+
if (!_disableTimestamps)
{
final long currentTime = System.currentTimeMillis();
diff --git a/java/client/src/main/java/org/apache/qpid/client/Closeable.java b/java/client/src/main/java/org/apache/qpid/client/Closeable.java
index 7e119343a1..e6771e122c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/Closeable.java
+++ b/java/client/src/main/java/org/apache/qpid/client/Closeable.java
@@ -52,6 +52,13 @@ public abstract class Closeable
protected final AtomicBoolean _closed = new AtomicBoolean(false);
/**
+ * Are we in the process of closing. We have this distinction so we can
+ * still signal we are in the process of closing so other objects can tell
+ * the difference and tidy up.
+ */
+ protected final AtomicBoolean _closing = new AtomicBoolean(false);
+
+ /**
* Checks if this is closed, and raises a JMSException if it is.
*
* @throws JMSException If this is closed.
@@ -75,6 +82,17 @@ public abstract class Closeable
}
/**
+ * Checks if this is closis.
+ *
+ * @return <tt>true</tt> if we are closing, <tt>false</tt> otherwise.
+ */
+ public boolean isClosing()
+ {
+ return _closing.get();
+ }
+
+
+ /**
* Closes this object.
*
* @throws JMSException If this cannot be closed for any reason.
diff --git a/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java b/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
index 476536e42b..43025bd724 100644
--- a/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
+++ b/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
@@ -47,7 +47,7 @@ public class XAConnectionImpl extends AMQConnection implements XAConnection, XAQ
public synchronized XASession createXASession() throws JMSException
{
checkNotClosed();
- return _delegate.createXASession(AMQSession.DEFAULT_PREFETCH_HIGH_MARK, AMQSession.DEFAULT_PREFETCH_HIGH_MARK);
+ return _delegate.createXASession();
}
//-- Interface XAQueueConnection
diff --git a/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java b/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
index 6763c72ecd..35adda9348 100644
--- a/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
+++ b/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
@@ -88,8 +88,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
checkStatus(result.getStatus());
}
@@ -142,8 +141,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
checkStatus(result.getStatus());
}
@@ -171,8 +169,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
}
@@ -201,8 +198,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
}
return result;
@@ -248,8 +244,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
DtxXaStatus status = result.getStatus();
int outcome = XAResource.XA_OK;
@@ -291,8 +286,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr( e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr( e.getException().getErrorCode());
}
Xid[] result = new Xid[res.getInDoubt().size()];
int i = 0;
@@ -329,8 +323,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr( e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr( e.getException().getErrorCode());
}
checkStatus(result.getStatus());
}
@@ -413,8 +406,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
// TODO: The amqp spec does not allow to make the difference
// between an already known XID and a wrong arguments (join and resume are set)
// TODO: make sure amqp addresses that
diff --git a/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java b/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
index 51b4b7899f..354b67cd35 100644
--- a/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
+++ b/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
@@ -17,7 +17,6 @@
*/
package org.apache.qpid.client;
-import org.apache.qpid.nclient.DtxSession;
import org.apache.qpid.client.message.MessageFactoryRegistry;
import javax.jms.*;
@@ -36,7 +35,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
/**
* This XASession Qpid DtxSession
*/
- private DtxSession _qpidDtxSession;
+ private org.apache.qpid.transport.Session _qpidDtxSession;
/**
* The standard session
@@ -48,7 +47,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
/**
* Create a JMS XASession
*/
- public XASessionImpl(org.apache.qpid.nclient.Connection qpidConnection, AMQConnection con, int channelId,
+ public XASessionImpl(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
int defaultPrefetchHigh, int defaultPrefetchLow)
{
super(qpidConnection, con, channelId, false, // this is not a transacted session
@@ -65,7 +64,9 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
*/
public void createSession()
{
- _qpidDtxSession = _qpidConnection.createDTXSession(0);
+ _qpidDtxSession = _qpidConnection.createSession(0);
+ _qpidDtxSession.setSessionListener(this);
+ _qpidDtxSession.dtxSelect();
}
@@ -126,7 +127,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
*
* @return The associated Qpid Session.
*/
- protected org.apache.qpid.nclient.DtxSession getQpidSession()
+ protected org.apache.qpid.transport.Session getQpidSession()
{
return _qpidDtxSession;
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java b/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
index edda18c715..e5050b4fbd 100644
--- a/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
+++ b/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
@@ -33,13 +33,13 @@ public class ClientProperties
public static final String IGNORE_SET_CLIENTID_PROP_NAME = "ignore_setclientID";
/**
- * This property is currently used within the 0.10 code path only
+ * This property is currently used within the 0.10 code path only
* The maximum number of pre-fetched messages per destination
* This property is used for all the connection unless it is overwritten by the connectionURL
* type: long
*/
public static final String MAX_PREFETCH_PROP_NAME = "max_prefetch";
- public static final String MAX_PREFETCH_DEFAULT = "1000";
+ public static final String MAX_PREFETCH_DEFAULT = "500";
/**
* When true a sync command is sent after every persistent messages.
@@ -47,6 +47,31 @@ public class ClientProperties
*/
public static final String SYNC_PERSISTENT_PROP_NAME = "sync_persistence";
+ /**
+ * When true a sync command is sent after sending a message ack.
+ * type: boolean
+ */
+ public static final String SYNC_ACK_PROP_NAME = "sync_ack";
+
+ /**
+ * sync_publish property - {persistent|all}
+ * If set to 'persistent',then persistent messages will be publish synchronously
+ * If set to 'all', then all messages regardless of the delivery mode will be
+ * published synchronously.
+ */
+ public static final String SYNC_PUBLISH_PROP_NAME = "sync_publish";
+
+ /**
+ * This value will be used in the following settings
+ * To calculate the SO_TIMEOUT option of the socket (2*idle_timeout)
+ * If this values is between the max and min values specified for heartbeat
+ * by the broker in TuneOK it will be used as the heartbeat interval.
+ * If not a warning will be printed and the max value specified for
+ * heartbeat in TuneOK will be used
+ */
+ public static final String IDLE_TIMEOUT_PROP_NAME = "idle_timeout";
+
+
/**
* ==========================================================
* Those properties are used when the io size should be bounded
@@ -75,4 +100,6 @@ public class ClientProperties
*/
public static final String WRITE_BUFFER_LIMIT_PROP_NAME = "qpid.read.buffer.limit";
public static final String WRITE_BUFFER_LIMIT_DEFAULT = "262144";
+
+ public static final String AMQP_VERSION = "qpid.amqp.version";
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java b/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
index 927f660932..f74dbba939 100644
--- a/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
@@ -20,11 +20,10 @@
*/
package org.apache.qpid.client.failover;
-import org.apache.mina.common.IoSession;
-
import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.AMQState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -81,9 +80,6 @@ public class FailoverHandler implements Runnable
/** Used for debugging. */
private static final Logger _logger = LoggerFactory.getLogger(FailoverHandler.class);
- /** Holds the MINA session for the connection that has failed, not the connection that is being failed onto. */
- private final IoSession _session;
-
/** Holds the protocol handler for the failed connection, upon which the new connection is to be set up. */
private AMQProtocolHandler _amqProtocolHandler;
@@ -97,12 +93,10 @@ public class FailoverHandler implements Runnable
* Creates a failover handler on a protocol session, for a particular MINA session (network connection).
*
* @param amqProtocolHandler The protocol handler that spans the failover.
- * @param session The MINA session, for the failing connection.
*/
- public FailoverHandler(AMQProtocolHandler amqProtocolHandler, IoSession session)
+ public FailoverHandler(AMQProtocolHandler amqProtocolHandler)
{
_amqProtocolHandler = amqProtocolHandler;
- _session = session;
}
/**
@@ -140,6 +134,8 @@ public class FailoverHandler implements Runnable
// a slightly more complex state model therefore I felt it was worthwhile doing this.
AMQStateManager existingStateManager = _amqProtocolHandler.getStateManager();
+
+ // Use a fresh new StateManager for the reconnection attempts
_amqProtocolHandler.setStateManager(new AMQStateManager());
@@ -194,9 +190,25 @@ public class FailoverHandler implements Runnable
}
else
{
- // Set the new Protocol Session in the StateManager.
+ // Set the new Protocol Session in the StateManager.
existingStateManager.setProtocolSession(_amqProtocolHandler.getProtocolSession());
+ // Now that the ProtocolHandler has been reconnected clean up
+ // the state of the old state manager. As if we simply reinstate
+ // it any old exception that had occured prior to failover may
+ // prohibit reconnection.
+ // e.g. During testing when the broker is shutdown gracefully.
+ // The broker
+ // Clear any exceptions we gathered
+ if (existingStateManager.getCurrentState() != AMQState.CONNECTION_OPEN)
+ {
+ // Clear the state of the previous state manager as it may
+ // have received an exception
+ existingStateManager.clearLastException();
+ existingStateManager.changeState(AMQState.CONNECTION_OPEN);
+ }
+
+
//Restore Existing State Manager
_amqProtocolHandler.setStateManager(existingStateManager);
try
@@ -221,7 +233,7 @@ public class FailoverHandler implements Runnable
_amqProtocolHandler.setFailoverState(FailoverState.FAILED);
/*try
{*/
- _amqProtocolHandler.exceptionCaught(_session, e);
+ _amqProtocolHandler.exception(e);
/*}
catch (Exception ex)
{
diff --git a/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java b/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java
index cf7e978c03..e9e52cc97c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java
+++ b/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java
@@ -99,37 +99,6 @@ public class FailoverRetrySupport<T, E extends Exception> implements FailoverSup
*/
public T execute() throws E
{
- while (true)
- {
- try
- {
- connection.blockUntilNotFailingOver();
- }
- catch (InterruptedException e)
- {
- _log.debug("Interrupted: " + e, e);
-
- return null;
- }
-
- synchronized (connection.getFailoverMutex())
- {
- try
- {
- return operation.execute();
- }
- catch (FailoverException e)
- {
- _log.debug("Failover exception caught during operation: " + e, e);
- }
- catch (IllegalStateException e)
- {
- if (!(e.getMessage().startsWith("Fail-over interupted no-op failover support")))
- {
- throw e;
- }
- }
- }
- }
+ return connection.executeRetrySupport(operation);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java
index 365fed6aa5..af47673a43 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java
@@ -1,4 +1,25 @@
package org.apache.qpid.client.handler;
+/*
+ *
+ * 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.
+ *
+ */
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
index 2b6745ebe4..2cf19bf391 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
@@ -32,7 +32,6 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ChannelCloseBody;
import org.apache.qpid.framing.ChannelCloseOkBody;
import org.apache.qpid.protocol.AMQConstant;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,7 +47,7 @@ public class ChannelCloseMethodHandler implements StateAwareMethodListener<Chann
}
public void methodReceived(AMQProtocolSession session, ChannelCloseBody method, int channelId)
- throws AMQException
+ throws AMQException
{
_logger.debug("ChannelClose method received");
@@ -59,52 +58,62 @@ public class ChannelCloseMethodHandler implements StateAwareMethodListener<Chann
_logger.debug("Channel close reply code: " + errorCode + ", reason: " + reason);
}
-
-
ChannelCloseOkBody body = session.getMethodRegistry().createChannelCloseOkBody();
AMQFrame frame = body.generateFrame(channelId);
session.writeFrame(frame);
-
- if (errorCode != AMQConstant.REPLY_SUCCESS)
+ try
{
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Channel close received with errorCode " + errorCode + ", and reason " + reason);
- }
-
- if (errorCode == AMQConstant.NO_CONSUMERS)
- {
- throw new AMQNoConsumersException("Error: " + reason, null, null);
- }
- else if (errorCode == AMQConstant.NO_ROUTE)
- {
- throw new AMQNoRouteException("Error: " + reason, null, null);
- }
- else if (errorCode == AMQConstant.INVALID_ARGUMENT)
+ if (errorCode != AMQConstant.REPLY_SUCCESS)
{
- _logger.debug("Broker responded with Invalid Argument.");
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Channel close received with errorCode " + errorCode + ", and reason " + reason);
+ }
+
+ if (errorCode == AMQConstant.NO_CONSUMERS)
+ {
+ throw new AMQNoConsumersException("Error: " + reason, null, null);
+ }
+ else if (errorCode == AMQConstant.NO_ROUTE)
+ {
+ throw new AMQNoRouteException("Error: " + reason, null, null);
+ }
+ else if (errorCode == AMQConstant.INVALID_ARGUMENT)
+ {
+ _logger.debug("Broker responded with Invalid Argument.");
+
+ throw new org.apache.qpid.AMQInvalidArgumentException(String.valueOf(reason), null);
+ }
+ else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
+ {
+ _logger.debug("Broker responded with Invalid Routing Key.");
+
+ throw new AMQInvalidRoutingKeyException(String.valueOf(reason), null);
+ }
+ else
+ {
+
+ throw new AMQChannelClosedException(errorCode, "Error: " + reason, null);
+ }
- throw new org.apache.qpid.AMQInvalidArgumentException(String.valueOf(reason), null);
- }
- else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
- {
- _logger.debug("Broker responded with Invalid Routing Key.");
-
- throw new AMQInvalidRoutingKeyException(String.valueOf(reason), null);
- }
- else
- {
- throw new AMQChannelClosedException(errorCode, "Error: " + reason, null);
}
-
}
- // fixme why is this only done when the close is expected...
- // should the above forced closes not also cause a close?
- // ----------
- // Closing the session only when it is expected allows the errors to be processed
- // Calling this here will prevent failover. So we should do this for all exceptions
- // that should never cause failover. Such as authentication errors.
-
- session.channelClosed(channelId, errorCode, String.valueOf(reason));
+ finally
+ {
+ // fixme why is this only done when the close is expected...
+ // should the above forced closes not also cause a close?
+ // ----------
+ // Closing the session only when it is expected allows the errors to be processed
+ // Calling this here will prevent failover. So we should do this for all exceptions
+ // that should never cause failover. Such as authentication errors.
+ // ----
+ // 2009-09-07 - ritchiem
+ // calling channelClosed will only close this session and will not
+ // prevent failover. If we don't close the session here then we will
+ // have problems during the session close as it will attempt to
+ // close the session that the broker has closed,
+
+ session.channelClosed(channelId, errorCode, String.valueOf(reason));
+ }
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java b/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
index 9c791730ca..909ac8aae8 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
@@ -39,6 +39,7 @@ public class ClientMethodDispatcherImpl implements MethodDispatcher
private static final BasicReturnMethodHandler _basicReturnMethodHandler = BasicReturnMethodHandler.getInstance();
private static final ChannelCloseMethodHandler _channelCloseMethodHandler = ChannelCloseMethodHandler.getInstance();
private static final ChannelFlowOkMethodHandler _channelFlowOkMethodHandler = ChannelFlowOkMethodHandler.getInstance();
+ private static final ChannelFlowMethodHandler _channelFlowMethodHandler = ChannelFlowMethodHandler.getInstance();
private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance();
private static final ConnectionOpenOkMethodHandler _connectionOpenOkMethodHandler = ConnectionOpenOkMethodHandler.getInstance();
private static final ConnectionRedirectMethodHandler _connectionRedirectMethodHandler = ConnectionRedirectMethodHandler.getInstance();
@@ -78,6 +79,16 @@ public class ClientMethodDispatcherImpl implements MethodDispatcher
}
});
+
+ _dispatcherFactories.put(ProtocolVersion.v0_91,
+ new DispatcherFactory()
+ {
+ public ClientMethodDispatcherImpl createMethodDispatcher(AMQProtocolSession session)
+ {
+ return new ClientMethodDispatcherImpl_0_91(session);
+ }
+ });
+
}
public static ClientMethodDispatcherImpl newMethodDispatcher(ProtocolVersion version, AMQProtocolSession session)
@@ -159,7 +170,8 @@ public class ClientMethodDispatcherImpl implements MethodDispatcher
public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException
{
- return false;
+ _channelFlowMethodHandler.methodReceived(_session, body, channelId);
+ return true;
}
public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl_0_91.java b/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl_0_91.java
new file mode 100644
index 0000000000..f15340ae00
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl_0_91.java
@@ -0,0 +1,158 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.handler;
+
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.MethodDispatcher_0_91;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.AMQMethodNotImplementedException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+
+public class ClientMethodDispatcherImpl_0_91 extends ClientMethodDispatcherImpl implements MethodDispatcher_0_91
+{
+ public ClientMethodDispatcherImpl_0_91(AMQProtocolSession session)
+ {
+ super(session);
+ }
+
+ public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+} \ No newline at end of file
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
index e639a33450..e40cafd72f 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
@@ -40,7 +40,6 @@ public class ConnectionOpenOkMethodHandler implements StateAwareMethodListener<C
}
public void methodReceived(AMQProtocolSession session, ConnectionOpenOkBody body, int channelId)
- throws AMQException
{
session.getStateManager().changeState(AMQState.CONNECTION_OPEN);
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
index 8857f1115a..c9212a54c1 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
@@ -68,6 +68,14 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener<Co
ProtocolVersion pv = new ProtocolVersion((byte) body.getVersionMajor(), (byte) body.getVersionMinor());
+ // 0-9-1 is indistinguishable from 0-9 using only major and minor ... if we established the connection as 0-9-1
+ // and now get back major = 0 , minor = 9 then we can assume it means 0-9-1
+
+ if(pv.equals(ProtocolVersion.v0_9) && session.getProtocolVersion().equals(ProtocolVersion.v0_91))
+ {
+ pv = ProtocolVersion.v0_91;
+ }
+
// For the purposes of interop, we can make the client accept the broker's version string.
// If it does, it then internally records the version as being the latest one that it understands.
// It needs to do this since frame lookup is done by version.
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
index e4e58c317d..287b5957a1 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
@@ -45,7 +45,6 @@ public class ConnectionTuneMethodHandler implements StateAwareMethodListener<Con
{ }
public void methodReceived(AMQProtocolSession session, ConnectionTuneBody frame, int channelId)
- throws AMQException
{
_logger.debug("ConnectionTune frame received");
final MethodRegistry methodRegistry = session.getMethodRegistry();
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java
index 7f43e4b4b2..314508805d 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java
@@ -22,7 +22,6 @@
package org.apache.qpid.client.message;
import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
import javax.jms.Destination;
import javax.jms.JMSException;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
index 8b4488f1f9..1479f06632 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
@@ -29,7 +29,6 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQPInvalidClassException;
-import org.apache.qpid.nclient.*;
import org.apache.qpid.jms.Message;
import org.apache.qpid.url.BindingURL;
import org.apache.qpid.url.AMQBindingURL;
@@ -42,12 +41,13 @@ import javax.jms.MessageNotWriteableException;
import javax.jms.MessageFormatException;
import javax.jms.DeliveryMode;
import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import org.apache.qpid.exchange.ExchangeDefaults;
-public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
+/**
+ * This extends AbstractAMQMessageDelegate which contains common code between
+ * both the 0_8 and 0_10 Message types.
+ *
+ */
+public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate
{
private static final Map<ReplyTo, Destination> _destinationCache = Collections.synchronizedMap(new ReferenceMap());
@@ -65,27 +65,6 @@ public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
private AMQSession _session;
private final long _deliveryTag;
- private static Map<AMQShortString,Integer> _exchangeTypeMap = new ConcurrentHashMap<AMQShortString, Integer>();
- private static Map<String,Integer> _exchangeTypeStringMap = new ConcurrentHashMap<String, Integer>();
- private static Map<String, Integer> _exchangeTypeToDestinationType = new ConcurrentHashMap<String, Integer>();;
-
- static
- {
- _exchangeTypeMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME, AMQDestination.QUEUE_TYPE);
- _exchangeTypeMap.put(AMQShortString.EMPTY_STRING, AMQDestination.QUEUE_TYPE);
- _exchangeTypeMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
- _exchangeTypeMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
-
- _exchangeTypeStringMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME.toString(), AMQDestination.QUEUE_TYPE);
- _exchangeTypeStringMap.put("", AMQDestination.QUEUE_TYPE);
- _exchangeTypeStringMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
- _exchangeTypeStringMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
-
-
- _exchangeTypeToDestinationType.put(ExchangeDefaults.DIRECT_EXCHANGE_CLASS.toString(), AMQDestination.QUEUE_TYPE);
- _exchangeTypeToDestinationType.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
- _exchangeTypeToDestinationType.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
- }
protected AMQMessageDelegate_0_10()
{
@@ -93,87 +72,49 @@ public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
_readableProperties = false;
}
- protected AMQMessageDelegate_0_10(long deliveryTag, MessageProperties messageProps, DeliveryProperties deliveryProps, AMQShortString exchange,
- AMQShortString routingKey) throws AMQException
+ protected AMQMessageDelegate_0_10(MessageProperties messageProps, DeliveryProperties deliveryProps, long deliveryTag)
{
- this(messageProps, deliveryProps, deliveryTag);
-
-
- AMQDestination dest;
-
- dest = generateDestination(exchange, routingKey);
- setJMSDestination(dest);
- }
+ _messageProps = messageProps;
+ _deliveryProps = deliveryProps;
+ _deliveryTag = deliveryTag;
+ _readableProperties = (_messageProps != null);
- private AMQDestination generateDestination(AMQShortString exchange, AMQShortString routingKey)
- {
AMQDestination dest;
- switch(getExchangeType(exchange))
- {
- case AMQDestination.QUEUE_TYPE:
- dest = new AMQQueue(exchange, routingKey, routingKey);
- break;
- case AMQDestination.TOPIC_TYPE:
- dest = new AMQTopic(exchange, routingKey, null);
- break;
- default:
- dest = new AMQUndefinedDestination(exchange, routingKey, null);
-
- }
-
- return dest;
- }
-
- private int getExchangeType(AMQShortString exchange)
- {
- Integer type = _exchangeTypeMap.get(exchange == null ? AMQShortString.EMPTY_STRING : exchange);
-
- if(type == null)
- {
- return AMQDestination.UNKNOWN_TYPE;
- }
-
- return type;
+ dest = generateDestination(new AMQShortString(_deliveryProps.getExchange()),
+ new AMQShortString(_deliveryProps.getRoutingKey()));
+ setJMSDestination(dest);
}
-
- public static void updateExchangeTypeMapping(Header header, org.apache.qpid.nclient.Session session)
+ /**
+ * Use the 0-10 ExchangeQuery call to validate the exchange type.
+ *
+ * This is used primarily to provide the correct JMSDestination value.
+ *
+ * The query is performed synchronously iff the map exchange is not already
+ * present in the exchange Map.
+ *
+ * @param header The message headers, from which the exchange name can be extracted
+ * @param session The 0-10 session to use to call ExchangeQuery
+ */
+ public static void updateExchangeTypeMapping(Header header, org.apache.qpid.transport.Session session)
{
DeliveryProperties deliveryProps = header.get(DeliveryProperties.class);
- if(deliveryProps != null)
+ if (deliveryProps != null)
{
String exchange = deliveryProps.getExchange();
- if(exchange != null && !_exchangeTypeStringMap.containsKey(exchange))
+ if (exchange != null && !exchangeMapContains(exchange))
{
-
- AMQShortString exchangeShortString = new AMQShortString(exchange);
Future<ExchangeQueryResult> future =
- session.exchangeQuery(exchange.toString());
+ session.exchangeQuery(exchange.toString());
ExchangeQueryResult res = future.get();
- Integer type = _exchangeTypeToDestinationType.get(res.getType());
- if(type == null)
- {
- type = AMQDestination.UNKNOWN_TYPE;
- }
- _exchangeTypeStringMap.put(exchange, type);
- _exchangeTypeMap.put(exchangeShortString, type);
-
+ updateExchangeType(exchange, res.getType());
}
}
}
- protected AMQMessageDelegate_0_10(MessageProperties messageProps, DeliveryProperties deliveryProps, long deliveryTag)
- {
- _messageProps = messageProps;
- _deliveryProps = deliveryProps;
- _deliveryTag = deliveryTag;
- _readableProperties = (_messageProps != null);
-
- }
-
public String getJMSMessageID() throws JMSException
{
@@ -287,7 +228,8 @@ public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
{
if (destination == null)
{
- throw new IllegalArgumentException("Null destination not allowed");
+ _messageProps.setReplyTo(null);
+ return;
}
if (!(destination instanceof AMQDestination))
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
index 4c20a44849..5157632280 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
@@ -46,7 +46,7 @@ import java.util.Enumeration;
import java.util.UUID;
import java.net.URISyntaxException;
-public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
+public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate
{
private static final Map _destinationCache = Collections.synchronizedMap(new ReferenceMap());
@@ -65,6 +65,16 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
private AMQSession _session;
private final long _deliveryTag;
+ // The base set of items that needs to be set.
+ private AMQMessageDelegate_0_8(BasicContentHeaderProperties properties, long deliveryTag)
+ {
+ _contentHeaderProperties = properties;
+ _deliveryTag = deliveryTag;
+ _readableProperties = (_contentHeaderProperties != null);
+ _headerAdapter = new JMSHeaderAdapter(((BasicContentHeaderProperties) _contentHeaderProperties).getHeaders());
+ }
+
+ // Used for the creation of new messages
protected AMQMessageDelegate_0_8()
{
this(new BasicContentHeaderProperties(), -1);
@@ -73,6 +83,7 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
}
+ // Used when generating a received message object
protected AMQMessageDelegate_0_8(long deliveryTag, BasicContentHeaderProperties contentHeader, AMQShortString exchange,
AMQShortString routingKey)
{
@@ -80,41 +91,33 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
Integer type = contentHeader.getHeaders().getInteger(CustomJMSXProperty.JMS_QPID_DESTTYPE.getShortStringName());
- if(type == null)
+ AMQDestination dest = null;
+
+ // If we have a type set the attempt to use that.
+ if (type != null)
{
- type = AMQDestination.UNKNOWN_TYPE;
+ switch (type.intValue())
+ {
+ case AMQDestination.QUEUE_TYPE:
+ dest = new AMQQueue(exchange, routingKey, routingKey);
+ break;
+ case AMQDestination.TOPIC_TYPE:
+ dest = new AMQTopic(exchange, routingKey, null);
+ break;
+ default:
+ // Use the generateDestination method
+ dest = null;
+ }
}
- AMQDestination dest;
-
- switch(type.intValue())
+ if (dest == null)
{
- case AMQDestination.QUEUE_TYPE:
- dest = new AMQQueue(exchange, routingKey, routingKey);
- break;
- case AMQDestination.TOPIC_TYPE:
- dest = new AMQTopic(exchange, routingKey, null);
- break;
- default:
- dest = new AMQUndefinedDestination(exchange, routingKey, null);
+ dest = generateDestination(exchange, routingKey);
}
-
-
- // Destination dest = AMQDestination.createDestination(url);
setJMSDestination(dest);
-
-
-
}
- protected AMQMessageDelegate_0_8(BasicContentHeaderProperties properties, long deliveryTag)
- {
- _contentHeaderProperties = properties;
- _deliveryTag = deliveryTag;
- _readableProperties = (_contentHeaderProperties != null);
- _headerAdapter = new JMSHeaderAdapter(((BasicContentHeaderProperties) _contentHeaderProperties).getHeaders());
- }
public String getJMSMessageID() throws JMSException
@@ -124,12 +127,18 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
public void setJMSMessageID(String messageId) throws JMSException
{
- getContentHeaderProperties().setMessageId(messageId);
+ if (messageId != null)
+ {
+ getContentHeaderProperties().setMessageId(messageId);
+ }
}
public void setJMSMessageID(UUID messageId) throws JMSException
{
- getContentHeaderProperties().setMessageId("ID:" + messageId);
+ if (messageId != null)
+ {
+ getContentHeaderProperties().setMessageId("ID:" + messageId);
+ }
}
@@ -196,7 +205,8 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
{
if (destination == null)
{
- throw new IllegalArgumentException("Null destination not allowed");
+ getContentHeaderProperties().setReplyTo((String) null);
+ return; // We're done here
}
if (!(destination instanceof AMQDestination))
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java
new file mode 100644
index 0000000000..534fb19b76
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java
@@ -0,0 +1,151 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.message;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.AMQUndefinedDestination;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This abstract class provides exchange lookup functionality that is shared
+ * between all MessageDelegates. Update facilities are provided so that the 0-10
+ * code base can update the mappings. The 0-8 code base does not have the
+ * facility to update the exchange map so it can only use the default mappings.
+ *
+ * That said any updates that a 0-10 client performs will also benefit any 0-8
+ * connections in this VM.
+ *
+ */
+public abstract class AbstractAMQMessageDelegate implements AMQMessageDelegate
+{
+
+ private static Map<AMQShortString, Integer> _exchangeTypeMap = new ConcurrentHashMap<AMQShortString, Integer>();
+ private static Map<String, Integer> _exchangeTypeStringMap = new ConcurrentHashMap<String, Integer>();
+ private static Map<String, Integer> _exchangeTypeToDestinationType = new ConcurrentHashMap<String, Integer>();
+
+ /**
+ * Add default Mappings for the Direct, Default, Topic and Fanout exchanges.
+ */
+ static
+ {
+ _exchangeTypeMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME, AMQDestination.QUEUE_TYPE);
+ _exchangeTypeMap.put(AMQShortString.EMPTY_STRING, AMQDestination.QUEUE_TYPE);
+ _exchangeTypeMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
+ _exchangeTypeMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
+
+ _exchangeTypeStringMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME.toString(), AMQDestination.QUEUE_TYPE);
+ _exchangeTypeStringMap.put("", AMQDestination.QUEUE_TYPE);
+ _exchangeTypeStringMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
+ _exchangeTypeStringMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
+
+ _exchangeTypeToDestinationType.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME.toString(), AMQDestination.QUEUE_TYPE);
+ _exchangeTypeToDestinationType.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
+ _exchangeTypeToDestinationType.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
+ }
+
+ /**
+ * Called when a Destination is requried.
+ *
+ * This will create the AMQDestination that is the correct type and value
+ * based on the incomming values.
+ * @param exchange The exchange name
+ * @param routingKey The routing key to be used for the Destination
+ * @return AMQDestination of the correct subtype
+ */
+ protected AMQDestination generateDestination(AMQShortString exchange, AMQShortString routingKey)
+ {
+ AMQDestination dest;
+ switch (getExchangeType(exchange))
+ {
+ case AMQDestination.QUEUE_TYPE:
+ dest = new AMQQueue(exchange, routingKey, routingKey);
+ break;
+ case AMQDestination.TOPIC_TYPE:
+ dest = new AMQTopic(exchange, routingKey, null);
+ break;
+ default:
+ dest = new AMQUndefinedDestination(exchange, routingKey, null);
+ }
+
+ return dest;
+ }
+
+ /**
+ * Update the exchange name to type mapping.
+ *
+ * If the newType is not known then an UNKNOWN_TYPE is created. Only if the
+ * exchange is of a known type: amq.direct, amq.topic, amq.fanout can we
+ * create a suitable AMQDestination representation
+ *
+ * @param exchange the name of the exchange
+ * @param newtype the AMQP exchange class name i.e. amq.direct
+ */
+ protected static void updateExchangeType(String exchange, String newtype)
+ {
+ Integer type = _exchangeTypeToDestinationType.get(newtype);
+ if (type == null)
+ {
+ type = AMQDestination.UNKNOWN_TYPE;
+ }
+ _exchangeTypeStringMap.put(exchange, type);
+ _exchangeTypeMap.put(new AMQShortString(exchange), type);
+ }
+
+ /**
+ * Accessor method to allow lookups of the given exchange name.
+ *
+ * This check allows the prevention of extra work required such as asking
+ * the broker for the exchange class name.
+ *
+ * @param exchange the exchange name to lookup
+ * @return true if there is a mapping for this exchange
+ */
+ protected static boolean exchangeMapContains(String exchange)
+ {
+ return _exchangeTypeStringMap.containsKey(exchange);
+ }
+
+ /**
+ * Returns an int representing the exchange type. This is used in the
+ * createDestination method to ensure the correct AMQDestiation is created.
+ *
+ * @param exchange the exchange name to lookup
+ * @return int representing the Exchange type
+ */
+ private int getExchangeType(AMQShortString exchange)
+ {
+ Integer type = _exchangeTypeMap.get(exchange == null ? AMQShortString.EMPTY_STRING : exchange);
+
+ if (type == null)
+ {
+ return AMQDestination.UNKNOWN_TYPE;
+ }
+
+ return type;
+ }
+
+}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java
index c0d51fa726..535b55ced5 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java
@@ -31,6 +31,7 @@ import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.transport.util.Functions;
/**
* @author Apache Software Foundation
@@ -84,53 +85,26 @@ public abstract class AbstractBytesMessage extends AbstractJMSMessage
}
public String toBodyString() throws JMSException
- {
- checkReadable();
+ {
try
{
- return getText();
+ if (_data != null)
+ {
+ return Functions.str(_data.buf(), 100,0);
+ }
+ else
+ {
+ return "";
+ }
+
}
- catch (IOException e)
+ catch (Exception e)
{
JMSException jmse = new JMSException(e.toString());
jmse.setLinkedException(e);
throw jmse;
}
- }
-
- /**
- * We reset the stream before and after reading the data. This means that toString() will always output
- * the entire message and also that the caller can then immediately start reading as if toString() had
- * never been called.
- *
- * @return
- * @throws IOException
- */
- private String getText() throws IOException
- {
- // this will use the default platform encoding
- if (_data == null)
- {
- return null;
- }
-
- int pos = _data.position();
- _data.rewind();
- // one byte left is for the end of frame marker
- if (_data.remaining() == 0)
- {
- // this is really redundant since pos must be zero
- _data.position(pos);
-
- return null;
- }
- else
- {
- String data = _data.getString(Charset.forName("UTF8").newDecoder());
- _data.position(pos);
-
- return data;
- }
+
}
/**
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java
index 0700ce5d23..288a4ea85c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java
@@ -367,13 +367,14 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message
try
{
StringBuffer buf = new StringBuffer("Body:\n");
+
buf.append(toBodyString());
buf.append("\nJMS Correlation ID: ").append(getJMSCorrelationID());
buf.append("\nJMS timestamp: ").append(getJMSTimestamp());
buf.append("\nJMS expiration: ").append(getJMSExpiration());
buf.append("\nJMS priority: ").append(getJMSPriority());
buf.append("\nJMS delivery mode: ").append(getJMSDeliveryMode());
- //buf.append("\nJMS reply to: ").append(String.valueOf(getJMSReplyTo()));
+ buf.append("\nJMS reply to: ").append(getReplyToString());
buf.append("\nJMS Redelivered: ").append(_redelivered);
buf.append("\nJMS Destination: ").append(getJMSDestination());
buf.append("\nJMS Type: ").append(getJMSType());
@@ -392,7 +393,7 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message
while(propertyNames.hasMoreElements())
{
String propertyName = (String) propertyNames.nextElement();
- buf.append(propertyName).append(":\t").append(getObjectProperty(propertyName));
+ buf.append("\t").append(propertyName).append(" = ").append(getObjectProperty(propertyName)).append("\n");
}
}
@@ -401,7 +402,7 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message
}
catch (JMSException e)
{
- return e.toString();
+ throw new RuntimeException(e);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
index 54a845ceef..e719c9a4b2 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
@@ -27,7 +27,6 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ContentBody;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.transport.Struct;
import org.apache.qpid.transport.MessageProperties;
import org.apache.qpid.transport.DeliveryProperties;
@@ -109,7 +108,8 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory
protected abstract AbstractJMSMessage createMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException;
- protected AbstractJMSMessage create010MessageWithBody(long messageNbr, Struct[] contentHeader,
+ protected AbstractJMSMessage create010MessageWithBody(long messageNbr, MessageProperties msgProps,
+ DeliveryProperties deliveryProps,
java.nio.ByteBuffer body) throws AMQException
{
ByteBuffer data;
@@ -130,11 +130,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory
_logger.debug("Creating message from buffer with position=" + data.position() + " and remaining=" + data
.remaining());
}
- // set the properties of this message
- MessageProperties mprop = (MessageProperties) contentHeader[0];
- DeliveryProperties devprop = (DeliveryProperties) contentHeader[1];
-
- AMQMessageDelegate delegate = new AMQMessageDelegate_0_10(mprop, devprop, messageNbr);
+ AMQMessageDelegate delegate = new AMQMessageDelegate_0_10(msgProps, deliveryProps, messageNbr);
AbstractJMSMessage message = createMessage(delegate, data);
return message;
@@ -163,12 +159,12 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory
return msg;
}
- public AbstractJMSMessage createMessage(long messageNbr, boolean redelivered, Struct[] contentHeader,
- java.nio.ByteBuffer body)
+ public AbstractJMSMessage createMessage(long messageNbr, boolean redelivered, MessageProperties msgProps,
+ DeliveryProperties deliveryProps, java.nio.ByteBuffer body)
throws JMSException, AMQException
{
final AbstractJMSMessage msg =
- create010MessageWithBody(messageNbr, contentHeader, body);
+ create010MessageWithBody(messageNbr,msgProps,deliveryProps, body);
msg.setJMSRedelivered(redelivered);
msg.receivedFromServer();
return msg;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java b/java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java
index 3db628017f..5b8a4ce878 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java
@@ -1,4 +1,25 @@
package org.apache.qpid.client.message;
+/*
+ *
+ * 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.
+ *
+ */
+
import java.util.Enumeration;
import java.util.HashMap;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java
index cd9d7ccf8b..8681dae2bd 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java
@@ -381,10 +381,4 @@ public class JMSBytesMessage extends AbstractBytesMessage implements BytesMessag
throw new MessageFormatException("Only primitives plus byte arrays and String are valid types");
}
}
-
- public String toString()
- {
- return String.valueOf(System.identityHashCode(this));
- }
-
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
index 39b9597af1..56e9a5dc73 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
@@ -25,8 +25,6 @@ import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
import javax.jms.JMSException;
import javax.jms.MessageFormatException;
@@ -35,8 +33,6 @@ import javax.jms.ObjectMessage;
import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessage
{
@@ -157,7 +153,7 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag
}
finally
{
- _data.rewind();
+ // _data.rewind();
close(in);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java
index c290149cef..f83ae6ace0 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java
@@ -100,6 +100,7 @@ public class JMSTextMessage extends AbstractJMSMessage implements javax.jms.Text
if (encoding == null || encoding.equalsIgnoreCase("UTF-8"))
{
_data = ByteBuffer.wrap(Strings.toUTF8(text));
+ setEncoding("UTF-8");
}
else
{
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
index e1275c37f7..f3d96cd855 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
@@ -27,7 +27,8 @@ import javax.jms.JMSException;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.transport.Struct;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.MessageProperties;
public interface MessageFactory
@@ -39,7 +40,8 @@ public interface MessageFactory
throws JMSException, AMQException;
AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered,
- Struct[] contentHeader,
+ MessageProperties msgProps,
+ DeliveryProperties deliveryProps,
java.nio.ByteBuffer body)
throws JMSException, AMQException;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java b/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
index 948d6d0d7d..a7d41e2cde 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
@@ -48,6 +48,7 @@ public class MessageFactoryRegistry
private final Map<String, MessageFactory> _mimeStringToFactoryMap = new HashMap<String, MessageFactory>();
private final Map<AMQShortString, MessageFactory> _mimeShortStringToFactoryMap =
new HashMap<AMQShortString, MessageFactory>();
+ private final MessageFactory _default = new JMSBytesMessageFactory();
/**
* Construct a new registry with the default message factories registered
@@ -63,7 +64,7 @@ public class MessageFactoryRegistry
mf.registerFactory(JMSBytesMessage.MIME_TYPE, new JMSBytesMessageFactory());
mf.registerFactory(JMSObjectMessage.MIME_TYPE, new JMSObjectMessageFactory());
mf.registerFactory(JMSStreamMessage.MIME_TYPE, new JMSStreamMessageFactory());
- mf.registerFactory(null, new JMSBytesMessageFactory());
+ mf.registerFactory(null, mf._default);
return mf;
}
@@ -113,39 +114,43 @@ public class MessageFactoryRegistry
MessageFactory mf = _mimeShortStringToFactoryMap.get(contentTypeShortString);
if (mf == null)
{
- throw new AMQException(null, "Unsupport MIME type of " + properties.getContentTypeAsString(), null);
- }
- else
- {
- return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies);
+ mf = _default;
}
+
+ return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies);
}
public AbstractJMSMessage createMessage(MessageTransfer transfer) throws AMQException, JMSException
{
MessageProperties mprop = transfer.getHeader().get(MessageProperties.class);
- String messageType = mprop.getContentType();
- if (messageType == null)
+ String messageType = "";
+ if ( mprop == null || mprop.getContentType() == null)
{
_logger.debug("no message type specified, building a byte message");
messageType = JMSBytesMessage.MIME_TYPE;
}
+ else
+ {
+ messageType = mprop.getContentType();
+ }
MessageFactory mf = _mimeStringToFactoryMap.get(messageType);
if (mf == null)
{
- throw new AMQException(null, "Unsupport MIME type of " + messageType, null);
+ mf = _default;
}
- else
+
+ boolean redelivered = false;
+ DeliveryProperties deliverProps;
+ if((deliverProps = transfer.getHeader().get(DeliveryProperties.class)) != null)
{
- boolean redelivered = false;
- DeliveryProperties deliverProps;
- if((deliverProps = transfer.getHeader().get(DeliveryProperties.class)) != null)
- {
- redelivered = deliverProps.getRedelivered();
- }
- return mf.createMessage(transfer.getId(), redelivered, transfer.getHeader().getStructs(), transfer.getBody());
+ redelivered = deliverProps.getRedelivered();
}
+ return mf.createMessage(transfer.getId(),
+ redelivered,
+ mprop == null? new MessageProperties():mprop,
+ deliverProps == null? new DeliveryProperties():deliverProps,
+ transfer.getBody());
}
@@ -159,11 +164,9 @@ public class MessageFactoryRegistry
MessageFactory mf = _mimeStringToFactoryMap.get(mimeType);
if (mf == null)
{
- throw new AMQException(null, "Unsupport MIME type of " + mimeType, null);
- }
- else
- {
- return mf.createMessage(delegateFactory);
+ mf = _default;
}
+
+ return mf.createMessage(delegateFactory);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java
index ed590772d9..6e5f33a65c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java
@@ -1,4 +1,25 @@
package org.apache.qpid.client.message;
+/*
+ *
+ * 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.
+ *
+ */
+
import org.apache.qpid.framing.AMQShortString;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java
index 713c87260c..e2cb36a030 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java
@@ -20,6 +20,7 @@
*/
package org.apache.qpid.client.message;
+import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.BasicMessageConsumer;
@@ -30,7 +31,7 @@ import org.apache.qpid.client.BasicMessageConsumer;
* Note that the actual work of creating a JMS message for the client code's use is done outside of the MINA dispatcher
* thread in order to minimise the amount of work done in the MINA dispatcher thread.
*/
-public abstract class UnprocessedMessage
+public abstract class UnprocessedMessage implements AMQSession.Dispatchable
{
private final int _consumerTag;
@@ -49,5 +50,9 @@ public abstract class UnprocessedMessage
return _consumerTag;
}
+ public void dispatch(AMQSession ssn)
+ {
+ ssn.dispatch(this);
+ }
} \ No newline at end of file
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java
index 6b1301a33f..f31bc88509 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java
@@ -33,9 +33,9 @@ public class UnprocessedMessage_0_10 extends UnprocessedMessage
{
private MessageTransfer _transfer;
- public UnprocessedMessage_0_10(int consumerTag, MessageTransfer xfr)
+ public UnprocessedMessage_0_10(MessageTransfer xfr)
{
- super(consumerTag);
+ super(Integer.parseInt(xfr.getDestination()));
_transfer = xfr;
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java
deleted file mode 100644
index 1de0e7bdfc..0000000000
--- a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package org.apache.qpid.client.protocol;
-
-import java.util.UUID;
-
-import javax.security.sasl.SaslClient;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.mina.common.IdleStatus;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.ConnectionTuneParameters;
-import org.apache.qpid.client.handler.ClientMethodDispatcherImpl;
-import org.apache.qpid.client.state.AMQState;
-import org.apache.qpid.framing.AMQDataBlock;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ProtocolInitiation;
-import org.apache.qpid.framing.ProtocolVersion;
-import org.apache.qpid.transport.Sender;
-
-public class AMQIoTransportProtocolSession extends AMQProtocolSession
-{
-
- protected Sender<java.nio.ByteBuffer> _ioSender;
- private SaslClient _saslClient;
- private ConnectionTuneParameters _connectionTuneParameters;
-
- public AMQIoTransportProtocolSession(AMQProtocolHandler protocolHandler, AMQConnection connection)
- {
- super(protocolHandler, connection);
- }
-
- @Override
- public void closeProtocolSession(boolean waitLast) throws AMQException
- {
- _ioSender.close();
- _protocolHandler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
- }
-
- @Override
- public void init()
- {
- _ioSender.send(new ProtocolInitiation(_connection.getProtocolVersion()).toNioByteBuffer());
- _ioSender.flush();
- }
-
- @Override
- protected AMQShortString generateQueueName()
- {
- int id;
- synchronized (_queueIdLock)
- {
- id = _queueId++;
- }
- return new AMQShortString("tmp_" + UUID.randomUUID() + "_" + id);
- }
-
- @Override
- public AMQConnection getAMQConnection()
- {
- return _connection;
- }
-
- @Override
- public SaslClient getSaslClient()
- {
- return _saslClient;
- }
-
- @Override
- public void setSaslClient(SaslClient client)
- {
- _saslClient = client;
- }
-
- /** @param delay delay in seconds (not ms) */
- @Override
- void initHeartbeats(int delay)
- {
- if (delay > 0)
- {
- // FIXME: actually do something here
- HeartbeatDiagnostics.init(delay, HeartbeatConfig.CONFIG.getTimeout(delay));
- }
- }
-
- @Override
- public void methodFrameReceived(final int channel, final AMQMethodBody amqMethodBody) throws AMQException
- {
- // FIXME?
- _protocolHandler.methodBodyReceived(channel, amqMethodBody, null);
- }
-
- @Override
- public void writeFrame(AMQDataBlock frame, boolean wait)
- {
- _ioSender.send(frame.toNioByteBuffer());
- if (wait)
- {
- _ioSender.flush();
- }
- }
-
- @Override
- public void setSender(Sender<java.nio.ByteBuffer> sender)
- {
- _ioSender = sender;
- }
-
- @Override
- public ConnectionTuneParameters getConnectionTuneParameters()
- {
- return _connectionTuneParameters;
- }
-
- @Override
- public void setConnectionTuneParameters(ConnectionTuneParameters params)
- {
- _connectionTuneParameters = params;
- AMQConnection con = getAMQConnection();
- con.setMaximumChannelCount(params.getChannelMax());
- con.setMaximumFrameSize(params.getFrameMax());
- initHeartbeats((int) params.getHeartbeat());
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
index e92817f713..a567c2c215 100644
--- a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
@@ -20,24 +20,23 @@
*/
package org.apache.qpid.client.protocol;
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoFilterChain;
-import org.apache.mina.common.IoHandlerAdapter;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.filter.ReadThrottleFilterBuilder;
-import org.apache.mina.filter.SSLFilter;
-import org.apache.mina.filter.WriteBufferLimitFilterBuilder;
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
import org.apache.mina.filter.codec.ProtocolCodecException;
-import org.apache.mina.filter.codec.ProtocolCodecFilter;
-import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.qpid.AMQConnectionClosedException;
import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQTimeoutException;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.SSLConfiguration;
-import org.apache.qpid.client.configuration.ClientProperties;
import org.apache.qpid.client.failover.FailoverException;
import org.apache.qpid.client.failover.FailoverHandler;
import org.apache.qpid.client.failover.FailoverState;
@@ -46,23 +45,29 @@ import org.apache.qpid.client.state.AMQStateManager;
import org.apache.qpid.client.state.StateWaiter;
import org.apache.qpid.client.state.listener.SpecificMethodFrameListener;
import org.apache.qpid.codec.AMQCodecFactory;
-import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.AMQBody;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ConnectionCloseOkBody;
+import org.apache.qpid.framing.HeartbeatBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.pool.ReadWriteThreadModel;
+import org.apache.qpid.pool.Job;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.protocol.AMQMethodListener;
-import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.transport.NetworkDriver;
import org.apache.qpid.transport.network.io.IoTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.CountDownLatch;
-
/**
* AMQProtocolHandler is the client side protocol handler for AMQP, it handles all protocol events received from the
* network by MINA. The primary purpose of AMQProtocolHandler is to translate the generic event model of MINA into the
@@ -102,17 +107,10 @@ import java.util.concurrent.CountDownLatch;
*
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Create the filter chain to filter this handlers events.
- * <td> {@link ProtocolCodecFilter}, {@link SSLContextFactory}, {@link SSLFilter}, {@link ReadWriteThreadModel}.
- *
* <tr><td> Maintain fail-over state.
* <tr><td>
* </table>
*
- * @todo Explain the system property: amqj.shared_read_write_pool. How does putting the protocol codec filter before the
- * async write filter make it a shared pool? The pooling filter uses the same thread pool for reading and writing
- * anyway, see {@link org.apache.qpid.pool.PoolingFilter}, docs for comments. Will putting the protocol codec
- * filter before it mean not doing the read/write asynchronously but in the main filter thread?
* @todo Use a single handler instance, by shifting everything to do with the 'protocol session' state, including
* failover state, into AMQProtocolSession, and tracking that from AMQConnection? The lifecycles of
* AMQProtocolSesssion and AMQConnection will be the same, so if there is high cohesion between them, they could
@@ -120,13 +118,15 @@ import java.util.concurrent.CountDownLatch;
* held per protocol handler, per protocol session, per network connection, per channel, in seperate classes, so
* that lifecycles of the fields match lifecycles of their containing objects.
*/
-public class AMQProtocolHandler extends IoHandlerAdapter
+public class AMQProtocolHandler implements ProtocolEngine
{
/** Used for debugging. */
private static final Logger _logger = LoggerFactory.getLogger(AMQProtocolHandler.class);
private static final Logger _protocolLogger = LoggerFactory.getLogger("qpid.protocol");
private static final boolean PROTOCOL_DEBUG = (System.getProperty("amqj.protocol.logging.level") != null);
+ private static final long MAXIMUM_STATE_WAIT_TIME = Long.parseLong(System.getProperty("amqj.MaximumStateWait", "30000"));
+
/**
* The connection that this protocol handler is associated with. There is a 1-1 mapping between connection
* instances and protocol handler instances.
@@ -137,7 +137,7 @@ public class AMQProtocolHandler extends IoHandlerAdapter
private volatile AMQProtocolSession _protocolSession;
/** Holds the state of the protocol session. */
- private AMQStateManager _stateManager = new AMQStateManager();
+ private AMQStateManager _stateManager;
/** Holds the method listeners, */
private final CopyOnWriteArraySet<AMQMethodListener> _frameListeners = new CopyOnWriteArraySet<AMQMethodListener>();
@@ -162,7 +162,19 @@ public class AMQProtocolHandler extends IoHandlerAdapter
private FailoverException _lastFailoverException;
/** Defines the default timeout to use for synchronous protocol commands. */
- private final long DEFAULT_SYNC_TIMEOUT = 1000 * 30;
+ private final long DEFAULT_SYNC_TIMEOUT = Long.getLong("amqj.default_syncwrite_timeout", 1000 * 30);
+
+ /** Object to lock on when changing the latch */
+ private Object _failoverLatchChange = new Object();
+ private AMQCodecFactory _codecFactory;
+ private Job _readJob;
+ private Job _writeJob;
+ private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance();
+ private NetworkDriver _networkDriver;
+ private ProtocolVersion _suggestedProtocolVersion;
+
+ private long _writtenBytes;
+ private long _readBytes;
/**
* Creates a new protocol handler, associated with the specified client connection instance.
@@ -172,101 +184,30 @@ public class AMQProtocolHandler extends IoHandlerAdapter
public AMQProtocolHandler(AMQConnection con)
{
_connection = con;
- }
-
- /**
- * Invoked by MINA when a MINA session for a new connection is created. This method sets up the filter chain on the
- * session, which filters the events handled by this handler. The filter chain consists of, handing off events
- * to an asynchronous thread pool, optionally encoding/decoding ssl, encoding/decoding AMQP.
- *
- * @param session The MINA session.
- *
- * @throws Exception Any underlying exceptions are allowed to fall through to MINA.
- */
- public void sessionCreated(IoSession session) throws Exception
- {
- _logger.debug("Protocol session created for session " + System.identityHashCode(session));
- _failoverHandler = new FailoverHandler(this, session);
-
- final ProtocolCodecFilter pcf = new ProtocolCodecFilter(new AMQCodecFactory(false));
-
- if (Boolean.getBoolean("amqj.shared_read_write_pool"))
- {
- session.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf);
- }
- else
- {
- session.getFilterChain().addLast("protocolFilter", pcf);
- }
- // we only add the SSL filter where we have an SSL connection
- if (_connection.getSSLConfiguration() != null)
- {
- SSLConfiguration sslConfig = _connection.getSSLConfiguration();
- SSLContextFactory sslFactory =
- new SSLContextFactory(sslConfig.getKeystorePath(), sslConfig.getKeystorePassword(), sslConfig.getCertType());
- SSLFilter sslFilter = new SSLFilter(sslFactory.buildClientContext());
- sslFilter.setUseClientMode(true);
- session.getFilterChain().addBefore("protocolFilter", "ssl", sslFilter);
- }
-
- try
- {
- ReadWriteThreadModel threadModel = ReadWriteThreadModel.getInstance();
- threadModel.getAsynchronousReadFilter().createNewJobForSession(session);
- threadModel.getAsynchronousWriteFilter().createNewJobForSession(session);
- }
- catch (RuntimeException e)
- {
- _logger.error(e.getMessage(), e);
- }
-
- if (Boolean.getBoolean(ClientProperties.PROTECTIO_PROP_NAME))
- {
- try
- {
- //Add IO Protection Filters
- IoFilterChain chain = session.getFilterChain();
-
- session.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter());
-
- ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder();
- readfilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty(
- ClientProperties.READ_BUFFER_LIMIT_PROP_NAME, ClientProperties.READ_BUFFER_LIMIT_DEFAULT)));
- readfilter.attach(chain);
-
- WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder();
- writefilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty(
- ClientProperties.WRITE_BUFFER_LIMIT_PROP_NAME, ClientProperties.WRITE_BUFFER_LIMIT_DEFAULT)));
- writefilter.attach(chain);
- session.getFilterChain().remove("tempExecutorFilterForFilterBuilder");
-
- _logger.info("Using IO Read/Write Filter Protection");
- }
- catch (Exception e)
- {
- _logger.error("Unable to attach IO Read/Write Filter Protection :" + e.getMessage());
- }
- }
- _protocolSession = new AMQProtocolSession(this, session, _connection);
-
- _stateManager.setProtocolSession(_protocolSession);
-
- _protocolSession.init();
+ _protocolSession = new AMQProtocolSession(this, _connection);
+ _stateManager = new AMQStateManager(_protocolSession);
+ _codecFactory = new AMQCodecFactory(false, _protocolSession);
+ _readJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, true);
+ _writeJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, false);
+ _poolReference.acquireExecutorService();
+ _failoverHandler = new FailoverHandler(this);
}
/**
* Called when we want to create a new IoTransport session
- * @param brokerDetail
+ * @param brokerDetail
*/
public void createIoTransportSession(BrokerDetails brokerDetail)
{
_protocolSession = new AMQProtocolSession(this, _connection);
_stateManager.setProtocolSession(_protocolSession);
IoTransport.connect_0_9(getProtocolSession(),
- brokerDetail.getHost(), brokerDetail.getPort());
+ brokerDetail.getHost(),
+ brokerDetail.getPort(),
+ brokerDetail.useSSL());
_protocolSession.init();
}
-
+
/**
* Called when the network connection is closed. This can happen, either because the client explicitly requested
* that the connection be closed, in which case nothing is done, or because the connection died. In the case
@@ -274,16 +215,10 @@ public class AMQProtocolHandler extends IoHandlerAdapter
* process will be started, provided that it is the clients policy to allow failover, and provided that a failover
* has not already been started or failed.
*
- * <p/>It is important to note that when the connection dies this method may be called or {@link #exceptionCaught}
- * may be called first followed by this method. This depends on whether the client was trying to send data at the
- * time of the failure.
- *
- * @param session The MINA session.
- *
* @todo Clarify: presumably exceptionCaught is called when the client is sending during a connection failure and
* not otherwise? The above comment doesn't make that clear.
*/
- public void sessionClosed(IoSession session)
+ public void closed()
{
if (_connection.isClosed())
{
@@ -322,7 +257,8 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
_logger.debug("sessionClose() not allowed to failover");
_connection.exceptionReceived(new AMQDisconnectedException(
- "Server closed connection and reconnection " + "not permitted.", null));
+ "Server closed connection and reconnection " + "not permitted.",
+ _stateManager.getLastException()));
}
else
{
@@ -337,41 +273,37 @@ public class AMQProtocolHandler extends IoHandlerAdapter
/** See {@link FailoverHandler} to see rationale for separate thread. */
private void startFailoverThread()
{
- Thread failoverThread = new Thread(_failoverHandler);
- failoverThread.setName("Failover");
- // Do not inherit daemon-ness from current thread as this can be a daemon
- // thread such as a AnonymousIoService thread.
- failoverThread.setDaemon(false);
- failoverThread.start();
+ if(!_connection.isClosed())
+ {
+ Thread failoverThread = new Thread(_failoverHandler);
+ failoverThread.setName("Failover");
+ // Do not inherit daemon-ness from current thread as this can be a daemon
+ // thread such as a AnonymousIoService thread.
+ failoverThread.setDaemon(false);
+ failoverThread.start();
+ }
}
- public void sessionIdle(IoSession session, IdleStatus status) throws Exception
+ public void readerIdle()
{
- _logger.debug("Protocol Session [" + this + ":" + session + "] idle: " + status);
- if (IdleStatus.WRITER_IDLE.equals(status))
- {
- // write heartbeat frame:
- _logger.debug("Sent heartbeat");
- session.write(HeartbeatBody.FRAME);
- HeartbeatDiagnostics.sent();
- }
- else if (IdleStatus.READER_IDLE.equals(status))
- {
- // failover:
- HeartbeatDiagnostics.timeout();
- _logger.warn("Timed out while waiting for heartbeat from peer.");
- session.close();
- }
+ _logger.debug("Protocol Session [" + this + "] idle: reader");
+ // failover:
+ HeartbeatDiagnostics.timeout();
+ _logger.warn("Timed out while waiting for heartbeat from peer.");
+ _networkDriver.close();
+ }
+
+ public void writerIdle()
+ {
+ _logger.debug("Protocol Session [" + this + "] idle: reader");
+ writeFrame(HeartbeatBody.FRAME);
+ HeartbeatDiagnostics.sent();
}
/**
- * Invoked when any exception is thrown by a user IoHandler implementation or by MINA. If the cause is an
- * IOException, MINA will close the connection automatically.
- *
- * @param session The MINA session.
- * @param cause The exception that triggered this event.
+ * Invoked when any exception is thrown by the NetworkDriver
*/
- public void exceptionCaught(IoSession session, Throwable cause)
+ public void exception(Throwable cause)
{
if (_failoverState == FailoverState.NOT_STARTED)
{
@@ -379,9 +311,9 @@ public class AMQProtocolHandler extends IoHandlerAdapter
if ((cause instanceof AMQConnectionClosedException) || cause instanceof IOException)
{
_logger.info("Exception caught therefore going to attempt failover: " + cause, cause);
- // this will attemp failover
-
- sessionClosed(session);
+ // this will attempt failover
+ _networkDriver.close();
+ closed();
}
else
{
@@ -428,12 +360,12 @@ public class AMQProtocolHandler extends IoHandlerAdapter
* @param e the exception to propagate
*
* @see #propagateExceptionToFrameListeners
- * @see #propagateExceptionToStateWaiters
*/
public void propagateExceptionToAllWaiters(Exception e)
{
+ getStateManager().error(e);
+
propagateExceptionToFrameListeners(e);
- propagateExceptionToStateWaiters(e);
}
/**
@@ -450,33 +382,20 @@ public class AMQProtocolHandler extends IoHandlerAdapter
*/
public void propagateExceptionToFrameListeners(Exception e)
{
- if (!_frameListeners.isEmpty())
+ synchronized (_frameListeners)
{
- final Iterator it = _frameListeners.iterator();
- while (it.hasNext())
+ if (!_frameListeners.isEmpty())
{
- final AMQMethodListener ml = (AMQMethodListener) it.next();
- ml.error(e);
+ final Iterator it = _frameListeners.iterator();
+ while (it.hasNext())
+ {
+ final AMQMethodListener ml = (AMQMethodListener) it.next();
+ ml.error(e);
+ }
}
}
}
- /**
- * This caters for the case where we only need to propogate an exception to the the state manager to interupt any
- * thing waiting for a state change.
- *
- * Currently (2008-07-15) the state manager is only used during 0-8/0-9 Connection establishement.
- *
- * Normally the state manager would not need to be notified without notifiying the frame listeners so in normal
- * cases {@link #propagateExceptionToAllWaiters} would be the correct choice.
- *
- * @param e the exception to propagate
- */
- public void propagateExceptionToStateWaiters(Exception e)
- {
- getStateManager().error(e);
- }
-
public void notifyFailoverStarting()
{
// Set the last exception in the sync block to ensure the ordering with add.
@@ -499,48 +418,81 @@ public class AMQProtocolHandler extends IoHandlerAdapter
private static int _messageReceivedCount;
- public void messageReceived(IoSession session, Object message) throws Exception
- {
- if (PROTOCOL_DEBUG)
- {
- _protocolLogger.info(String.format("RECV: [%s] %s", this, message));
- }
- if(message instanceof AMQFrame)
+ public void received(ByteBuffer msg)
+ {
+ try
{
- final boolean debug = _logger.isDebugEnabled();
- final long msgNumber = ++_messageReceivedCount;
+ _readBytes += msg.remaining();
+ final ArrayList<AMQDataBlock> dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg);
- if (debug && ((msgNumber % 1000) == 0))
+ Job.fireAsynchEvent(_poolReference.getPool(), _readJob, new Runnable()
{
- _logger.debug("Received " + _messageReceivedCount + " protocol messages");
- }
-
- AMQFrame frame = (AMQFrame) message;
-
- final AMQBody bodyFrame = frame.getBodyFrame();
- HeartbeatDiagnostics.received(bodyFrame instanceof HeartbeatBody);
-
- bodyFrame.handle(frame.getChannel(), _protocolSession);
-
- _connection.bytesReceived(_protocolSession.getIoSession().getReadBytes());
+ public void run()
+ {
+ // Decode buffer
+
+ for (AMQDataBlock message : dataBlocks)
+ {
+
+ try
+ {
+ if (PROTOCOL_DEBUG)
+ {
+ _protocolLogger.info(String.format("RECV: [%s] %s", this, message));
+ }
+
+ if(message instanceof AMQFrame)
+ {
+ final boolean debug = _logger.isDebugEnabled();
+ final long msgNumber = ++_messageReceivedCount;
+
+ if (debug && ((msgNumber % 1000) == 0))
+ {
+ _logger.debug("Received " + _messageReceivedCount + " protocol messages");
+ }
+
+ AMQFrame frame = (AMQFrame) message;
+
+ final AMQBody bodyFrame = frame.getBodyFrame();
+
+ HeartbeatDiagnostics.received(bodyFrame instanceof HeartbeatBody);
+
+ bodyFrame.handle(frame.getChannel(), _protocolSession);
+
+ _connection.bytesReceived(_readBytes);
+ }
+ else if (message instanceof ProtocolInitiation)
+ {
+ // We get here if the server sends a response to our initial protocol header
+ // suggesting an alternate ProtocolVersion; the server will then close the
+ // connection.
+ ProtocolInitiation protocolInit = (ProtocolInitiation) message;
+ _suggestedProtocolVersion = protocolInit.checkVersion();
+
+ // get round a bug in old versions of qpid whereby the connection is not closed
+ _stateManager.changeState(AMQState.CONNECTION_CLOSED);
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.error("Exception processing frame", e);
+ propagateExceptionToFrameListeners(e);
+ exception(e);
+ }
+ }
+ }
+ });
}
- else if (message instanceof ProtocolInitiation)
+ catch (Exception e)
{
- // We get here if the server sends a response to our initial protocol header
- // suggesting an alternate ProtocolVersion; the server will then close the
- // connection.
- ProtocolInitiation protocolInit = (ProtocolInitiation) message;
- ProtocolVersion pv = protocolInit.checkVersion();
- getConnection().setProtocolVersion(pv);
-
- // get round a bug in old versions of qpid whereby the connection is not closed
- _stateManager.changeState(AMQState.CONNECTION_CLOSED);
+ propagateExceptionToFrameListeners(e);
+ exception(e);
}
}
- public void methodBodyReceived(final int channelId, final AMQBody bodyFrame, IoSession session)//, final IoSession session)
+ public void methodBodyReceived(final int channelId, final AMQBody bodyFrame)
throws AMQException
{
@@ -556,18 +508,20 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
boolean wasAnyoneInterested = getStateManager().methodReceived(evt);
- if (!_frameListeners.isEmpty())
+ synchronized (_frameListeners)
{
- //This iterator is safe from the error state as the frame listeners always add before they send so their
- // will be ready and waiting for this response.
- Iterator it = _frameListeners.iterator();
- while (it.hasNext())
+ if (!_frameListeners.isEmpty())
{
- final AMQMethodListener listener = (AMQMethodListener) it.next();
- wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested;
+ //This iterator is safe from the error state as the frame listeners always add before they send so their
+ // will be ready and waiting for this response.
+ Iterator it = _frameListeners.iterator();
+ while (it.hasNext())
+ {
+ final AMQMethodListener listener = (AMQMethodListener) it.next();
+ wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested;
+ }
}
}
-
if (!wasAnyoneInterested)
{
throw new AMQException(null, "AMQMethodEvent " + evt + " was not processed by any listener. Listeners:"
@@ -578,32 +532,13 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
propagateExceptionToFrameListeners(e);
- exceptionCaught(session, e);
+ exception(e);
}
}
private static int _messagesOut;
- public void messageSent(IoSession session, Object message) throws Exception
- {
- if (PROTOCOL_DEBUG)
- {
- _protocolLogger.debug(String.format("SEND: [%s] %s", this, message));
- }
-
- final long sentMessages = _messagesOut++;
-
- final boolean debug = _logger.isDebugEnabled();
-
- if (debug && ((sentMessages % 1000) == 0))
- {
- _logger.debug("Sent " + _messagesOut + " protocol messages");
- }
-
- _connection.bytesSent(session.getWrittenBytes());
- }
-
public StateWaiter createWaiter(Set<AMQState> states) throws AMQException
{
return getStateManager().createWaiter(states);
@@ -617,12 +552,40 @@ public class AMQProtocolHandler extends IoHandlerAdapter
*/
public void writeFrame(AMQDataBlock frame)
{
- _protocolSession.writeFrame(frame);
+ writeFrame(frame, false);
}
public void writeFrame(AMQDataBlock frame, boolean wait)
{
- _protocolSession.writeFrame(frame, wait);
+ final ByteBuffer buf = frame.toNioByteBuffer();
+ _writtenBytes += buf.remaining();
+ Job.fireAsynchEvent(_poolReference.getPool(), _writeJob, new Runnable()
+ {
+ public void run()
+ {
+ _networkDriver.send(buf);
+ }
+ });
+ if (PROTOCOL_DEBUG)
+ {
+ _protocolLogger.debug(String.format("SEND: [%s] %s", this, frame));
+ }
+
+ final long sentMessages = _messagesOut++;
+
+ final boolean debug = _logger.isDebugEnabled();
+
+ if (debug && ((sentMessages % 1000) == 0))
+ {
+ _logger.debug("Sent " + _messagesOut + " protocol messages");
+ }
+
+ _connection.bytesSent(_writtenBytes);
+
+ if (wait)
+ {
+ _networkDriver.flush();
+ }
}
/**
@@ -657,9 +620,30 @@ public class AMQProtocolHandler extends IoHandlerAdapter
throw _lastFailoverException;
}
+ if(_stateManager.getCurrentState() == AMQState.CONNECTION_CLOSED ||
+ _stateManager.getCurrentState() == AMQState.CONNECTION_CLOSING)
+ {
+ Exception e = _stateManager.getLastException();
+ if (e != null)
+ {
+ if (e instanceof AMQException)
+ {
+ AMQException amqe = (AMQException) e;
+
+ throw amqe.cloneForCurrentThread();
+ }
+ else
+ {
+ throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e);
+ }
+ }
+ }
+
_frameListeners.add(listener);
+ //FIXME: At this point here we should check or before add we should check _stateManager is in an open
+ // state so as we don't check we are likely just to time out here as I believe is being seen in QPID-1255
}
- _protocolSession.writeFrame(frame);
+ writeFrame(frame);
return listener.blockForFrame(timeout);
// When control resumes before this line, a reply will have been received
@@ -703,38 +687,42 @@ public class AMQProtocolHandler extends IoHandlerAdapter
*/
public void closeConnection(long timeout) throws AMQException
{
- getStateManager().changeState(AMQState.CONNECTION_CLOSING);
-
ConnectionCloseBody body = _protocolSession.getMethodRegistry().createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(), // replyCode
new AMQShortString("JMS client is closing the connection."), 0, 0);
final AMQFrame frame = body.generateFrame(0);
- try
- {
- syncWrite(frame, ConnectionCloseOkBody.class, timeout);
- _protocolSession.closeProtocolSession();
- }
- catch (AMQTimeoutException e)
- {
- _protocolSession.closeProtocolSession(false);
- }
- catch (FailoverException e)
+ //If the connection is already closed then don't do a syncWrite
+ if (!getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSED))
{
- _logger.debug("FailoverException interrupted connection close, ignoring as connection close anyway.");
+ try
+ {
+ syncWrite(frame, ConnectionCloseOkBody.class, timeout);
+ _networkDriver.close();
+ closed();
+ }
+ catch (AMQTimeoutException e)
+ {
+ closed();
+ }
+ catch (FailoverException e)
+ {
+ _logger.debug("FailoverException interrupted connection close, ignoring as connection close anyway.");
+ }
}
+ _poolReference.releaseExecutorService();
}
/** @return the number of bytes read from this protocol session */
public long getReadBytes()
{
- return _protocolSession.getIoSession().getReadBytes();
+ return _readBytes;
}
/** @return the number of bytes written to this protocol session */
public long getWrittenBytes()
{
- return _protocolSession.getIoSession().getWrittenBytes();
+ return _writtenBytes;
}
public void failover(String host, int port)
@@ -747,9 +735,15 @@ public class AMQProtocolHandler extends IoHandlerAdapter
public void blockUntilNotFailingOver() throws InterruptedException
{
- if (_failoverLatch != null)
+ synchronized(_failoverLatchChange)
{
- _failoverLatch.await();
+ if (_failoverLatch != null)
+ {
+ if(!_failoverLatch.await(MAXIMUM_STATE_WAIT_TIME, TimeUnit.MILLISECONDS))
+ {
+
+ }
+ }
}
}
@@ -765,7 +759,10 @@ public class AMQProtocolHandler extends IoHandlerAdapter
public void setFailoverLatch(CountDownLatch failoverLatch)
{
- _failoverLatch = failoverLatch;
+ synchronized (_failoverLatchChange)
+ {
+ _failoverLatch = failoverLatch;
+ }
}
public AMQConnection getConnection()
@@ -781,6 +778,7 @@ public class AMQProtocolHandler extends IoHandlerAdapter
public void setStateManager(AMQStateManager stateManager)
{
_stateManager = stateManager;
+ _stateManager.setProtocolSession(_protocolSession);
}
public AMQProtocolSession getProtocolSession()
@@ -817,4 +815,41 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
return _protocolSession.getProtocolVersion();
}
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _networkDriver.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _networkDriver.getLocalAddress();
+ }
+
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _networkDriver = driver;
+ }
+
+ /** @param delay delay in seconds (not ms) */
+ void initHeartbeats(int delay)
+ {
+ if (delay > 0)
+ {
+ getNetworkDriver().setMaxWriteIdle(delay);
+ getNetworkDriver().setMaxReadIdle(HeartbeatConfig.CONFIG.getTimeout(delay));
+ HeartbeatDiagnostics.init(delay, HeartbeatConfig.CONFIG.getTimeout(delay));
+ }
+ }
+
+ public NetworkDriver getNetworkDriver()
+ {
+ return _networkDriver;
+ }
+
+ public ProtocolVersion getSuggestedProtocolVersion()
+ {
+ return _suggestedProtocolVersion;
+ }
+
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
index 5e12a5e6f8..2d59146b43 100644
--- a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
+++ b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
@@ -20,11 +20,6 @@
*/
package org.apache.qpid.client.protocol;
-import org.apache.commons.lang.StringUtils;
-import org.apache.mina.common.CloseFuture;
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.common.WriteFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,6 +28,7 @@ import javax.security.sasl.SaslClient;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import org.apache.commons.lang.StringUtils;
import org.apache.qpid.AMQException;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQSession;
@@ -65,10 +61,6 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
protected static final String SASL_CLIENT = "SASLClient";
- protected final IoSession _minaProtocolSession;
-
- protected WriteFuture _lastWriteFuture;
-
/**
* The handler from which this session was created and which is used to handle protocol events. We send failover
* events to the handler.
@@ -102,28 +94,15 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
protected final AMQConnection _connection;
- private static final int FAST_CHANNEL_ACCESS_MASK = 0xFFFFFFF0;
+ private ConnectionTuneParameters _connectionTuneParameters;
- public AMQProtocolSession(AMQProtocolHandler protocolHandler, IoSession protocolSession, AMQConnection connection)
- {
- _protocolHandler = protocolHandler;
- _minaProtocolSession = protocolSession;
- _minaProtocolSession.setAttachment(this);
- // properties of the connection are made available to the event handlers
- _minaProtocolSession.setAttribute(AMQ_CONNECTION, connection);
- // fixme - real value needed
- _minaProtocolSession.setWriteTimeout(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
- _protocolVersion = connection.getProtocolVersion();
- _methodDispatcher = ClientMethodDispatcherImpl.newMethodDispatcher(ProtocolVersion.getLatestSupportedVersion(),
- this);
- _connection = connection;
+ private SaslClient _saslClient;
- }
+ private static final int FAST_CHANNEL_ACCESS_MASK = 0xFFFFFFF0;
public AMQProtocolSession(AMQProtocolHandler protocolHandler, AMQConnection connection)
{
_protocolHandler = protocolHandler;
- _minaProtocolSession = null;
_protocolVersion = connection.getProtocolVersion();
_methodDispatcher = ClientMethodDispatcherImpl.newMethodDispatcher(ProtocolVersion.getLatestSupportedVersion(),
this);
@@ -134,7 +113,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
{
// start the process of setting up the connection. This is the first place that
// data is written to the server.
- _minaProtocolSession.write(new ProtocolInitiation(_connection.getProtocolVersion()));
+ _protocolHandler.writeFrame(new ProtocolInitiation(_connection.getProtocolVersion()));
}
public String getClientID()
@@ -175,14 +154,9 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
return getAMQConnection().getPassword();
}
- public IoSession getIoSession()
- {
- return _minaProtocolSession;
- }
-
public SaslClient getSaslClient()
{
- return (SaslClient) _minaProtocolSession.getAttribute(SASL_CLIENT);
+ return _saslClient;
}
/**
@@ -192,28 +166,21 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
*/
public void setSaslClient(SaslClient client)
{
- if (client == null)
- {
- _minaProtocolSession.removeAttribute(SASL_CLIENT);
- }
- else
- {
- _minaProtocolSession.setAttribute(SASL_CLIENT, client);
- }
+ _saslClient = client;
}
public ConnectionTuneParameters getConnectionTuneParameters()
{
- return (ConnectionTuneParameters) _minaProtocolSession.getAttribute(CONNECTION_TUNE_PARAMETERS);
+ return _connectionTuneParameters;
}
public void setConnectionTuneParameters(ConnectionTuneParameters params)
{
- _minaProtocolSession.setAttribute(CONNECTION_TUNE_PARAMETERS, params);
+ _connectionTuneParameters = params;
AMQConnection con = getAMQConnection();
con.setMaximumChannelCount(params.getChannelMax());
con.setMaximumFrameSize(params.getFrameMax());
- initHeartbeats((int) params.getHeartbeat());
+ _protocolHandler.initHeartbeats((int) params.getHeartbeat());
}
/**
@@ -225,7 +192,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
* @throws AMQException if this was not expected
*/
public void unprocessedMessageReceived(final int channelId, UnprocessedMessage message) throws AMQException
- {
+ {
if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0)
{
_channelId2UnprocessedMsgArray[channelId] = message;
@@ -335,21 +302,12 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
*/
public void writeFrame(AMQDataBlock frame)
{
- writeFrame(frame, false);
+ _protocolHandler.writeFrame(frame);
}
public void writeFrame(AMQDataBlock frame, boolean wait)
{
- WriteFuture f = _minaProtocolSession.write(frame);
- if (wait)
- {
- // fixme -- time out?
- f.join();
- }
- else
- {
- _lastWriteFuture = f;
- }
+ _protocolHandler.writeFrame(frame, wait);
}
/**
@@ -407,33 +365,12 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
public AMQConnection getAMQConnection()
{
- return (AMQConnection) _minaProtocolSession.getAttribute(AMQ_CONNECTION);
+ return _connection;
}
public void closeProtocolSession() throws AMQException
{
- closeProtocolSession(true);
- }
-
- public void closeProtocolSession(boolean waitLast) throws AMQException
- {
- _logger.debug("Waiting for last write to join.");
- if (waitLast && (_lastWriteFuture != null))
- {
- _lastWriteFuture.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
- }
-
- _logger.debug("Closing protocol session");
-
- final CloseFuture future = _minaProtocolSession.close();
-
- // There is no recovery we can do if the join on the close failes so simply mark the connection CLOSED
- // then wait for the connection to close.
- // ritchiem: Could this release BlockingWaiters to early? The close has been done as much as possible so any
- // error now shouldn't matter.
-
- _protocolHandler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
- future.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
+ _protocolHandler.closeConnection(0);
}
public void failover(String host, int port)
@@ -449,22 +386,11 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
id = _queueId++;
}
// get rid of / and : and ; from address for spec conformance
- String localAddress = StringUtils.replaceChars(_minaProtocolSession.getLocalAddress().toString(), "/;:", "");
+ String localAddress = StringUtils.replaceChars(_protocolHandler.getLocalAddress().toString(), "/;:", "");
return new AMQShortString("tmp_" + localAddress + "_" + id);
}
- /** @param delay delay in seconds (not ms) */
- void initHeartbeats(int delay)
- {
- if (delay > 0)
- {
- _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay);
- _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.CONFIG.getTimeout(delay));
- HeartbeatDiagnostics.init(delay, HeartbeatConfig.CONFIG.getTimeout(delay));
- }
- }
-
public void confirmConsumerCancelled(int channelId, AMQShortString consumerTag)
{
final AMQSession session = getSession(channelId);
@@ -477,9 +403,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
_protocolVersion = pv;
_methodRegistry = MethodRegistry.getMethodRegistry(pv);
_methodDispatcher = ClientMethodDispatcherImpl.newMethodDispatcher(pv, this);
-
- // _registry = MainRegistry.getVersionSpecificRegistry(versionMajor, versionMinor);
- }
+ }
public byte getProtocolMinorVersion()
{
@@ -496,11 +420,6 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
return _protocolVersion;
}
-// public VersionSpecificRegistry getRegistry()
-// {
-// return _registry;
-// }
-
public MethodRegistry getMethodRegistry()
{
return _methodRegistry;
@@ -530,7 +449,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
public void methodFrameReceived(final int channel, final AMQMethodBody amqMethodBody) throws AMQException
{
- _protocolHandler.methodBodyReceived(channel, amqMethodBody, _minaProtocolSession);
+ _protocolHandler.methodBodyReceived(channel, amqMethodBody);
}
public void notifyError(Exception error)
@@ -542,4 +461,11 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
{
// No-op, interface munging
}
+
+
+ @Override
+ public String toString()
+ {
+ return "AMQProtocolSession[" + _connection + ']';
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
index 89ee8337f8..1fcfde3579 100644
--- a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
+++ b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
@@ -18,4 +18,5 @@
#
CallbackHandler.CRAM-MD5-HASHED=org.apache.qpid.client.security.UsernameHashedPasswordCallbackHandler
CallbackHandler.CRAM-MD5=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
+CallbackHandler.AMQPLAIN=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
CallbackHandler.PLAIN=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
diff --git a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java
index 803b34b7fa..2b4261b4b7 100644
--- a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java
+++ b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java
@@ -85,8 +85,19 @@ public class DynamicSaslRegistrar
if (factories.size() > 0)
{
- Security.insertProviderAt(new JCAProvider(factories), 0);
- _logger.debug("Dynamic SASL provider added as a security provider");
+ // Ensure we are used before the defaults
+ if (Security.insertProviderAt(new JCAProvider(factories), 1) == -1)
+ {
+ _logger.error("Unable to load custom SASL providers.");
+ }
+ else
+ {
+ _logger.info("Additional SASL providers successfully registered.");
+ }
+ }
+ else
+ {
+ _logger.warn("No additional SASL providers registered.");
}
}
catch (IOException e)
@@ -185,6 +196,7 @@ public class DynamicSaslRegistrar
continue;
}
+ _logger.debug("Registering class "+ clazz.getName() +" for mechanism "+mechanism);
factoriesToRegister.put(mechanism, (Class<? extends SaslClientFactory>) clazz);
}
catch (Exception ex)
diff --git a/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java b/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java
index 5a2c5ac5c1..828d26ed0d 100644
--- a/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java
+++ b/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
import javax.security.sasl.SaslClientFactory;
import java.security.Provider;
+import java.security.Security;
import java.util.Map;
/**
@@ -49,10 +50,10 @@ public class JCAProvider extends Provider
*/
public JCAProvider(Map<String, Class<? extends SaslClientFactory>> providerMap)
{
- super("AMQSASLProvider", 1.0, "A JCA provider that registers all "
+ super("AMQSASLProvider-Client", 1.0, "A JCA provider that registers all "
+ "AMQ SASL providers that want to be registered");
register(providerMap);
- // Security.addProvider(this);
+// Security.addProvider(this);
}
/**
@@ -64,7 +65,7 @@ public class JCAProvider extends Provider
{
for (Map.Entry<String, Class<? extends SaslClientFactory>> me : providerMap.entrySet())
{
- put("SaslClientFactory." + me.getKey(), me.getValue().getName());
+ put( "SaslClientFactory."+me.getKey(), me.getValue().getName());
log.debug("Registered SASL Client factory for " + me.getKey() + " as " + me.getValue().getName());
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java b/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
index f8645139f2..9c7d62670c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
+++ b/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
@@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.io.IOException;
/**
* The state manager is responsible for managing the state of the protocol session. <p/>
@@ -86,7 +87,7 @@ public class AMQStateManager implements AMQMethodListener
return _currentState;
}
- public void changeState(AMQState newState) throws AMQException
+ public void changeState(AMQState newState)
{
_logger.debug("State changing to " + newState + " from old state " + _currentState);
@@ -136,6 +137,22 @@ public class AMQStateManager implements AMQMethodListener
*/
public void error(Exception error)
{
+ if (error instanceof AMQException)
+ {
+ // AMQException should be being notified before closing the
+ // ProtocolSession. Which will change the State to CLOSED.
+ // if we have a hard error.
+ if (((AMQException)error).isHardError())
+ {
+ changeState(AMQState.CONNECTION_CLOSING);
+ }
+ }
+ else
+ {
+ // Be on the safe side here and mark the connection closed
+ changeState(AMQState.CONNECTION_CLOSED);
+ }
+
if (_waiters.size() == 0)
{
_logger.error("No Waiters for error saving as last error:" + error.getMessage());
@@ -196,4 +213,9 @@ public class AMQStateManager implements AMQMethodListener
{
return _lastException;
}
+
+ public void clearLastException()
+ {
+ _lastException = null;
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java b/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java
index 4695b195d5..79f438d35d 100644
--- a/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java
+++ b/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java
@@ -113,7 +113,6 @@ public class StateWaiter extends BlockingWaiter<AMQState>
{
_logger.error("Failover occured whilst waiting for states:" + _awaitStates);
- e.printStackTrace();
return null;
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java b/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java
index b2f7ae8395..1ac8f62e32 100644
--- a/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java
+++ b/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java
@@ -20,27 +20,20 @@
*/
package org.apache.qpid.client.transport;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
import org.apache.mina.common.ByteBuffer;
-import org.apache.mina.common.ConnectFuture;
import org.apache.mina.common.IoConnector;
import org.apache.mina.common.SimpleByteBufferAllocator;
-import org.apache.mina.transport.socket.nio.ExistingSocketConnector;
-import org.apache.mina.transport.socket.nio.SocketConnectorConfig;
-import org.apache.mina.transport.socket.nio.SocketSessionConfig;
-
+import org.apache.qpid.client.SSLConfiguration;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.pool.ReadWriteThreadModel;
-
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.transport.network.mina.MINANetworkDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
public class SocketTransportConnection implements ITransportConnection
{
private static final Logger _logger = LoggerFactory.getLogger(SocketTransportConnection.class);
@@ -71,61 +64,27 @@ public class SocketTransportConnection implements ITransportConnection
}
final IoConnector ioConnector = _socketConnectorFactory.newSocketConnector();
- SocketConnectorConfig cfg = (SocketConnectorConfig) ioConnector.getDefaultConfig();
-
- // if we do not use our own thread model we get the MINA default which is to use
- // its own leader-follower model
- boolean readWriteThreading = Boolean.getBoolean("amqj.shared_read_write_pool");
- if (readWriteThreading)
- {
- cfg.setThreadModel(ReadWriteThreadModel.getInstance());
- }
-
- SocketSessionConfig scfg = (SocketSessionConfig) cfg.getSessionConfig();
- scfg.setTcpNoDelay("true".equalsIgnoreCase(System.getProperty("amqj.tcpNoDelay", "true")));
- scfg.setSendBufferSize(Integer.getInteger("amqj.sendBufferSize", DEFAULT_BUFFER_SIZE));
- _logger.info("send-buffer-size = " + scfg.getSendBufferSize());
- scfg.setReceiveBufferSize(Integer.getInteger("amqj.receiveBufferSize", DEFAULT_BUFFER_SIZE));
- _logger.info("recv-buffer-size = " + scfg.getReceiveBufferSize());
-
final InetSocketAddress address;
if (brokerDetail.getTransport().equals(BrokerDetails.SOCKET))
{
address = null;
-
- Socket socket = TransportConnection.removeOpenSocket(brokerDetail.getHost());
-
- if (socket != null)
- {
- _logger.info("Using existing Socket:" + socket);
-
- ((ExistingSocketConnector) ioConnector).setOpenSocket(socket);
- }
- else
- {
- throw new IllegalArgumentException("Active Socket must be provided for broker " +
- "with 'socket://<SocketID>' transport:" + brokerDetail);
- }
}
else
{
address = new InetSocketAddress(brokerDetail.getHost(), brokerDetail.getPort());
_logger.info("Attempting connection to " + address);
}
-
-
- ConnectFuture future = ioConnector.connect(address, protocolHandler);
-
- // wait for connection to complete
- if (future.join(brokerDetail.getTimeout()))
- {
- // we call getSession which throws an IOException if there has been an error connecting
- future.getSession();
- }
- else
+
+ SSLConfiguration sslConfig = protocolHandler.getConnection().getSSLConfiguration();
+ SSLContextFactory sslFactory = null;
+ if (sslConfig != null)
{
- throw new IOException("Timeout waiting for connection.");
+ sslFactory = new SSLContextFactory(sslConfig.getKeystorePath(), sslConfig.getKeystorePassword(), sslConfig.getCertType());
}
+
+ MINANetworkDriver driver = new MINANetworkDriver(ioConnector);
+ driver.open(brokerDetail.getPort(), address.getAddress(), protocolHandler, null, sslFactory);
+ protocolHandler.setNetworkDriver(driver);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java b/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java
index 6c12821c74..a4f8bb0166 100644
--- a/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java
+++ b/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java
@@ -20,6 +20,12 @@
*/
package org.apache.qpid.client.transport;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.mina.common.IoConnector;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoServiceConfig;
@@ -30,16 +36,12 @@ import org.apache.mina.transport.vmpipe.VmPipeAcceptor;
import org.apache.mina.transport.vmpipe.VmPipeAddress;
import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException;
import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.pool.ReadWriteThreadModel;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.thread.QpidThreadExecutor;
+import org.apache.qpid.transport.network.mina.MINANetworkDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.net.Socket;
-
/**
* The TransportConnection is a helper class responsible for connecting to an AMQ server. It sets up the underlying
* connector, which currently always uses TCP/IP sockets. It creates the "protocol handler" which deals with MINA
@@ -61,7 +63,7 @@ public class TransportConnection
private static Logger _logger = LoggerFactory.getLogger(TransportConnection.class);
- private static final String DEFAULT_QPID_SERVER = "org.apache.qpid.server.protocol.AMQPFastProtocolHandler";
+ private static final String DEFAULT_QPID_SERVER = "org.apache.qpid.server.protocol.AMQProtocolEngineFactory";
private static Map<String, Socket> _openSocketRegister = new ConcurrentHashMap<String, Socket>();
@@ -75,7 +77,7 @@ public class TransportConnection
return _openSocketRegister.remove(socketID);
}
- public static synchronized ITransportConnection getInstance(BrokerDetails details) throws AMQTransportConnectionException
+ public static synchronized ITransportConnection getInstance(final BrokerDetails details) throws AMQTransportConnectionException
{
int transport = getTransport(details.getTransport());
@@ -91,7 +93,22 @@ public class TransportConnection
{
public IoConnector newSocketConnector()
{
- return new ExistingSocketConnector();
+ ExistingSocketConnector connector = new ExistingSocketConnector(1,new QpidThreadExecutor());
+
+ Socket socket = TransportConnection.removeOpenSocket(details.getHost());
+
+ if (socket != null)
+ {
+ _logger.info("Using existing Socket:" + socket);
+
+ ((ExistingSocketConnector) connector).setOpenSocket(socket);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Active Socket must be provided for broker " +
+ "with 'socket://<SocketID>' transport:" + details);
+ }
+ return connector;
}
});
case TCP:
@@ -106,12 +123,12 @@ public class TransportConnection
_logger.warn("Using Qpid MultiThreaded NIO - " + (System.getProperties().containsKey("qpidnio")
? "Qpid NIO is new default"
: "Sysproperty 'qpidnio' is set"));
- result = new MultiThreadSocketConnector();
+ result = new MultiThreadSocketConnector(1, new QpidThreadExecutor());
}
else
{
_logger.info("Using Mina NIO");
- result = new SocketConnector(); // non-blocking connector
+ result = new SocketConnector(1, new QpidThreadExecutor()); // non-blocking connector
}
// Don't have the connector's worker thread wait around for other connections (we only use
// one SocketConnector per connection at the moment anyway). This allows short-running
@@ -189,8 +206,6 @@ public class TransportConnection
_acceptor = new VmPipeAcceptor();
IoServiceConfig config = _acceptor.getDefaultConfig();
-
- config.setThreadModel(ReadWriteThreadModel.getInstance());
}
synchronized (_inVmPipeAddress)
{
@@ -275,7 +290,10 @@ public class TransportConnection
{
Class[] cnstr = {Integer.class};
Object[] params = {port};
- provider = (IoHandlerAdapter) Class.forName(protocolProviderClass).getConstructor(cnstr).newInstance(params);
+
+ provider = new MINANetworkDriver();
+ ProtocolEngineFactory engineFactory = (ProtocolEngineFactory) Class.forName(protocolProviderClass).getConstructor(cnstr).newInstance(params);
+ ((MINANetworkDriver) provider).setProtocolEngineFactory(engineFactory, true);
// Give the broker a second to create
_logger.info("Created VMBroker Instance:" + port);
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java b/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java
index dca6efba67..504d475740 100644
--- a/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java
+++ b/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java
@@ -20,25 +20,26 @@
*/
package org.apache.qpid.client.transport;
+import java.io.IOException;
+
import org.apache.mina.common.ConnectFuture;
-import org.apache.mina.common.IoServiceConfig;
import org.apache.mina.transport.vmpipe.QpidVmPipeConnector;
import org.apache.mina.transport.vmpipe.VmPipeAddress;
import org.apache.mina.transport.vmpipe.VmPipeConnector;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.pool.ReadWriteThreadModel;
+import org.apache.qpid.transport.network.mina.MINANetworkDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-
public class VmPipeTransportConnection implements ITransportConnection
{
private static final Logger _logger = LoggerFactory.getLogger(VmPipeTransportConnection.class);
private static int _port;
+ private MINANetworkDriver _networkDriver;
+
public VmPipeTransportConnection(int port)
{
_port = port;
@@ -47,16 +48,16 @@ public class VmPipeTransportConnection implements ITransportConnection
public void connect(AMQProtocolHandler protocolHandler, BrokerDetails brokerDetail) throws IOException
{
final VmPipeConnector ioConnector = new QpidVmPipeConnector();
- final IoServiceConfig cfg = ioConnector.getDefaultConfig();
-
- cfg.setThreadModel(ReadWriteThreadModel.getInstance());
final VmPipeAddress address = new VmPipeAddress(_port);
_logger.info("Attempting connection to " + address);
- ConnectFuture future = ioConnector.connect(address, protocolHandler);
+ _networkDriver = new MINANetworkDriver(ioConnector, protocolHandler);
+ protocolHandler.setNetworkDriver(_networkDriver);
+ ConnectFuture future = ioConnector.connect(address, _networkDriver);
// wait for connection to complete
future.join();
// we call getSession which throws an IOException if there has been an error connecting
future.getSession();
+ _networkDriver.setProtocolEngine(protocolHandler);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/url/URLParser.java b/java/client/src/main/java/org/apache/qpid/client/url/URLParser.java
index b975713ad7..f3f74dd332 100644
--- a/java/client/src/main/java/org/apache/qpid/client/url/URLParser.java
+++ b/java/client/src/main/java/org/apache/qpid/client/url/URLParser.java
@@ -1,4 +1,25 @@
package org.apache.qpid.client.url;
+/*
+ *
+ * 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.
+ *
+ */
+
import java.net.URI;
import java.net.URISyntaxException;
@@ -37,22 +58,31 @@ public class URLParser
if ((connection.getHost() == null) || connection.getHost().equals(""))
{
- String uid = AMQConnectionFactory.getUniqueClientID();
- if (uid == null)
- {
- throw URLHelper.parseError(-1, "Client Name not specified", fullURL);
+ String tmp = connection.getAuthority();
+ // hack to read a clientid such as "my_clientID"
+ if (tmp != null && tmp.indexOf('@') < tmp.length()-1)
+ {
+ _url.setClientName(tmp.substring(tmp.indexOf('@')+1,tmp.length()));
}
else
{
- _url.setClientName(uid);
+ String uid = AMQConnectionFactory.getUniqueClientID();
+ if (uid == null)
+ {
+ throw URLHelper.parseError(-1, "Client Name not specified", fullURL);
+ }
+ else
+ {
+ _url.setClientName(uid);
+ }
}
- }
+ }
else
{
_url.setClientName(connection.getHost());
}
-
+
String userInfo = connection.getUserInfo();
if (userInfo == null)
diff --git a/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java b/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
index 67cda957fb..a3d015eadc 100644
--- a/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
+++ b/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
@@ -253,7 +253,7 @@ public abstract class BlockingWaiter<T>
}
else
{
- System.err.println("WARNING: new error arrived while old one not yet processed");
+ System.err.println("WARNING: new error '" + e == null ? "null" : e.getMessage() + "' arrived while old one not yet processed:" + _error.getMessage());
}
try
diff --git a/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java b/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java
index bddbc329ab..ee7fc533a3 100644
--- a/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java
+++ b/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java
@@ -22,10 +22,11 @@ package org.apache.qpid.client.util;
import java.util.Iterator;
import java.util.Queue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* A blocking queue that emits events above a user specified threshold allowing the caller to take action (e.g. flow
* control) to try to prevent the queue growing (much) further. The underlying queue itself is not bounded therefore the
@@ -36,6 +37,8 @@ import java.util.concurrent.ConcurrentLinkedQueue;
*/
public class FlowControllingBlockingQueue
{
+ private static final Logger _logger = LoggerFactory.getLogger(FlowControllingBlockingQueue.class);
+
/** This queue is bounded and is used to store messages before being dispatched to the consumer */
private final Queue _queue = new ConcurrentLinkedQueue();
@@ -46,6 +49,8 @@ public class FlowControllingBlockingQueue
/** We require a separate count so we can track whether we have reached the threshold */
private int _count;
+
+ private boolean disableFlowControl;
public boolean isEmpty()
{
@@ -69,6 +74,10 @@ public class FlowControllingBlockingQueue
_flowControlHighThreshold = highThreshold;
_flowControlLowThreshold = lowThreshold;
_listener = listener;
+ if (highThreshold == 0)
+ {
+ disableFlowControl = true;
+ }
}
public Object take() throws InterruptedException
@@ -84,7 +93,7 @@ public class FlowControllingBlockingQueue
}
}
}
- if (_listener != null)
+ if (!disableFlowControl && _listener != null)
{
synchronized (_listener)
{
@@ -93,6 +102,7 @@ public class FlowControllingBlockingQueue
_listener.underThreshold(_count);
}
}
+
}
return o;
@@ -106,7 +116,7 @@ public class FlowControllingBlockingQueue
notifyAll();
}
- if (_listener != null)
+ if (!disableFlowControl && _listener != null)
{
synchronized (_listener)
{
diff --git a/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java b/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java
index 2c05f5ce0f..09152f7f1b 100644
--- a/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java
+++ b/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java
@@ -204,6 +204,24 @@ public class PropertyExpression implements Expression
}
}
});
+
+ JMS_PROPERTY_EXPRESSIONS.put("JMSMessageID", new Expression()
+ {
+ public Object evaluate(AbstractJMSMessage message)
+ {
+ try
+ {
+ return message.getJMSMessageID();
+ }
+ catch (Exception e)
+ {
+ _logger.warn("Error evaluating property",e);
+
+ return null;
+ }
+
+ }
+ });
}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java b/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
index 0316255b2c..7227ab247c 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
@@ -34,6 +34,8 @@ public interface BrokerDetails
public static final String OPTIONS_RETRY = "retries";
public static final String OPTIONS_CONNECT_TIMEOUT = "connecttimeout";
public static final String OPTIONS_CONNECT_DELAY = "connectdelay";
+ public static final String OPTIONS_IDLE_TIMEOUT = "idle_timeout";
+ public static final String OPTIONS_SASL_MECHS = "sasl_mechs";
public static final int DEFAULT_PORT = 5672;
public static final String SOCKET = "socket";
@@ -55,7 +57,7 @@ public interface BrokerDetails
public static final String VIRTUAL_HOST = "virtualhost";
public static final String CLIENT_ID = "client_id";
public static final String USERNAME = "username";
- public static final String PASSWORD = "password";
+ public static final String PASSWORD = "password";
String getHost();
@@ -94,6 +96,8 @@ public interface BrokerDetails
SSLConfiguration getSSLConfiguration();
void setSSLConfiguration(SSLConfiguration sslConfiguration);
+
+ boolean useSSL();
String toString();
diff --git a/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java b/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
index da8cd4f750..03ab967c36 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
@@ -33,9 +33,11 @@ import java.util.List;
*/
public interface ConnectionURL
{
- public static final String AMQ_SYNC_PERSISTENCE = "sync_persistence";
- public static final String AMQ_MAXPREFETCH = "maxprefetch";
public static final String AMQ_PROTOCOL = "amqp";
+ public static final String OPTIONS_SYNC_PERSISTENCE = "sync_persistence";
+ public static final String OPTIONS_MAXPREFETCH = "maxprefetch";
+ public static final String OPTIONS_SYNC_ACK = "sync_ack";
+ public static final String OPTIONS_SYNC_PUBLISH = "sync_publish";
public static final String OPTIONS_BROKERLIST = "brokerlist";
public static final String OPTIONS_FAILOVER = "failover";
public static final String OPTIONS_FAILOVER_CYCLE = "cyclecount";
diff --git a/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java b/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java
index 8e3ccc3b02..7cdcd32306 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java
@@ -20,9 +20,12 @@
*/
package org.apache.qpid.jms;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.jms.failover.FailoverExchangeMethod;
import org.apache.qpid.jms.failover.FailoverMethod;
import org.apache.qpid.jms.failover.FailoverRoundRobinServers;
import org.apache.qpid.jms.failover.FailoverSingleServer;
+import org.apache.qpid.jms.failover.NoFailover;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,7 +51,7 @@ public class FailoverPolicy
private long _lastMethodTime;
private long _lastFailTime;
- public FailoverPolicy(ConnectionURL connectionDetails)
+ public FailoverPolicy(ConnectionURL connectionDetails, AMQConnection conn)
{
FailoverMethod method;
@@ -88,6 +91,14 @@ public class FailoverPolicy
{
method = new FailoverRoundRobinServers(connectionDetails);
}
+ else if (failoverMethod.equals(FailoverMethod.FAILOVER_EXCHANGE))
+ {
+ method = new FailoverExchangeMethod(connectionDetails, conn);
+ }
+ else if (failoverMethod.equals(FailoverMethod.NO_FAILOVER))
+ {
+ method = new NoFailover(connectionDetails);
+ }
else
{
try
@@ -272,7 +283,7 @@ public class FailoverPolicy
public FailoverMethod getCurrentMethod()
{
- if ((_currentMethod >= 0) && (_currentMethod < (_methods.length - 1)))
+ if ((_currentMethod >= 0) && (_currentMethod < (_methods.length)))
{
return _methods[_currentMethod];
}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java b/java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java
index 80cfa18ec1..1dbe464230 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java
@@ -1,4 +1,25 @@
package org.apache.qpid.jms;
+/*
+ *
+ * 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.
+ *
+ */
+
import org.apache.qpid.AMQException;
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java
new file mode 100644
index 0000000000..960661daea
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java
@@ -0,0 +1,317 @@
+/*
+ *
+ * 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.failover;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQAnyDestination;
+import org.apache.qpid.client.AMQBrokerDetails;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * When using the Failover exchange a single broker is supplied in the URL.
+ * The connection will then connect to the cluster using the above broker details.
+ * Once connected, the membership details of the cluster will be obtained via
+ * subscribing to a queue bound to the failover exchange.
+ *
+ * The failover exchange will provide a list of broker URLs in the format "transport:ip:port"
+ * Out of this list we only select brokers that match the transport of the original
+ * broker supplied in the connection URL.
+ *
+ * Also properties defined for the original broker will be applied to all the brokers selected
+ * from the list.
+ */
+
+public class FailoverExchangeMethod implements FailoverMethod, MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(FailoverExchangeMethod.class);
+
+ /** This is not safe to use until attainConnection is called */
+ private AMQConnection _conn;
+
+ /** Protects the broker list when modifications happens */
+ private Object _brokerListLock = new Object();
+
+ /** The session used to subscribe to failover exchange */
+ private Session _ssn;
+
+ private BrokerDetails _originalBrokerDetail;
+
+ /** The index into the hostDetails array of the broker to which we are connected */
+ private int _currentBrokerIndex = 0;
+
+ /** The broker currently selected **/
+ private BrokerDetails _currentBrokerDetail;
+
+ /** Array of BrokerDetail used to make connections. */
+ private ConnectionURL _connectionDetails;
+
+ /** Denotes the number of failed attempts **/
+ private int _failedAttemps = 0;
+
+ public FailoverExchangeMethod(ConnectionURL connectionDetails, AMQConnection conn)
+ {
+ _connectionDetails = connectionDetails;
+ _originalBrokerDetail = _connectionDetails.getBrokerDetails(0);
+
+ // This is not safe to use until attainConnection is called, as this ref will not initialized fully.
+ // The reason being this constructor is called inside the AMWConnection constructor.
+ // It would be best if we find a way to pass this ref after AMQConnection is fully initialized.
+ _conn = conn;
+ }
+
+ private void subscribeForUpdates() throws JMSException
+ {
+ if (_ssn == null)
+ {
+ _ssn = _conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer cons = _ssn.createConsumer(
+ new AMQAnyDestination(new AMQShortString("amq.failover"),
+ new AMQShortString("amq.failover"),
+ new AMQShortString(""),
+ true,true,null,false,
+ new AMQShortString[0]));
+ cons.setMessageListener(this);
+ }
+ }
+
+ public void onMessage(Message m)
+ {
+ _logger.info("Failover exchange notified cluster membership change");
+
+ String currentBrokerIP = "";
+ try
+ {
+ currentBrokerIP = InetAddress.getByName(_currentBrokerDetail.getHost()).getHostAddress();
+ }
+ catch(Exception e)
+ {
+ _logger.warn("Unable to resolve current broker host name",e);
+ }
+
+ List<BrokerDetails> brokerList = new ArrayList<BrokerDetails>();
+ try
+ {
+ List<String> list = (List<String>)m.getObjectProperty("amq.failover");
+ for (String brokerEntry:list)
+ {
+ String[] urls = brokerEntry.substring(5) .split(",");
+ // Iterate until you find the correct transport
+ // Need to reconsider the logic when the C++ broker supports
+ // SSL URLs.
+ for (String url:urls)
+ {
+ String[] tokens = url.split(":");
+ if (tokens[0].equalsIgnoreCase(_originalBrokerDetail.getTransport()))
+ {
+ BrokerDetails broker = new AMQBrokerDetails();
+ broker.setTransport(tokens[0]);
+ broker.setHost(tokens[1]);
+ broker.setPort(Integer.parseInt(tokens[2]));
+ broker.setProperties(_originalBrokerDetail.getProperties());
+ broker.setSSLConfiguration(_originalBrokerDetail.getSSLConfiguration());
+ brokerList.add(broker);
+
+ if (currentBrokerIP.equals(broker.getHost()) &&
+ _currentBrokerDetail.getPort() == broker.getPort())
+ {
+ _currentBrokerIndex = brokerList.indexOf(broker);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ catch(JMSException e)
+ {
+ _logger.error("Error parsing the message sent by failover exchange",e);
+ }
+
+ synchronized (_brokerListLock)
+ {
+ _connectionDetails.setBrokerDetails(brokerList);
+ }
+
+ _logger.info("============================================================");
+ _logger.info("Updated cluster membership details " + _connectionDetails);
+ _logger.info("============================================================");
+ }
+
+ public void attainedConnection()
+ {
+ try
+ {
+ _failedAttemps = 0;
+ _logger.info("============================================================");
+ _logger.info("Attained connection ");
+ _logger.info("============================================================");
+ subscribeForUpdates();
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Unable to subscribe for cluster membership updates",e);
+ }
+ }
+
+ public BrokerDetails getCurrentBrokerDetails()
+ {
+ synchronized (_brokerListLock)
+ {
+ _currentBrokerDetail = _connectionDetails.getBrokerDetails(_currentBrokerIndex);
+ return _currentBrokerDetail;
+ }
+ }
+
+ public BrokerDetails getNextBrokerDetails()
+ {
+ synchronized(_brokerListLock)
+ {
+ if (_currentBrokerIndex == (_connectionDetails.getBrokerCount() - 1))
+ {
+ _currentBrokerIndex = 0;
+ }
+ else
+ {
+ _currentBrokerIndex++;
+ }
+
+ BrokerDetails broker = _connectionDetails.getBrokerDetails(_currentBrokerIndex);
+
+ // When the broker list is updated it will include the current broker as well
+ // There is no point trying it again, so trying the next one.
+ if (_currentBrokerDetail != null &&
+ broker.getHost().equals(_currentBrokerDetail.getHost()) &&
+ broker.getPort() == _currentBrokerDetail.getPort())
+ {
+ if (_connectionDetails.getBrokerCount() > 1)
+ {
+ return getNextBrokerDetails();
+ }
+ else
+ {
+ _failedAttemps ++;
+ return null;
+ }
+ }
+
+ String delayStr = broker.getProperty(BrokerDetails.OPTIONS_CONNECT_DELAY);
+ if (delayStr != null)
+ {
+ Long delay = Long.parseLong(delayStr);
+ _logger.info("Delay between connect retries:" + delay);
+ try
+ {
+ Thread.sleep(delay);
+ }
+ catch (InterruptedException ie)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ _logger.info("No delay between connect retries, use tcp://host:port?connectdelay='value' to enable.");
+ }
+
+ _failedAttemps ++;
+ _currentBrokerDetail = broker;
+ return broker;
+ }
+ }
+
+ public boolean failoverAllowed()
+ {
+ // We allow to Failover provided
+ // our broker list is not empty and
+ // we haven't gone through all of them
+
+ boolean b = _connectionDetails.getBrokerCount() > 0 &&
+ _failedAttemps <= _connectionDetails.getBrokerCount();
+
+
+ _logger.info("============================================================");
+ _logger.info(toString());
+ _logger.info("FailoverAllowed " + b);
+ _logger.info("============================================================");
+
+ return b;
+ }
+
+ public void reset()
+ {
+ _failedAttemps = 0;
+ }
+
+ public void setBroker(BrokerDetails broker)
+ {
+ // not sure if this method is needed
+ }
+
+ public void setRetries(int maxRetries)
+ {
+ // no max retries we keep trying as long
+ // as we get updates
+ }
+
+ public String methodName()
+ {
+ return "Failover Exchange";
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("FailoverExchange:\n");
+ sb.append("\n Current Broker Index:");
+ sb.append(_currentBrokerIndex);
+ sb.append("\n Failed Attempts:");
+ sb.append(_failedAttemps);
+ sb.append("\n Orignal broker details:");
+ sb.append(_originalBrokerDetail).append("\n");
+ sb.append("\n -------- Broker List -----------\n");
+ for (int i = 0; i < _connectionDetails.getBrokerCount(); i++)
+ {
+ if (i == _currentBrokerIndex)
+ {
+ sb.append(">");
+ }
+
+ sb.append(_connectionDetails.getBrokerDetails(i));
+ sb.append("\n");
+ }
+ sb.append("--------------------------------\n");
+ return sb.toString();
+ }
+}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java
index d7ec46dea3..1cef067e5f 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java
@@ -27,7 +27,10 @@ public interface FailoverMethod
{
public static final String SINGLE_BROKER = "singlebroker";
public static final String ROUND_ROBIN = "roundrobin";
+ public static final String FAILOVER_EXCHANGE= "failover_exchange";
public static final String RANDOM = "random";
+ public static final String NO_FAILOVER = "nofailover";
+
/**
* Reset the Failover to initial conditions
*/
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java
index 9c172da6a2..41ba4974ec 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java
@@ -30,27 +30,27 @@ public class FailoverRoundRobinServers implements FailoverMethod
private static final Logger _logger = LoggerFactory.getLogger(FailoverRoundRobinServers.class);
/** The default number of times to cycle through all servers */
- public static final int DEFAULT_CYCLE_RETRIES = 0;
+ public static final int DEFAULT_CYCLE_RETRIES = 1;
/** The default number of times to retry each server */
public static final int DEFAULT_SERVER_RETRIES = 0;
/** The index into the hostDetails array of the broker to which we are connected */
- private int _currentBrokerIndex = -1;
+ private int _currentBrokerIndex = 0;
/** The number of times to retry connecting for each server */
private int _serverRetries;
/** The current number of retry attempts made */
- private int _currentServerRetry;
+ private int _currentServerRetry = 0;
/** The number of times to cycle through the servers */
private int _cycleRetries;
/** The current number of cycles performed. */
- private int _currentCycleRetries;
+ private int _currentCycleRetries = 0;
/** Array of BrokerDetail used to make connections. */
- private ConnectionURL _connectionDetails;
+ protected ConnectionURL _connectionDetails;
public FailoverRoundRobinServers(ConnectionURL connectionDetails)
{
@@ -62,10 +62,12 @@ public class FailoverRoundRobinServers implements FailoverMethod
_connectionDetails = connectionDetails;
// There is no current broker at startup so set it to -1.
- _currentBrokerIndex = -1;
+ _currentBrokerIndex = 0;
String cycleRetries = _connectionDetails.getFailoverOption(ConnectionURL.OPTIONS_FAILOVER_CYCLE);
+ _cycleRetries = DEFAULT_CYCLE_RETRIES;
+
if (cycleRetries != null)
{
try
@@ -74,42 +76,39 @@ public class FailoverRoundRobinServers implements FailoverMethod
}
catch (NumberFormatException nfe)
{
- _cycleRetries = DEFAULT_CYCLE_RETRIES;
+ _logger.warn("Cannot set cycle Retries, " + cycleRetries + " is not a number. Using default: " + DEFAULT_CYCLE_RETRIES);
}
}
_currentCycleRetries = 0;
_serverRetries = 0;
- _currentServerRetry = -1;
+ _currentServerRetry = 0;
}
public void reset()
{
_currentBrokerIndex = 0;
_currentCycleRetries = 0;
- _currentServerRetry = -1;
+ _currentServerRetry = 0;
}
public boolean failoverAllowed()
{
- return ((_currentCycleRetries < _cycleRetries) || (_currentServerRetry < _serverRetries)
- || (_currentBrokerIndex < (_connectionDetails.getBrokerCount() - 1)));
+ _logger.info("==== Checking failoverAllowed() ====");
+ _logger.info(toString());
+ _logger.info("====================================");
+ return ((_currentCycleRetries < _cycleRetries) || (_currentServerRetry < _serverRetries));
}
public void attainedConnection()
{
_currentCycleRetries = 0;
- _currentServerRetry = -1;
+ _currentServerRetry = 0;
}
public BrokerDetails getCurrentBrokerDetails()
{
- if (_currentBrokerIndex == -1)
- {
- return null;
- }
-
return _connectionDetails.getBrokerDetails(_currentBrokerIndex);
}
@@ -121,20 +120,8 @@ public class FailoverRoundRobinServers implements FailoverMethod
{
if (_currentServerRetry < _serverRetries)
{
- if (_currentBrokerIndex == -1)
- {
- _currentBrokerIndex = 0;
-
- setBroker(_connectionDetails.getBrokerDetails(_currentBrokerIndex));
-
- _logger.info("First run using " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
- }
- else
- {
- _logger.info("Retrying " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
- doDelay=true;
- }
-
+ _logger.info("Trying " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
+ doDelay= _currentBrokerIndex != 0;
_currentServerRetry++;
}
else
@@ -154,19 +141,8 @@ public class FailoverRoundRobinServers implements FailoverMethod
{
if (_currentServerRetry < _serverRetries)
{
- if (_currentBrokerIndex == -1)
- {
- _currentBrokerIndex = 0;
-
- setBroker(_connectionDetails.getBrokerDetails(_currentBrokerIndex));
-
- _logger.info("First run using " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
- }
- else
- {
- _logger.info("Retrying " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
- doDelay=true;
- }
+ _logger.info("Trying " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
+ doDelay= _currentBrokerIndex != 0;
_currentServerRetry++;
}
@@ -198,7 +174,11 @@ public class FailoverRoundRobinServers implements FailoverMethod
}
else
{
- _logger.info("No delay between connect retries, use tcp://host:port?connectdelay='value' to enable.");
+ // Only display if option not set. Not if deDelay==false.
+ if (delayStr == null)
+ {
+ _logger.info("No delay between connect retries, use tcp://host:port?connectdelay='value' to enable.");
+ }
}
return broker;
@@ -225,7 +205,7 @@ public class FailoverRoundRobinServers implements FailoverMethod
}
}
- _currentServerRetry = -1;
+ _currentServerRetry = 0;
_currentBrokerIndex = index;
}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java
index 9fa006233b..d033a49f5c 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java
@@ -30,16 +30,16 @@ public class FailoverSingleServer implements FailoverMethod
private static final Logger _logger = LoggerFactory.getLogger(FailoverSingleServer.class);
/** The default number of times to rety a conection to this server */
- public static final int DEFAULT_SERVER_RETRIES = 1;
+ public static final int DEFAULT_SERVER_RETRIES = 0;
/** The details of the Single Server */
private BrokerDetails _brokerDetail;
/** The number of times to retry connecting to the sever */
- private int _retries;
+ protected int _retries;
/** The current number of attempts made to the server */
- private int _currentRetries;
+ protected int _currentRetries = 0;
public FailoverSingleServer(ConnectionURL connectionDetails)
@@ -61,7 +61,7 @@ public class FailoverSingleServer implements FailoverMethod
public void reset()
{
- _currentRetries = -1;
+ _currentRetries = 0;
}
public boolean failoverAllowed()
@@ -157,7 +157,7 @@ public class FailoverSingleServer implements FailoverMethod
public String toString()
{
- return "SingleServer:\n" +
+ return methodName()+":\n" +
"Max Retries:" + _retries +
"\nCurrent Retry:" + _currentRetries +
"\n" + _brokerDetail + "\n";
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/NoFailover.java b/java/client/src/main/java/org/apache/qpid/jms/failover/NoFailover.java
new file mode 100644
index 0000000000..1231324397
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/NoFailover.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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.failover;
+
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+
+/**
+ * Extend the Single Server Model to gain retry functionality but once connected do not attempt to failover.
+ */
+public class NoFailover extends FailoverSingleServer
+{
+ private boolean _connected = false;
+
+ public NoFailover(BrokerDetails brokerDetail)
+ {
+ super(brokerDetail);
+ }
+
+ public NoFailover(ConnectionURL connectionDetails)
+ {
+ super(connectionDetails);
+ }
+
+ @Override
+ public void attainedConnection()
+ {
+ _connected=true;
+ _currentRetries = _retries;
+ }
+
+ @Override
+ public String methodName()
+ {
+ return "NoFailover";
+ }
+
+ @Override
+ public String toString()
+ {
+ return super.toString() + (_connected ? "Connection attained." : "Never connected.") + "\n";
+ }
+
+}
diff --git a/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java b/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
index 43ac56dee9..8b702c008f 100644
--- a/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
+++ b/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
@@ -48,6 +48,7 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.url.AMQBindingURL;
import org.apache.qpid.url.BindingURL;
import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -84,9 +85,20 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
Properties p = new Properties();
p.load(new BufferedInputStream(new FileInputStream(file)));
+ Strings.Resolver resolver = new Strings.ChainedResolver
+ (Strings.SYSTEM_RESOLVER, new Strings.PropertiesResolver(p));
- environment.putAll(p);
- System.getProperties().putAll(p);
+ for (Map.Entry me : p.entrySet())
+ {
+ String key = (String) me.getKey();
+ String value = (String) me.getValue();
+ String expanded = Strings.expand(value, resolver);
+ environment.put(key, expanded);
+ if (System.getProperty(key) == null)
+ {
+ System.setProperty(key, expanded);
+ }
+ }
_logger.info("Loaded Context Properties:" + environment.toString());
}
else
@@ -96,7 +108,8 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
}
catch (IOException ioe)
{
- _logger.warn("Unable to load property file specified in Provider_URL:" + environment.get(Context.PROVIDER_URL));
+ _logger.warn("Unable to load property file specified in Provider_URL:" + environment.get(Context.PROVIDER_URL) +"\n" +
+ "Due to:"+ioe.getMessage());
}
createConnectionFactories(data, environment);
@@ -126,7 +139,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
if (key.startsWith(CONNECTION_FACTORY_PREFIX))
{
String jndiName = key.substring(CONNECTION_FACTORY_PREFIX.length());
- ConnectionFactory cf = createFactory(entry.getValue().toString());
+ ConnectionFactory cf = createFactory(entry.getValue().toString().trim());
if (cf != null)
{
data.put(jndiName, cf);
@@ -144,7 +157,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
if (key.startsWith(DESTINATION_PREFIX))
{
String jndiName = key.substring(DESTINATION_PREFIX.length());
- Destination dest = createDestination(entry.getValue().toString());
+ Destination dest = createDestination(entry.getValue().toString().trim());
if (dest != null)
{
data.put(jndiName, dest);
@@ -162,7 +175,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
if (key.startsWith(QUEUE_PREFIX))
{
String jndiName = key.substring(QUEUE_PREFIX.length());
- Queue q = createQueue(entry.getValue().toString());
+ Queue q = createQueue(entry.getValue().toString().trim());
if (q != null)
{
data.put(jndiName, q);
@@ -180,7 +193,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
if (key.startsWith(TOPIC_PREFIX))
{
String jndiName = key.substring(TOPIC_PREFIX.length());
- Topic t = createTopic(entry.getValue().toString());
+ Topic t = createTopic(entry.getValue().toString().trim());
if (t != null)
{
if (_logger.isDebugEnabled())
@@ -283,7 +296,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
int i = 0;
for (String key:keys)
{
- bindings[i] = new AMQShortString(key);
+ bindings[i] = new AMQShortString(key.trim());
i++;
}
// The Destination has a dual nature. If this was used for a producer the key is used
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/Client.java b/java/client/src/main/java/org/apache/qpid/nclient/Client.java
deleted file mode 100644
index af0e724e42..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/Client.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.qpid.nclient;
-
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.apache.qpid.client.url.URLParser_0_10;
-import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.url.QpidURL;
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.QpidException;
-import org.apache.qpid.nclient.impl.ClientSession;
-import org.apache.qpid.nclient.impl.ClientSessionDelegate;
-import org.apache.qpid.transport.Channel;
-import org.apache.qpid.transport.ClientDelegate;
-import org.apache.qpid.transport.Connection;
-import org.apache.qpid.transport.ConnectionClose;
-import org.apache.qpid.transport.ConnectionCloseCode;
-import org.apache.qpid.transport.ConnectionCloseOk;
-import org.apache.qpid.transport.ProtocolHeader;
-import org.apache.qpid.transport.ProtocolVersionException;
-import org.apache.qpid.transport.SessionDelegate;
-import org.apache.qpid.transport.network.io.IoTransport;
-import org.apache.qpid.transport.network.mina.MinaHandler;
-import org.apache.qpid.transport.network.nio.NioHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-public class Client implements org.apache.qpid.nclient.Connection
-{
- private Connection _conn;
- private ClosedListener _closedListner;
- private final Lock _lock = new ReentrantLock();
- private static Logger _logger = LoggerFactory.getLogger(Client.class);
- private Condition closeOk;
- private boolean closed = false;
- private long timeout = 60000;
-
- private ProtocolHeader header = null;
-
- /**
- *
- * @return returns a new connection to the broker.
- */
- public static org.apache.qpid.nclient.Connection createConnection()
- {
- return new Client();
- }
-
- public void connect(String host, int port,String virtualHost,String username, String password) throws QpidException
- {
-
- final Condition negotiationComplete = _lock.newCondition();
- closeOk = _lock.newCondition();
- _lock.lock();
-
- ClientDelegate connectionDelegate = new ClientDelegate()
- {
- private boolean receivedClose = false;
- public SessionDelegate getSessionDelegate()
- {
- return new ClientSessionDelegate();
- }
-
- public void exception(Throwable t)
- {
- if (_closedListner != null)
- {
- _closedListner.onClosed(ErrorCode.CONNECTION_ERROR,ErrorCode.CONNECTION_ERROR.getDesc(),t);
- }
- else
- {
- throw new RuntimeException("connection closed",t);
- }
- }
-
- public void closed()
- {
- if (_closedListner != null && !this.receivedClose)
- {
- _closedListner.onClosed(ErrorCode.CONNECTION_ERROR,ErrorCode.CONNECTION_ERROR.getDesc(),null);
- }
- }
-
- @Override public void connectionCloseOk(Channel context, ConnectionCloseOk struct)
- {
- _lock.lock();
- try
- {
- closed = true;
- this.receivedClose = true;
- closeOk.signalAll();
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- @Override public void connectionClose(Channel context, ConnectionClose connectionClose)
- {
- super.connectionClose(context, connectionClose);
- ErrorCode errorCode = ErrorCode.get(connectionClose.getReplyCode().getValue());
- if (_closedListner == null && errorCode != ErrorCode.NO_ERROR)
- {
- throw new RuntimeException
- (new QpidException("Server closed the connection: Reason " +
- connectionClose.getReplyText(),
- errorCode,
- null));
- }
- else
- {
- _closedListner.onClosed(errorCode, connectionClose.getReplyText(),null);
- }
-
- this.receivedClose = true;
- }
- @Override public void init(Channel ch, ProtocolHeader hdr)
- {
- // TODO: once the merge is done we'll need to update this code
- // for handling 0.8 protocol version type i.e. major=8 and mino
- if (hdr.getMajor() != 0 || hdr.getMinor() != 10)
- {
- Client.this.header = hdr;
- _lock.lock();
- negotiationComplete.signalAll();
- _lock.unlock();
- }
- }
- };
-
- connectionDelegate.setCondition(_lock,negotiationComplete);
- connectionDelegate.setUsername(username);
- connectionDelegate.setPassword(password);
- connectionDelegate.setVirtualHost(virtualHost);
-
- String transport = System.getProperty("transport","io");
- if (transport.equalsIgnoreCase("nio"))
- {
- _logger.info("using NIO Transport");
- _conn = NioHandler.connect(host, port,connectionDelegate);
- }
- else if (transport.equalsIgnoreCase("io"))
- {
- _logger.info("using Plain IO Transport");
- _conn = IoTransport.connect(host, port,connectionDelegate);
- }
- else
- {
- _logger.info("using MINA Transport");
- _conn = MinaHandler.connect(host, port,connectionDelegate);
- // _conn = NativeHandler.connect(host, port,connectionDelegate);
- }
-
- // XXX: hardcoded version numbers
- _conn.send(new ProtocolHeader(1, 0, 10));
-
- try
- {
- negotiationComplete.await(timeout, TimeUnit.MILLISECONDS);
- if (header != null)
- {
- _conn.close();
- throw new ProtocolVersionException(header.getMajor(), header.getMinor());
- }
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- public void connect(String url)throws QpidException
- {
- URLParser_0_10 parser = null;
- try
- {
- parser = new URLParser_0_10(url);
- }
- catch(Exception e)
- {
- throw new QpidException("Error parsing the URL",ErrorCode.UNDEFINED,e);
- }
- List<BrokerDetails> brokers = parser.getAllBrokerDetails();
- BrokerDetails brokerDetail = brokers.get(0);
- connect(brokerDetail.getHost(), brokerDetail.getPort(), brokerDetail.getProperty("virtualhost"),
- brokerDetail.getProperty("username")== null? "guest":brokerDetail.getProperty("username"),
- brokerDetail.getProperty("password")== null? "guest":brokerDetail.getProperty("password"));
- }
-
- /*
- * Until the dust settles with the URL disucssion
- * I am not going to implement this.
- */
- public void connect(QpidURL url) throws QpidException
- {
- throw new UnsupportedOperationException("Not implemented");
- }
-
- /* {
- // temp impl to tests
- BrokerDetails details = url.getAllBrokerDetails().get(0);
- connect(details.getHost(),
- details.getPort(),
- details.getVirtualHost(),
- details.getUserName(),
- details.getPassword());
- }
-*/
-
- public void close() throws QpidException
- {
- Channel ch = _conn.getChannel(0);
- ch.connectionClose(ConnectionCloseCode.NORMAL, "client is closing");
- _lock.lock();
- try
- {
- try
- {
- long start = System.currentTimeMillis();
- long elapsed = 0;
- while (!closed && elapsed < timeout)
- {
- closeOk.await(timeout - elapsed, TimeUnit.MILLISECONDS);
- elapsed = System.currentTimeMillis() - start;
- }
- if(!closed)
- {
- throw new QpidException("Timed out when closing connection", ErrorCode.CONNECTION_ERROR, null);
- }
- }
- catch (InterruptedException e)
- {
- throw new QpidException("Interrupted when closing connection", ErrorCode.CONNECTION_ERROR, null);
- }
- }
- finally
- {
- _lock.unlock();
- }
- _conn.close();
- }
-
- public Session createSession(long expiryInSeconds)
- {
- Channel ch = _conn.getChannel();
- ClientSession ssn = new ClientSession(UUID.randomUUID().toString().getBytes());
- ssn.attach(ch);
- ssn.sessionAttach(ssn.getName());
- ssn.sessionRequestTimeout(expiryInSeconds);
- return ssn;
- }
-
- public DtxSession createDTXSession(int expiryInSeconds)
- {
- ClientSession clientSession = (ClientSession) createSession(expiryInSeconds);
- clientSession.dtxSelect();
- return (DtxSession) clientSession;
- }
-
- public void setClosedListener(ClosedListener closedListner)
- {
-
- _closedListner = closedListner;
- }
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/Connection.java b/java/client/src/main/java/org/apache/qpid/nclient/Connection.java
deleted file mode 100644
index 2d5b50b33a..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/Connection.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.nclient;
-
-import org.apache.qpid.QpidException;
-
-/**
- * This represents a physical connection to a broker.
- */
-public interface Connection
-{
- /**
- * Establish the connection using the given parameters
- *
- * @param host host name
- * @param port port number
- * @param virtualHost the virtual host name
- * @param username user name
- * @param password password
- * @throws QpidException If the communication layer fails to establish the connection.
- */
- public void connect(String host, int port,String virtualHost,String username, String password) throws QpidException;
-
- /**
- * Establish the connection with the broker identified by the URL.
- *
- * @param url Specifies the URL of the broker.
- * @throws QpidException If the communication layer fails to connect with the broker, an exception is thrown.
- */
- public void connect(String url) throws QpidException;
-
- /**
- * Close this connection.
- *
- * @throws QpidException if the communication layer fails to close the connection.
- */
- public void close() throws QpidException;
-
- /**
- * Create a session for this connection.
- * <p> The returned session is suspended
- * (i.e. this session is not attached to an underlying channel)
- *
- * @param expiryInSeconds Expiry time expressed in seconds, if the value is less than
- * or equal to 0 then the session does not expire.
- * @return A newly created (suspended) session.
- */
- public Session createSession(long expiryInSeconds);
-
- /**
- * Create a DtxSession for this connection.
- * <p> A Dtx Session must be used when resources have to be manipulated as
- * part of a global transaction.
- * <p> The retuned DtxSession is suspended
- * (i.e. this session is not attached with an underlying channel)
- *
- * @param expiryInSeconds Expiry time expressed in seconds, if the value is less than or equal
- * to 0 then the session does not expire.
- * @return A newly created (suspended) DtxSession.
- */
- public DtxSession createDTXSession(int expiryInSeconds);
-
- /**
- * If the communication layer detects a serious problem with a connection, it
- * informs the connection's ClosedListener
- *
- * @param exceptionListner The ClosedListener
- */
- public void setClosedListener(ClosedListener exceptionListner);
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/DtxSession.java b/java/client/src/main/java/org/apache/qpid/nclient/DtxSession.java
deleted file mode 100644
index 8a859f2d84..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/DtxSession.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.nclient;
-
-import org.apache.qpid.transport.Future;
-import org.apache.qpid.transport.GetTimeoutResult;
-import org.apache.qpid.transport.Option;
-import org.apache.qpid.transport.RecoverResult;
-import org.apache.qpid.transport.XaResult;
-import org.apache.qpid.transport.Xid;
-
-/**
- * The resources for this session are controlled under the scope of a distributed transaction.
- */
-public interface DtxSession extends Session
-{
-
- /**
- * This method is called when messages should be produced and consumed on behalf a transaction
- * branch identified by xid.
- * possible options are:
- * <ul>
- * <li> {@link Option#JOIN}: Indicate that the start applies to joining a transaction previously seen.
- * <li> {@link Option#RESUME}: Indicate that the start applies to resuming a suspended transaction branch specified.
- * </ul>
- *
- * @param xid Specifies the xid of the transaction branch to be started.
- * @param options Possible options are: {@link Option#JOIN} and {@link Option#RESUME}.
- * @return Confirms to the client that the transaction branch is started or specify the error condition.
- */
- public Future<XaResult> dtxStart(Xid xid, Option... options);
-
- /**
- * This method is called when the work done on behalf of a transaction branch finishes or needs to
- * be suspended.
- * possible options are:
- * <ul>
- * <li> {@link Option#FAIL}: indicates that this portion of work has failed;
- * otherwise this portion of work has
- * completed successfully.
- * <li> {@link Option#SUSPEND}: Indicates that the transaction branch is
- * temporarily suspended in an incomplete state.
- * </ul>
- *
- * @param xid Specifies the xid of the transaction branch to be ended.
- * @param options Available options are: {@link Option#FAIL} and {@link Option#SUSPEND}.
- * @return Confirms to the client that the transaction branch is ended or specifies the error condition.
- */
- public Future<XaResult> dtxEnd(Xid xid, Option... options);
-
- /**
- * Commit the work done on behalf of a transaction branch. This method commits the work associated
- * with xid. Any produced messages are made available and any consumed messages are discarded.
- * The only possible option is:
- * <ul>
- * <li> {@link Option#ONE_PHASE}: When set, one-phase commit optimization is used.
- * </ul>
- *
- * @param xid Specifies the xid of the transaction branch to be committed.
- * @param options Available option is: {@link Option#ONE_PHASE}
- * @return Confirms to the client that the transaction branch is committed or specifies the error condition.
- */
- public Future<XaResult> dtxCommit(Xid xid, Option... options);
-
- /**
- * This method is called to forget about a heuristically completed transaction branch.
- *
- * @param xid Specifies the xid of the transaction branch to be forgotten.
- */
- public void dtxForget(Xid xid, Option ... options);
-
- /**
- * This method obtains the current transaction timeout value in seconds. If set-timeout was not
- * used prior to invoking this method, the return value is the default timeout value; otherwise, the
- * value used in the previous set-timeout call is returned.
- *
- * @param xid Specifies the xid of the transaction branch used for getting the timeout.
- * @return The current transaction timeout value in seconds.
- */
- public Future<GetTimeoutResult> dtxGetTimeout(Xid xid, Option ... options);
-
- /**
- * This method prepares any message produced or consumed on behalf of xid, ready for commitment.
- *
- * @param xid Specifies the xid of the transaction branch to be prepared.
- * @return The status of the prepare operation can be any one of:
- * xa-ok: Normal execution.
- * <p/>
- * xa-rdonly: The transaction branch was read-only and has been committed.
- * <p/>
- * xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
- * reason.
- * <p/>
- * xa-rbtimeout: The work represented by this transaction branch took too long.
- */
- public Future<XaResult> dtxPrepare(Xid xid, Option ... options);
-
- /**
- * This method is called to obtain a list of transaction branches that are in a prepared or
- * heuristically completed state.
- * @return a array of xids to be recovered.
- */
- public Future<RecoverResult> dtxRecover(Option ... options);
-
- /**
- * This method rolls back the work associated with xid. Any produced messages are discarded and
- * any consumed messages are re-queued.
- *
- * @param xid Specifies the xid of the transaction branch to be rolled back.
- * @return Confirms to the client that the transaction branch is rolled back or specifies the error condition.
- */
- public Future<XaResult> dtxRollback(Xid xid, Option ... options);
-
- /**
- * Sets the specified transaction branch timeout value in seconds.
- *
- * @param xid Specifies the xid of the transaction branch for setting the timeout.
- * @param timeout The transaction timeout value in seconds.
- */
- public void dtxSetTimeout(Xid xid, long timeout, Option ... options);
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/JMSTestCase.java b/java/client/src/main/java/org/apache/qpid/nclient/JMSTestCase.java
deleted file mode 100644
index 4e1b9058e6..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/JMSTestCase.java
+++ /dev/null
@@ -1,115 +0,0 @@
- package org.apache.qpid.nclient;
-
-import java.util.Enumeration;
-
-import javax.jms.ExceptionListener;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import javax.jms.Queue;
-import javax.jms.QueueBrowser;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.framing.AMQShortString;
-
-public class JMSTestCase
-{
-
- public static void main(String[] args)
- {
-
- try
- {
- javax.jms.Connection con = new AMQConnection("qpid:password=pass;username=name@tcp:localhost:5672");
- con.start();
-
- javax.jms.Session ssn = con.createSession(false, 1);
-
- javax.jms.Destination dest = new AMQQueue(new AMQShortString("direct"),"test");
- javax.jms.MessageProducer prod = ssn.createProducer(dest);
- QueueBrowser browser = ssn.createBrowser((Queue)dest, "Test = 'test'");
-
- javax.jms.TextMessage msg = ssn.createTextMessage();
- msg.setStringProperty("TEST", "test");
- msg.setText("Should get this");
- prod.send(msg);
-
- javax.jms.TextMessage msg2 = ssn.createTextMessage();
- msg2.setStringProperty("TEST", "test2");
- msg2.setText("Shouldn't get this");
- prod.send(msg2);
-
-
- Enumeration enu = browser.getEnumeration();
- for (;enu.hasMoreElements();)
- {
- System.out.println(enu.nextElement());
- System.out.println("\n");
- }
-
- javax.jms.MessageConsumer cons = ssn.createConsumer(dest, "Test = 'test'");
- javax.jms.TextMessage m = null; // (javax.jms.TextMessage)cons.receive();
- cons.setMessageListener(new MessageListener()
- {
- public void onMessage(Message m)
- {
- javax.jms.TextMessage m2 = (javax.jms.TextMessage)m;
- try
- {
- System.out.println("headers : " + m2.toString());
- System.out.println("m : " + m2.getText());
- System.out.println("\n\n");
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- }
-
- });
-
- con.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- e.printStackTrace();
- }
- });
-
- System.out.println("Waiting");
- while (m == null)
- {
-
- }
-
- System.out.println("Exiting");
-
- /*javax.jms.TextMessage msg = ssn.createTextMessage();
- msg.setText("This is a test message");
- msg.setBooleanProperty("targetMessage", false);
- prod.send(msg);
-
- msg.setBooleanProperty("targetMessage", true);
- prod.send(msg);
-
- javax.jms.TextMessage m = (javax.jms.TextMessage)cons.receiveNoWait();
-
- if (m == null)
- {
- System.out.println("message is null");
- }
- else
- {
- System.out.println("message is not null" + m);
- }*/
-
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- }
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/Session.java b/java/client/src/main/java/org/apache/qpid/nclient/Session.java
deleted file mode 100644
index 0d84394c7c..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/Session.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.nclient;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Map;
-
-import org.apache.qpid.transport.*;
-import org.apache.qpid.api.Message;
-
-/**
- * <p>A session is associated with a connection.
- * When it is created, a session is not associated with an underlying channel.
- * The session is single threaded. </p>
- * <p/>
- * All the Session commands are asynchronous. Synchronous behavior is achieved through invoking the sync method.
- * For example, <code>command1</code> will be synchronously invoked by using the following sequence:
- * <ul>
- * <li> <code>session.command1()</code>
- * <li> <code>session.sync()</code>
- * </ul>
- */
-public interface Session
-{
- public static final short TRANSFER_ACQUIRE_MODE_NO_ACQUIRE = 1;
- public static final short TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE = 0;
- public static final short TRANSFER_CONFIRM_MODE_REQUIRED = 0;
- public static final short TRANSFER_CONFIRM_MODE_NOT_REQUIRED = 1;
- public static final short MESSAGE_FLOW_MODE_CREDIT = 0;
- public static final short MESSAGE_FLOW_MODE_WINDOW = 1;
- public static final short MESSAGE_FLOW_UNIT_MESSAGE = 0;
- public static final short MESSAGE_FLOW_UNIT_BYTE = 1;
- public static final long MESSAGE_FLOW_MAX_BYTES = 0xFFFFFFFF;
- public static final short MESSAGE_REJECT_CODE_GENERIC = 0;
- public static final short MESSAGE_REJECT_CODE_IMMEDIATE_DELIVERY_FAILED = 1;
- public static final short MESSAGE_ACQUIRE_ANY_AVAILABLE_MESSAGE = 0;
- public static final short MESSAGE_ACQUIRE_MESSAGES_IF_ALL_ARE_AVAILABLE = 1;
-
- //------------------------------------------------------
- // Session housekeeping methods
- //------------------------------------------------------
-
- /**
- * Sync method will block the session until all outstanding commands
- * are executed.
- */
- public void sync();
-
- public void close();
-
- public void sessionDetach(byte[] name, Option ... options);
-
- public void sessionRequestTimeout(long expiry, Option ... options);
-
- public byte[] getName();
-
- public void setAutoSync(boolean value);
-
- //------------------------------------------------------
- // Messaging methods
- // Producer
- //------------------------------------------------------
- /**
- * Transfer a message to a specified exchange.
- * <p/>
- * <p>This transfer provides a complete message
- * using a single method. The method is internally mapped to messageTransfer() and headers() followed
- * by data() and endData().
- * <b><i>This method should only be used by small messages.</b></i></p>
- *
- * @param destination The exchange the message is being sent to.
- * @param msg The Message to be sent.
- * @param confirmMode <ul> </li>off ({@link Session#TRANSFER_CONFIRM_MODE_NOT_REQUIRED}): confirmation
- * is not required. Once a message has been transferred in pre-acquire
- * mode (or once acquire has been sent in no-acquire mode) the message is considered
- * transferred.
- * <p/>
- * <li> on ({@link Session#TRANSFER_CONFIRM_MODE_REQUIRED}): an acquired message
- * is not considered transferred until the original
- * transfer is complete. A complete transfer is signaled by execution.complete.
- * </ul>
- * @param acquireMode <ul>
- * <li> no-acquire ({@link Session#TRANSFER_ACQUIRE_MODE_NO_ACQUIRE}): the message
- * must be explicitly acquired.
- * <li> pre-acquire ({@link Session#TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE}): the message is
- * acquired when the transfer starts.
- * </ul>
- * @throws java.io.IOException If transferring a message fails due to some internal communication error, an exception is thrown.
- */
- public void messageTransfer(String destination, Message msg, short confirmMode, short acquireMode)
- throws IOException;
-
-
- /**
- * This command transfers a message between two peers.
- *
- * @param destination Specifies the destination to which the message is to be transferred.
- * @param acceptMode Indicates whether message.accept, session.complete,
- * or nothing at all is required to indicate successful transfer of the message.
- *
- * @param acquireMode Indicates whether or not the transferred message has been acquired.
- */
- public void messageTransfer(String destination, MessageAcceptMode acceptMode, MessageAcquireMode acquireMode,
- Header header, ByteBuffer body, Option ... options);
-
- /**
- * This command transfers a message between two peers.
- *
- * @param destination Specifies the destination to which the message is to be transferred.
- * @param acceptMode Indicates whether message.accept, session.complete,
- * or nothing at all is required to indicate successful transfer of the message.
- *
- * @param acquireMode Indicates whether or not the transferred message has been acquired.
- */
- public void messageTransfer(String destination, MessageAcceptMode acceptMode, MessageAcquireMode acquireMode,
- Header header, byte[] body, Option ... options);
-
- /**
- * This command transfers a message between two peers.
- *
- * @param destination Specifies the destination to which the message is to be transferred.
- * @param acceptMode Indicates whether message.accept, session.complete,
- * or nothing at all is required to indicate successful transfer of the message.
- *
- * @param acquireMode Indicates whether or not the transferred message has been acquired.
- */
- public void messageTransfer(String destination, MessageAcceptMode acceptMode, MessageAcquireMode acquireMode,
- Header header, String body, Option ... options);
-
- //------------------------------------------------------
- // Messaging methods
- // Consumer
- //------------------------------------------------------
-
- /**
- * Associate a message listener with a destination.
- * <p> The destination is bound to a queue, and messages are filtered based
- * on the provider filter map (message filtering is specific to the provider and in some cases might not be handled).
- * <p> The valid options are:
- * <ul>
- * <li>{@link Option#EXCLUSIVE}: <p> Requests exclusive subscription access, so that only this
- * subscription can access the queue.
- * <li>{@link Option#NONE}: <p> This is an empty option, and has no effect.
- * </ul>
- *
- * @param queue The queue that the receiver is receiving messages from.
- * @param destination The destination, or delivery tag, for the subscriber.
- * @param confirmMode <ul> </li>off ({@link Session#TRANSFER_CONFIRM_MODE_NOT_REQUIRED}): confirmation
- * is not required. Once a message has been transferred in pre-acquire
- * mode (or once acquire has been sent in no-acquire mode) the message is considered
- * transferred.
- * <p/>
- * <li> on ({@link Session#TRANSFER_CONFIRM_MODE_REQUIRED}): an acquired message
- * is not considered transferred until the original
- * transfer is complete. A complete transfer is signaled by execution.complete.
- * </ul>
- * @param acquireMode <ul>
- * <li> no-acquire ({@link Session#TRANSFER_ACQUIRE_MODE_NO_ACQUIRE}): the message must
- * be explicitly acquired.
- * <li> pre-acquire ({@link Session#TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE}): the message is
- * acquired when the transfer starts.
- * </ul>
- * @param listener The listener for this destination. To transfer large messages
- * use a {@link org.apache.qpid.nclient.MessagePartListener}.
- * @param options Set of options. Valid options are {{@link Option#EXCLUSIVE}
- * and {@link Option#NONE}.
- * @param filter A set of filters for the subscription. The syntax and semantics of these filters varies
- * according to the provider's implementation.
- */
- public void messageSubscribe(String queue, String destination, short confirmMode, short acquireMode,
- MessagePartListener listener, Map<String, Object> filter, Option... options);
-
- /**
- * This method cancels a consumer. The server will not send any more messages to the specified destination.
- * This does not affect already delivered messages.
- * The client may receive a
- * number of messages in between sending the cancel method and receiving
- * notification that the cancellation has been completed.
- *
- * @param destination The destination to be cancelled.
- */
- public void messageCancel(String destination, Option ... options);
-
- /**
- * Associate a message listener with a destination.
- * <p> Only one listener is permitted for each destination. When a new listener is created,
- * it replaces the previous message listener. To prevent message loss, this occurs only when the original listener
- * has completed processing a message.
- *
- * @param destination The destination the listener is associated with.
- * @param listener The new listener for this destination.
- */
- public void setMessageListener(String destination, MessagePartListener listener);
-
- /**
- * Sets the mode of flow control used for a given destination.
- * <p> With credit based flow control, the broker continually maintains its current
- * credit balance with the recipient. The credit balance consists of two values, a message
- * count, and a byte count. Whenever message data is sent, both counts must be decremented.
- * If either value reaches zero, the flow of message data must stop. Additional credit is
- * received via the {@link Session#messageFlow} method.
- * <p> Window based flow control is identical to credit based flow control, however message
- * acknowledgment implicitly grants a single unit of message credit, and the size of the
- * message in byte credits for each acknowledged message.
- *
- * @param destination The destination to set the flow mode on.
- * @param mode <ul> <li>credit ({@link Session#MESSAGE_FLOW_MODE_CREDIT}): choose credit based flow control
- * <li> window ({@link Session#MESSAGE_FLOW_MODE_WINDOW}): choose window based flow control</ul>
- */
- public void messageSetFlowMode(String destination, MessageFlowMode mode, Option ... options);
-
-
- /**
- * This method controls the flow of message data to a given destination. It is used by the
- * recipient of messages to dynamically match the incoming rate of message flow to its
- * processing or forwarding capacity. Upon receipt of this method, the sender must add "value"
- * number of the specified unit to the available credit balance for the specified destination.
- * A value of 0 indicates an infinite amount of credit. This disables any limit for
- * the given unit until the credit balance is zeroed with {@link Session#messageStop}
- * or {@link Session#messageFlush}.
- *
- * @param destination The destination to set the flow.
- * @param unit Specifies the unit of credit balance.
- * <p/>
- * One of: <ul>
- * <li> message ({@link Session#MESSAGE_FLOW_UNIT_MESSAGE})
- * <li> byte ({@link Session#MESSAGE_FLOW_UNIT_BYTE})
- * </ul>
- * @param value Number of credits, a value of 0 indicates an infinite amount of credit.
- */
- public void messageFlow(String destination, MessageCreditUnit unit, long value, Option ... options);
-
- /**
- * Forces the broker to exhaust its credit supply.
- * <p> The credit on the broker will remain at zero once
- * this method is completed.
- *
- * @param destination The destination on which the credit supply is to be exhausted.
- */
- public void messageFlush(String destination, Option ... options);
-
- /**
- * On receipt of this method, the brokers set credit to zero for a given
- * destination. When confirmation of this method
- * is issued credit is set to zero. No further messages will be sent until
- * further credit is received.
- *
- * @param destination The destination on which to reset credit.
- */
- public void messageStop(String destination, Option ... options);
-
- /**
- * Acknowledge the receipt of a range of messages.
- * <p>Messages must already be acquired, either by receiving them in
- * pre-acquire mode or by explicitly acquiring them.
- *
- * @param ranges Range of messages to be acknowledged.
- * @param accept pecify whether to send a message accept to the broker
- */
- public void messageAcknowledge(RangeSet ranges, boolean accept);
-
- /**
- * Reject a range of acquired messages.
- * <p>The broker will deliver rejected messages to the
- * alternate-exchange on the queue from which it came. If no alternate-exchange is
- * defined for that queue the broker will discard the message.
- *
- * @param ranges Range of messages to be rejected.
- * @param code The reject code must be one of {@link Session#MESSAGE_REJECT_CODE_GENERIC} or
- * {@link Session#MESSAGE_REJECT_CODE_IMMEDIATE_DELIVERY_FAILED} (immediate delivery was attempted but
- * failed).
- * @param text String describing the reason for a message transfer rejection.
- */
- public void messageReject(RangeSet ranges, MessageRejectCode code, String text, Option ... options);
-
- /**
- * As it is possible that the broker does not manage to reject some messages, after completion of
- * {@link Session#messageReject} this method will return the ranges of rejected messages.
- * <p> Note that {@link Session#messageReject} and this methods are asynchronous therefore for accessing to the
- * previously rejected messages this method must be invoked in conjunction with {@link Session#sync()}.
- * <p> A recommended invocation sequence would be:
- * <ul>
- * <li> {@link Session#messageReject}
- * <li> {@link Session#sync()}
- * <li> {@link Session#getRejectedMessages()}
- * </ul>
- *
- * @return The rejected message ranges
- */
- public RangeSet getRejectedMessages();
-
- /**
- * Try to acquire ranges of messages hence releasing them form the queue.
- * This means that once acknowledged, a message will not be delivered to any other receiver.
- * <p> As those messages may have been consumed by another receivers hence,
- * message acquisition can fail.
- * The outcome of the acquisition is returned as an array of ranges of qcquired messages.
- * <p> This method should only be called on non-acquired messages.
- *
- * @param ranges Ranges of messages to be acquired.
- * @return Indicates the acquired messages
- */
- public Future<Acquired> messageAcquire(RangeSet ranges, Option ... options);
-
- /**
- * Give up responsibility for processing ranges of messages.
- * <p> Released messages are re-enqueued.
- *
- * @param ranges Ranges of messages to be released.
- * @param options Valid option is: {@link Option#SET_REDELIVERED})
- */
- public void messageRelease(RangeSet ranges, Option ... options);
-
- // -----------------------------------------------
- // Local transaction methods
- // ----------------------------------------------
- /**
- * Selects the session for local transaction support.
- */
- public void txSelect(Option ... options);
-
- /**
- * Commit the receipt and delivery of all messages exchanged by this session's resources.
- *
- * @throws IllegalStateException If this session is not transacted, an exception will be thrown.
- */
- public void txCommit(Option ... options) throws IllegalStateException;
-
- /**
- * Roll back the receipt and delivery of all messages exchanged by this session's resources.
- *
- * @throws IllegalStateException If this session is not transacted, an exception will be thrown.
- */
- public void txRollback(Option ... options) throws IllegalStateException;
-
- //---------------------------------------------
- // Queue methods
- //---------------------------------------------
-
- /**
- * Declare a queue with the given queueName
- * <p> Following are the valid options:
- * <ul>
- * <li> {@link Option#AUTO_DELETE}: <p> If this field is set and the exclusive field is also set,
- * then the queue is deleted when the connection closes.
- * If this field is set and the exclusive field is not set the queue is deleted when all
- * the consumers have finished using it.
- * <li> {@link Option#DURABLE}: <p> If set when creating a new queue,
- * the queue will be marked as durable. Durable queues
- * remain active when a server restarts. Non-durable queues (transient queues) are purged
- * if/when a server restarts. Note that durable queues do not necessarily hold persistent
- * messages, although it does not make sense to send persistent messages to a transient
- * queue.
- * <li> {@link Option#EXCLUSIVE}: <p> Exclusive queues can only be used from one connection at a time.
- * Once a connection declares an exclusive queue, that queue cannot be used by any other connections until the
- * declaring connection closes.
- * <li> {@link Option#PASSIVE}: <p> If set, the server will not create the queue.
- * This field allows the client to assert the presence of a queue without modifying the server state.
- * <li>{@link Option#NONE}: <p> Has no effect as it represents an empty option.
- * </ul>
- * <p>In the absence of a particular option, the defaul value is false for each option
- *
- * @param queueName The name of the delcared queue.
- * @param alternateExchange If a message is rejected by a queue, then it is sent to the alternate-exchange. A message
- * may be rejected by a queue for the following reasons:
- * <oL> <li> The queue is deleted when it is not empty;
- * <li> Immediate delivery of a message is requested, but there are no consumers connected to
- * the queue. </ol>
- * @param arguments Used for backward compatibility
- * @param options Set of Options ( valide options are: {@link Option#AUTO_DELETE}, {@link Option#DURABLE},
- * {@link Option#EXCLUSIVE}, {@link Option#PASSIVE} and {@link Option#NONE})
- * @see Option
- */
- public void queueDeclare(String queueName, String alternateExchange, Map<String, Object> arguments,
- Option... options);
-
- /**
- * Bind a queue with an exchange.
- *
- * @param queueName Specifies the name of the queue to bind. If the queue name is empty, refers to the current
- * queue for the session, which is the last declared queue.
- * @param exchangeName The exchange name.
- * @param routingKey Specifies the routing key for the binding. The routing key is used for routing messages
- * depending on the exchange configuration. Not all exchanges use a routing key - refer to
- * the specific exchange documentation. If the queue name is empty, the server uses the last
- * queue declared on the session. If the routing key is also empty, the server uses this
- * queue name for the routing key as well. If the queue name is provided but the routing key
- * is empty, the server does the binding with that empty routing key. The meaning of empty
- * routing keys depends on the exchange implementation.
- * @param arguments Used for backward compatibility
- */
- public void exchangeBind(String queueName, String exchangeName, String routingKey, Map<String, Object> arguments,
- Option ... options);
-
- /**
- * Unbind a queue from an exchange.
- *
- * @param queueName Specifies the name of the queue to unbind.
- * @param exchangeName The name of the exchange to unbind from.
- * @param routingKey Specifies the routing key of the binding to unbind.
- */
- public void exchangeUnbind(String queueName, String exchangeName, String routingKey, Option ... options);
-
- /**
- * This method removes all messages from a queue. It does not cancel consumers. Purged messages
- * are deleted without any formal "undo" mechanism.
- *
- * @param queueName Specifies the name of the queue to purge. If the queue name is empty, refers to the
- * current queue for the session, which is the last declared queue.
- */
- public void queuePurge(String queueName, Option ... options);
-
- /**
- * This method deletes a queue. When a queue is deleted any pending messages are sent to a
- * dead-letter queue if this is defined in the server configuration, and all consumers on the
- * queue are cancelled.
- * <p> Following are the valid options:
- * <ul>
- * <li> {@link Option#IF_EMPTY}: <p> If set, the server will only delete the queue if it has no messages.
- * <li> {@link Option#IF_UNUSED}: <p> If set, the server will only delete the queue if it has no consumers.
- * If the queue has consumers the server does does not delete it but raises a channel exception instead.
- * <li>{@link Option#NONE}: <p> Has no effect as it represents an empty option.
- * </ul>
- * </p>
- * <p/>
- * <p>In the absence of a particular option, the defaul value is false for each option</p>
- *
- * @param queueName Specifies the name of the queue to delete. If the queue name is empty, refers to the
- * current queue for the session, which is the last declared queue.
- * @param options Set of options (Valid options are: {@link Option#IF_EMPTY}, {@link Option#IF_UNUSED}
- * and {@link Option#NONE})
- * @see Option
- */
- public void queueDelete(String queueName, Option... options);
-
-
- /**
- * This method is used to request information on a particular queue.
- *
- * @param queueName The name of the queue for which information is requested.
- * @return Information on the specified queue.
- */
- public Future<QueueQueryResult> queueQuery(String queueName, Option ... options);
-
-
- /**
- * This method is used to request information on a particular binding.
- *
- * @param exchange The exchange name.
- * @param queue The queue name.
- * @param routingKey The routing key
- * @param arguments bacward compatibilties params.
- * @return Information on the specified binding.
- */
- public Future<ExchangeBoundResult> exchangeBound(String exchange, String queue, String routingKey,
- Map<String, Object> arguments, Option ... options);
-
- // --------------------------------------
- // exhcange methods
- // --------------------------------------
-
- /**
- * This method creates an exchange. If the exchange already exists,
- * the method verifies the class and checks the details are correct.
- * <p>Valid options are:
- * <ul>
- * <li>{@link Option#AUTO_DELETE}: <p>If set, the exchange is deleted when all queues have finished using it.
- * <li>{@link Option#DURABLE}: <p>If set, the exchange will
- * be marked as durable. Durable exchanges remain active when a server restarts. Non-durable exchanges (transient
- * exchanges) are purged when a server restarts.
- * <li>{@link Option#PASSIVE}: <p>If set, the server will not create the exchange.
- * The client can use this to check whether an exchange exists without modifying the server state.
- * <li> {@link Option#NONE}: <p>This option is an empty option, and has no effect.
- * </ul>
- * <p>In the absence of a particular option, the defaul value is false for each option</p>
- *
- * @param exchangeName The exchange name.
- * @param type Each exchange belongs to one of a set of exchange types implemented by the server. The
- * exchange types define the functionality of the exchange - i.e. how messages are routed
- * through it. It is not valid or meaningful to attempt to change the type of an existing
- * exchange. Default exchange types are: direct, topic, headers and fanout.
- * @param alternateExchange In the event that a message cannot be routed, this is the name of the exchange to which
- * the message will be sent.
- * @param options Set of options (valid options are: {@link Option#AUTO_DELETE}, {@link Option#DURABLE},
- * {@link Option#PASSIVE}, {@link Option#NONE})
- * @param arguments Used for backward compatibility
- * @see Option
- */
- public void exchangeDeclare(String exchangeName, String type, String alternateExchange,
- Map<String, Object> arguments, Option... options);
-
- /**
- * This method deletes an exchange. When an exchange is deleted all queue bindings on the
- * exchange are cancelled.
- * <p> Following are the valid options:
- * <ul>
- * <li> {@link Option#IF_UNUSED}: <p> If set, the server will only delete the exchange if it has no queue bindings. If the
- * exchange has queue bindings the server does not delete it but raises a channel exception
- * instead.
- * <li> {@link Option#NONE}: <p> Has no effect as it represents an empty option.
- * </ul>
- * <p>Note that if an option is not set, it will default to false.
- *
- * @param exchangeName The name of exchange to be deleted.
- * @param options Set of options. Valid options are: {@link Option#IF_UNUSED}, {@link Option#NONE}.
- * @see Option
- */
- public void exchangeDelete(String exchangeName, Option... options);
-
-
- /**
- * This method is used to request information about a particular exchange.
- *
- * @param exchangeName The name of the exchange about which information is requested. If not set, the method will
- * return information about the default exchange.
- * @return Information on the specified exchange.
- */
- public Future<ExchangeQueryResult> exchangeQuery(String exchangeName, Option ... options);
-
- /**
- * If the session receives a sessionClosed with an error code it
- * informs the session's exceptionListener
- *
- * @param exceptionListner The exceptionListener
- */
- public void setClosedListener(ClosedListener exceptionListner);
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSession.java b/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSession.java
deleted file mode 100644
index 27805a1f39..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSession.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package org.apache.qpid.nclient.impl;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.qpid.QpidException;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.ClosedListener;
-import org.apache.qpid.nclient.MessagePartListener;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.transport.Option;
-import org.apache.qpid.transport.Range;
-import org.apache.qpid.transport.RangeSet;
-
-import static org.apache.qpid.transport.Option.*;
-
-/**
- * Implements a Qpid Sesion.
- */
-public class ClientSession extends org.apache.qpid.transport.Session implements org.apache.qpid.nclient.DtxSession
-{
- static
- {
- String max = "message_size_before_sync"; // KB's
- try
- {
- MAX_NOT_SYNC_DATA_LENGH = new Long(System.getProperties().getProperty(max, "200000000"));
- }
- catch (NumberFormatException e)
- {
- // use default size
- MAX_NOT_SYNC_DATA_LENGH = 200000000;
- }
- String flush = "message_size_before_flush";
- try
- {
- MAX_NOT_FLUSH_DATA_LENGH = new Long(System.getProperties().getProperty(flush, "2000000"));
- }
- catch (NumberFormatException e)
- {
- // use default size
- MAX_NOT_FLUSH_DATA_LENGH = 20000000;
- }
- }
-
- private static long MAX_NOT_SYNC_DATA_LENGH;
- private static long MAX_NOT_FLUSH_DATA_LENGH;
-
- private Map<String,MessagePartListener> _messageListeners = new ConcurrentHashMap<String,MessagePartListener>();
- private ClosedListener _exceptionListner;
- private RangeSet _rejectedMessages;
- private long _currentDataSizeNotSynced;
- private long _currentDataSizeNotFlushed;
-
- public ClientSession(byte[] name)
- {
- super(name);
- }
-
- public void messageAcknowledge(RangeSet ranges, boolean accept)
- {
- for (Range range : ranges)
- {
- super.processed(range);
- }
- super.flushProcessed(accept ? BATCH : NONE);
- if (accept)
- {
- messageAccept(ranges);
- }
- }
-
- public void messageSubscribe(String queue, String destination, short acceptMode, short acquireMode, MessagePartListener listener, Map<String, Object> filter, Option... options)
- {
- setMessageListener(destination,listener);
- super.messageSubscribe(queue, destination, MessageAcceptMode.get(acceptMode),
- MessageAcquireMode.get(acquireMode), null, 0, filter,
- options);
- }
-
- public void messageTransfer(String destination, Message msg, short acceptMode, short acquireMode) throws IOException
- {
- DeliveryProperties dp = msg.getDeliveryProperties();
- MessageProperties mp = msg.getMessageProperties();
- ByteBuffer body = msg.readData();
- int size = body.remaining();
- super.messageTransfer
- (destination, MessageAcceptMode.get(acceptMode),
- MessageAcquireMode.get(acquireMode),
- new Header(dp, mp), body);
- _currentDataSizeNotSynced += size;
- _currentDataSizeNotFlushed += size;
- }
-
- public void sync()
- {
- super.sync();
- _currentDataSizeNotSynced = 0;
- }
-
- public RangeSet getRejectedMessages()
- {
- return _rejectedMessages;
- }
-
- public void setMessageListener(String destination, MessagePartListener listener)
- {
- if (listener == null)
- {
- throw new IllegalArgumentException("Cannot set message listener to null");
- }
- _messageListeners.put(destination, listener);
- }
-
- public void setClosedListener(ClosedListener exceptionListner)
- {
- _exceptionListner = exceptionListner;
- }
-
- void setRejectedMessages(RangeSet rejectedMessages)
- {
- _rejectedMessages = rejectedMessages;
- }
-
- void notifyException(QpidException ex)
- {
- _exceptionListner.onClosed(null, null, null);
- }
-
- Map<String,MessagePartListener> getMessageListeners()
- {
- return _messageListeners;
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSessionDelegate.java b/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSessionDelegate.java
deleted file mode 100644
index 620cf14c33..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSessionDelegate.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.apache.qpid.nclient.impl;
-
-import java.nio.ByteBuffer;
-
-import org.apache.qpid.ErrorCode;
-
-import org.apache.qpid.nclient.MessagePartListener;
-
-import org.apache.qpid.QpidException;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.MessageReject;
-import org.apache.qpid.transport.MessageTransfer;
-import org.apache.qpid.transport.Range;
-import org.apache.qpid.transport.Session;
-import org.apache.qpid.transport.SessionDetached;
-import org.apache.qpid.transport.SessionDelegate;
-
-
-public class ClientSessionDelegate extends SessionDelegate
-{
-
- // --------------------------------------------
- // Message methods
- // --------------------------------------------
- @Override public void messageTransfer(Session session, MessageTransfer xfr)
- {
- MessagePartListener listener = ((ClientSession)session).getMessageListeners()
- .get(xfr.getDestination());
- listener.messageTransfer(xfr);
- }
-
- @Override public void messageReject(Session session, MessageReject struct)
- {
- for (Range range : struct.getTransfers())
- {
- for (long l = range.getLower(); l <= range.getUpper(); l++)
- {
- System.out.println("message rejected: " +
- session.getCommand((int) l));
- }
- }
- ((ClientSession)session).setRejectedMessages(struct.getTransfers());
- ((ClientSession)session).notifyException(new QpidException("Message Rejected",ErrorCode.MESSAGE_REJECTED,null));
- session.processed(struct);
- }
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/impl/Constants.java b/java/client/src/main/java/org/apache/qpid/nclient/impl/Constants.java
deleted file mode 100644
index f689e9abde..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/impl/Constants.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-package org.apache.qpid.nclient.impl;
-
-/**
- * This class holds all the 0.10 client constants which value can be set
- * through properties.
- */
-public class Constants
-{
- static
- {
-
- String max="message_size_before_sync";// KB's
- try
- {
- MAX_NOT_SYNC_DATA_LENGH=new Long(System.getProperties().getProperty(max, "200000000"));
- }
- catch (NumberFormatException e)
- {
- // use default size
- MAX_NOT_SYNC_DATA_LENGH=200000000;
- }
- String flush="message_size_before_flush";
- try
- {
- MAX_NOT_FLUSH_DATA_LENGH=new Long(System.getProperties().getProperty(flush, "2000000"));
- }
- catch (NumberFormatException e)
- {
- // use default size
- MAX_NOT_FLUSH_DATA_LENGH=20000000;
- }
- }
-
- /**
- * The total message size in KBs that can be transferted before
- * client and broker are synchronized.
- * A sync will result in the client library releasing the sent messages
- * from memory. (messages are kept
- * in memory so client can reconnect to a broker in the event of a failure)
- * <p>
- * Property name: message_size_before_sync
- * <p>
- * Default value: 200000000
- */
- public static long MAX_NOT_SYNC_DATA_LENGH;
- /**
- * The total message size in KBs that can be transferted before
- * messages are flushed.
- * When a flush returns all messages have reached the broker.
- * <p>
- * Property name: message_size_before_flush
- * <p>
- * Default value: 200000000
- */
- public static long MAX_NOT_FLUSH_DATA_LENGH;
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/impl/DemoClient.java b/java/client/src/main/java/org/apache/qpid/nclient/impl/DemoClient.java
deleted file mode 100644
index 88b5dc6392..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/impl/DemoClient.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package org.apache.qpid.nclient.impl;
-
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.ClosedListener;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessageListener;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageProperties;
-
-import java.nio.ByteBuffer;
-import java.util.UUID;
-
-public class DemoClient
-{
- public static MessagePartListenerAdapter createAdapter()
- {
- return new MessagePartListenerAdapter(new MessageListener()
- {
- public void onMessage(Message m)
- {
- System.out.println("\n================== Received Msg ==================");
- System.out.println("Message Id : " + m.getMessageProperties().getMessageId());
- System.out.println(m.toString());
- System.out.println("================== End Msg ==================\n");
- }
-
- });
- }
-
- public static final void main(String[] args)
- {
- Connection conn = Client.createConnection();
- try{
- conn.connect("0.0.0.0", 5672, "test", "guest", "guest");
- }catch(Exception e){
- e.printStackTrace();
- }
-
- Session ssn = conn.createSession(50000);
- ssn.setClosedListener(new ClosedListener()
- {
- public void onClosed(ErrorCode errorCode, String reason, Throwable t)
- {
- System.out.println("ErrorCode : " + errorCode + " reason : " + reason);
- }
- });
- ssn.queueDeclare("queue1", null, null);
- ssn.exchangeBind("queue1", "amq.direct", "queue1",null);
- ssn.sync();
-
- ssn.messageSubscribe("queue1", "myDest", (short)0, (short)0,createAdapter(), null);
-
- // queue
- ssn.messageTransfer("amq.direct", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
- new Header(new DeliveryProperties().setRoutingKey("queue1"),
- new MessageProperties().setMessageId(UUID.randomUUID())),
- ByteBuffer.wrap("this is the data".getBytes()));
-
- //reject
- ssn.messageTransfer("amq.direct", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
- new Header(new DeliveryProperties().setRoutingKey("stocks")),
- ByteBuffer.wrap("this should be rejected".getBytes()));
- ssn.sync();
-
- // topic subs
- ssn.messageSubscribe("topic1", "myDest2", (short)0, (short)0,createAdapter(), null);
- ssn.messageSubscribe("topic2", "myDest3", (short)0, (short)0,createAdapter(), null);
- ssn.messageSubscribe("topic3", "myDest4", (short)0, (short)0,createAdapter(), null);
- ssn.sync();
-
- ssn.queueDeclare("topic1", null, null);
- ssn.exchangeBind("topic1", "amq.topic", "stock.*",null);
- ssn.queueDeclare("topic2", null, null);
- ssn.exchangeBind("topic2", "amq.topic", "stock.us.*",null);
- ssn.queueDeclare("topic3", null, null);
- ssn.exchangeBind("topic3", "amq.topic", "stock.us.rh",null);
- ssn.sync();
-
- // topic
- ssn.messageTransfer("amq.topic", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
- new Header(new DeliveryProperties().setRoutingKey("stock.us.ibm"),
- new MessageProperties().setMessageId(UUID.randomUUID())),
- ByteBuffer.wrap("Topic message".getBytes()));
- }
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/interop/BasicInteropTest.java b/java/client/src/main/java/org/apache/qpid/nclient/interop/BasicInteropTest.java
deleted file mode 100644
index 9ea9297e14..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/interop/BasicInteropTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package org.apache.qpid.nclient.interop;
-
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.QpidException;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.ClosedListener;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessageListener;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageCreditUnit;
-import org.apache.qpid.transport.MessageFlowMode;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.transport.RangeSet;
-
-public class BasicInteropTest implements ClosedListener
-{
-
- private Session session;
- private Connection conn;
- private String host;
-
- public BasicInteropTest(String host)
- {
- this.host = host;
- }
-
- public void close() throws QpidException
- {
- conn.close();
- }
-
- public void testCreateConnection(){
- System.out.println("------- Creating connection--------");
- conn = Client.createConnection();
- try{
- conn.connect(host, 5672, "test", "guest", "guest");
- }catch(Exception e){
- System.out.println("------- Error Creating connection--------");
- e.printStackTrace();
- System.exit(1);
- }
- System.out.println("------- Connection created Suscessfully --------");
- }
-
- public void testCreateSession(){
- System.out.println("------- Creating session --------");
- session = conn.createSession(0);
- System.out.println("------- Session created sucessfully --------");
- }
-
- public void testExchange(){
- System.out.println("------- Creating an exchange --------");
- session.exchangeDeclare("test", "direct", "", null);
- session.sync();
- System.out.println("------- Exchange created --------");
- }
-
- public void testQueue(){
- System.out.println("------- Creating a queue --------");
- session.queueDeclare("testQueue", "", null);
- session.sync();
- System.out.println("------- Queue created --------");
-
- System.out.println("------- Binding a queue --------");
- session.exchangeBind("testQueue", "test", "testKey", null);
- session.sync();
- System.out.println("------- Queue bound --------");
- }
-
- public void testSendMessage(){
- System.out.println("------- Sending a message --------");
- Map<String,Object> props = new HashMap<String,Object>();
- props.put("name", "rajith");
- props.put("age", 10);
- props.put("spf", 8.5);
- session.messageTransfer("test", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
- new Header(new DeliveryProperties().setRoutingKey("testKey"),
- new MessageProperties().setApplicationHeaders(props)),
- ByteBuffer.wrap("TestMessage".getBytes()));
-
- session.sync();
- System.out.println("------- Message sent --------");
- }
-
- public void testSubscribe()
- {
- System.out.println("------- Sending a subscribe --------");
- session.messageSubscribe("testQueue", "myDest",
- Session.TRANSFER_CONFIRM_MODE_REQUIRED,
- Session.TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE,
- new MessagePartListenerAdapter(new MessageListener(){
-
- public void onMessage(Message message)
- {
- System.out.println("--------Message Received--------");
- System.out.println(message.toString());
- System.out.println("--------/Message Received--------");
- RangeSet ack = new RangeSet();
- ack.add(message.getMessageTransferId(),message.getMessageTransferId());
- session.messageAcknowledge(ack, true);
- }
-
- }),
- null);
-
- System.out.println("------- Setting Credit mode --------");
- session.messageSetFlowMode("myDest", MessageFlowMode.WINDOW);
- System.out.println("------- Setting Credit --------");
- session.messageFlow("myDest", MessageCreditUnit.MESSAGE, 1);
- session.messageFlow("myDest", MessageCreditUnit.BYTE, -1);
- }
-
- public void testMessageFlush()
- {
- session.messageFlush("myDest");
- session.sync();
- }
-
- public void onClosed(ErrorCode errorCode, String reason, Throwable t)
- {
- System.out.println("------- Broker Notified an error --------");
- System.out.println("------- " + errorCode + " --------");
- System.out.println("------- " + reason + " --------");
- System.out.println("------- /Broker Notified an error --------");
- }
-
- public static void main(String[] args) throws QpidException
- {
- String host = "0.0.0.0";
- if (args.length>0)
- {
- host = args[0];
- }
-
- BasicInteropTest t = new BasicInteropTest(host);
- t.testCreateConnection();
- t.testCreateSession();
- t.testExchange();
- t.testQueue();
- t.testSubscribe();
- t.testSendMessage();
- t.testMessageFlush();
- t.close();
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java b/java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java
index 64c89c960c..14bfb4f95e 100644
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java
@@ -1,4 +1,25 @@
package org.apache.qpid.nclient.util;
+/*
+ *
+ * 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.
+ *
+ */
+
import java.io.IOException;
import java.nio.ByteBuffer;
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/FileMessage.java b/java/client/src/main/java/org/apache/qpid/nclient/util/FileMessage.java
deleted file mode 100644
index 179c91c2e9..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/FileMessage.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.apache.qpid.nclient.util;
-
-import java.io.EOFException;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.api.Message;
-
-/**
- * FileMessage provides pull style semantics for
- * larges messages backed by a disk.
- * Instead of loading all data into memeory it uses
- * FileChannel to map regions of the file into memeory
- * at a time.
- *
- * The write methods are not supported.
- *
- * From the standpoint of performance it is generally
- * only worth mapping relatively large files into memory.
- *
- * FileMessage msg = new FileMessage(in,delProps,msgProps);
- * session.messageTransfer(dest,msg,0,0);
- *
- * The messageTransfer method will read the file in chunks
- * and stream it.
- *
- */
-public class FileMessage extends ReadOnlyMessage implements Message
-{
- private FileChannel _fileChannel;
- private int _chunkSize;
- private long _fileSize;
- private long _pos = 0;
-
- public FileMessage(FileInputStream in,int chunkSize,DeliveryProperties deliveryProperties,MessageProperties messageProperties)throws IOException
- {
- _messageProperties = messageProperties;
- _deliveryProperties = deliveryProperties;
-
- _fileChannel = in.getChannel();
- _chunkSize = chunkSize;
- _fileSize = _fileChannel.size();
-
- if (_fileSize <= _chunkSize)
- {
- _chunkSize = (int)_fileSize;
- }
- }
-
- public void setHeader(Header header) {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Header getHeader() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void readData(byte[] target) throws IOException
- {
- throw new UnsupportedOperationException();
- }
-
- public ByteBuffer readData() throws IOException
- {
- if (_pos == _fileSize)
- {
- throw new EOFException();
- }
-
- if (_pos + _chunkSize > _fileSize)
- {
- _chunkSize = (int)(_fileSize - _pos);
- }
- MappedByteBuffer bb = _fileChannel.map(FileChannel.MapMode.READ_ONLY, _pos, _chunkSize);
- _pos += _chunkSize;
- return bb;
- }
-
- /**
- * This message is used by an application user to
- * provide data to the client library using pull style
- * semantics. Since the message is not transfered yet, it
- * does not have a transfer id. Hence this method is not
- * applicable to this implementation.
- */
- public int getMessageTransferId()
- {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java b/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
index 0e54e04a99..10fd8d2a80 100644
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
+++ b/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
@@ -1,4 +1,25 @@
package org.apache.qpid.nclient.util;
+/*
+ *
+ * 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.
+ *
+ */
+
import java.io.IOException;
import java.nio.ByteBuffer;
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/ReadOnlyMessage.java b/java/client/src/main/java/org/apache/qpid/nclient/util/ReadOnlyMessage.java
deleted file mode 100644
index 6583a95c7e..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/ReadOnlyMessage.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.apache.qpid.nclient.util;
-
-import java.nio.ByteBuffer;
-
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.api.Message;
-
-public abstract class ReadOnlyMessage implements Message
-{
- MessageProperties _messageProperties;
- DeliveryProperties _deliveryProperties;
-
- public void appendData(byte[] src)
- {
- throw new UnsupportedOperationException("This Message is read only after the initial source");
- }
-
- public void appendData(ByteBuffer src)
- {
- throw new UnsupportedOperationException("This Message is read only after the initial source");
- }
-
- public DeliveryProperties getDeliveryProperties()
- {
- return _deliveryProperties;
- }
-
- public MessageProperties getMessageProperties()
- {
- return _messageProperties;
- }
-
- public void clearData()
- {
- throw new UnsupportedOperationException("This Message is read only after the initial source, cannot clear data");
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/StreamingMessage.java b/java/client/src/main/java/org/apache/qpid/nclient/util/StreamingMessage.java
deleted file mode 100644
index a4574438ac..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/StreamingMessage.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.qpid.nclient.util;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.api.Message;
-
-public class StreamingMessage extends ReadOnlyMessage implements Message
-{
- SocketChannel _socChannel;
- private int _chunkSize;
- private ByteBuffer _readBuf;
-
- public Header getHeader() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setHeader(Header header) {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public StreamingMessage(SocketChannel in,int chunkSize,DeliveryProperties deliveryProperties,MessageProperties messageProperties)throws IOException
- {
- _messageProperties = messageProperties;
- _deliveryProperties = deliveryProperties;
-
- _socChannel = in;
- _chunkSize = chunkSize;
- _readBuf = ByteBuffer.allocate(_chunkSize);
- }
-
- public void readData(byte[] target) throws IOException
- {
- throw new UnsupportedOperationException();
- }
-
- public ByteBuffer readData() throws IOException
- {
- if(_socChannel.isConnected() && _socChannel.isOpen())
- {
- _readBuf.clear();
- _socChannel.read(_readBuf);
- }
- else
- {
- throw new EOFException("The underlying socket/channel has closed");
- }
-
- return _readBuf.duplicate();
- }
-
- /**
- * This message is used by an application user to
- * provide data to the client library using pull style
- * semantics. Since the message is not transfered yet, it
- * does not have a transfer id. Hence this method is not
- * applicable to this implementation.
- */
- public int getMessageTransferId()
- {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/java/client/src/test/java/org/apache/qpid/client/AMQQueueTest.java b/java/client/src/test/java/org/apache/qpid/client/AMQQueueTest.java
new file mode 100644
index 0000000000..7789f87ace
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/AMQQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import junit.framework.TestCase;
+
+public class AMQQueueTest extends TestCase
+{
+ AMQShortString exchange = new AMQShortString("test.exchange");
+ AMQShortString routingkey = new AMQShortString("test-route");
+ AMQShortString qname = new AMQShortString("test-queue");
+ AMQShortString[] oneBinding = new AMQShortString[]{new AMQShortString("bindingA")};
+ AMQShortString[] bindings = new AMQShortString[]{new AMQShortString("bindingB"),
+ new AMQShortString("bindingC")};
+
+ public void testToURLNoBindings()
+ {
+ AMQQueue dest = new AMQQueue(exchange, routingkey, qname);
+ String url = dest.toURL();
+ assertEquals("direct://test.exchange/test-route/test-queue?routingkey='test-route'", url);
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java b/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
new file mode 100644
index 0000000000..da44822ec3
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
@@ -0,0 +1,94 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.url.URLSyntaxException;
+
+import java.io.IOException;
+
+public class MockAMQConnection extends AMQConnection
+{
+ public MockAMQConnection(String broker, String username, String password, String clientName, String virtualHost)
+ throws AMQException, URLSyntaxException
+ {
+ super(broker, username, password, clientName, virtualHost);
+ }
+
+ public MockAMQConnection(String broker, String username, String password, String clientName, String virtualHost, SSLConfiguration sslConfig)
+ throws AMQException, URLSyntaxException
+ {
+ super(broker, username, password, clientName, virtualHost, sslConfig);
+ }
+
+ public MockAMQConnection(String host, int port, String username, String password, String clientName, String virtualHost)
+ throws AMQException, URLSyntaxException
+ {
+ super(host, port, username, password, clientName, virtualHost);
+ }
+
+ public MockAMQConnection(String host, int port, String username, String password, String clientName, String virtualHost, SSLConfiguration sslConfig)
+ throws AMQException, URLSyntaxException
+ {
+ super(host, port, username, password, clientName, virtualHost, sslConfig);
+ }
+
+ public MockAMQConnection(String host, int port, boolean useSSL, String username, String password, String clientName, String virtualHost, SSLConfiguration sslConfig)
+ throws AMQException, URLSyntaxException
+ {
+ super(host, port, useSSL, username, password, clientName, virtualHost, sslConfig);
+ }
+
+ public MockAMQConnection(String connection)
+ throws AMQException, URLSyntaxException
+ {
+ super(connection);
+ }
+
+ public MockAMQConnection(String connection, SSLConfiguration sslConfig)
+ throws AMQException, URLSyntaxException
+ {
+ super(connection, sslConfig);
+ }
+
+ public MockAMQConnection(ConnectionURL connectionURL, SSLConfiguration sslConfig)
+ throws AMQException
+ {
+ super(connectionURL, sslConfig);
+ }
+
+ protected MockAMQConnection(String username, String password, String clientName, String virtualHost)
+ {
+ super(username, password, clientName, virtualHost);
+ }
+
+ @Override
+ public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException
+ {
+ _connected = true;
+ _protocolHandler.getStateManager().changeState(AMQState.CONNECTION_OPEN);
+ return null;
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/client/message/AbstractJMSMessageTest.java b/java/client/src/test/java/org/apache/qpid/client/message/AbstractJMSMessageTest.java
new file mode 100644
index 0000000000..b4774113be
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/message/AbstractJMSMessageTest.java
@@ -0,0 +1,36 @@
+package org.apache.qpid.client.message;
+
+import javax.jms.JMSException;
+
+import junit.framework.TestCase;
+
+public class AbstractJMSMessageTest extends TestCase
+{
+
+ public void testSetNullJMSReplyTo08() throws JMSException
+ {
+ JMSTextMessage message = new JMSTextMessage(AMQMessageDelegateFactory.FACTORY_0_8);
+ try
+ {
+ message.setJMSReplyTo(null);
+ }
+ catch (IllegalArgumentException e)
+ {
+ fail("Null destination should be allowed");
+ }
+ }
+
+ public void testSetNullJMSReplyTo10() throws JMSException
+ {
+ JMSTextMessage message = new JMSTextMessage(AMQMessageDelegateFactory.FACTORY_0_10);
+ try
+ {
+ message.setJMSReplyTo(null);
+ }
+ catch (IllegalArgumentException e)
+ {
+ fail("Null destination should be allowed");
+ }
+ }
+
+}
diff --git a/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java b/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java
new file mode 100644
index 0000000000..f520a21ba0
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java
@@ -0,0 +1,289 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.protocol;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQBody;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.amqp_8_0.BasicRecoverOkBodyImpl;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.transport.TestNetworkDriver;
+import org.apache.qpid.client.MockAMQConnection;
+import org.apache.qpid.client.AMQAuthenticationException;
+import org.apache.qpid.client.state.AMQState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This is a test address QPID-1431 where frame listeners would fail to be notified of an incomming exception.
+ *
+ * Currently we do checks at the Session level to ensure that the connection/session are open. However, it is possible
+ * for the connection to close AFTER this check has been performed.
+ *
+ * Performing a similar check at the frameListener level in AMQProtocolHandler makes most sence as this will prevent
+ * listening when there can be no returning frames.
+ *
+ * With the correction in place it also means that the new listener will either make it on to the list for notification
+ * or it will be notified of any existing exception due to the connection being closed.
+ *
+ * There may still be an issue in this space if the client utilises a second thread to close the session as there will
+ * be no exception set to throw and so the wait will occur. That said when the session is closed the framelisteners
+ * should be notified. Not sure this is tested.
+ */
+public class AMQProtocolHandlerTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(AMQProtocolHandlerTest.class);
+
+ // The handler to test
+ AMQProtocolHandler _handler;
+
+ // A frame to block upon whilst waiting the exception
+ AMQFrame _blockFrame;
+
+ // Latch to know when the listener receives an exception
+ private CountDownLatch _handleCountDown;
+ // The listener that will receive an exception
+ BlockToAccessFrameListener _listener;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ //Create a new ProtocolHandler with a fake connection.
+ _handler = new AMQProtocolHandler(new MockAMQConnection("amqp://guest:guest@client/test?brokerlist='vm://:1'"));
+ _handler.setNetworkDriver(new TestNetworkDriver());
+ AMQBody body = BasicRecoverOkBodyImpl.getFactory().newInstance(null, 1);
+ _blockFrame = new AMQFrame(0, body);
+
+ _handleCountDown = new CountDownLatch(1);
+
+ _logger.info("Creating _Listener that should also receive the thrown exception.");
+ _listener = new BlockToAccessFrameListener(1);
+ }
+
+ /**
+ * There are two paths based on the type of exception thrown.
+ *
+ * This tests that when an AMQException is thrown we get the same type of AMQException back with the real exception
+ * wrapped as the cause.
+ *
+ * @throws InterruptedException - if we are unable to wait for the test signals
+ */
+ public void testFrameListenerUpdateWithAMQException() throws InterruptedException
+ {
+ AMQException trigger = new AMQAuthenticationException(AMQConstant.ACCESS_REFUSED,
+ "AMQPHTest", new RuntimeException());
+
+ performWithException(trigger);
+
+
+ AMQException receivedException = (AMQException) _listener.getReceivedException();
+
+ assertEquals("Return exception was not the expected type",
+ AMQAuthenticationException.class, receivedException.getClass());
+
+ assertEquals("The _Listener did not receive the correct error code",
+ trigger.getErrorCode(), receivedException.getErrorCode());
+ }
+
+ /**
+ * There are two paths based on the type of exception thrown.
+ *
+ * This tests that when a generic Exception is thrown we get the exception back wrapped in a AMQException
+ * as the cause.
+ * @throws InterruptedException - if we are unable to wait for the test signals
+ */
+ public void testFrameListenerUpdateWithException() throws InterruptedException
+ {
+
+ Exception trigger = new Exception(new RuntimeException());
+
+ performWithException(trigger);
+
+ assertEquals("The _Listener did not receive the correct error code",
+ AMQConstant.INTERNAL_ERROR, ((AMQException)_listener.getReceivedException()).getErrorCode());
+ }
+
+ /**
+ * This is the main test method for both test cases.
+ *
+ * What occurs is that we create a new thread that will block (<30s[DEFAULT]) for a frame or exception to occur .
+ *
+ * We use a CountDownLatch to ensure that the new thread is running before we then yield and sleep to help ensure
+ * the new thread has entered the synchronized block in the writeCommandFrameAndWaitForReply.
+ *
+ * We can then ack like an the incomming exception handler in (ConnectionCloseMethodHandler).
+ *
+ * We fire the error to the stateManager, which in this case will recored the error as there are no state listeners.
+ *
+ * We then set the connection to be closed, as we would normally close the socket at this point.
+ *
+ * Then fire the exception in to any frameListeners.
+ *
+ * The blocked listener (created above) when receiving the error simulates the user by creating a new request to
+ * block for a frame.
+ *
+ * This request should fail. Prior to the fix this will fail with a NPE as we are attempting to use a null listener
+ * in the writeCommand.... call L:268.
+ *
+ * This highlights that the listener would be added dispite there being a pending error state that the listener will
+ * miss as it is not currently part of the _frameListeners set that is being notified by the iterator.
+ *
+ * The method waits to ensure that an exception is received before returning.
+ *
+ * The calling methods validate that exception that was received based on the one they sent in.
+ *
+ * @param trigger The exception to throw through the handler
+ */
+ private void performWithException(Exception trigger) throws InterruptedException
+ {
+
+ final CountDownLatch callingWriteCommand = new CountDownLatch(1);
+
+ //Set an initial listener that will allow us to create a new blocking method
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+
+ try
+ {
+
+ _logger.info("At initial block, signalling to fire new exception");
+ callingWriteCommand.countDown();
+
+ _handler.writeCommandFrameAndWaitForReply(_blockFrame, _listener);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+ }).start();
+
+ _logger.info("Waiting for 'initial block' to start ");
+ if (!callingWriteCommand.await(1000, TimeUnit.MILLISECONDS))
+ {
+ fail("Failed to start new thread to block for frame");
+ }
+
+ // Do what we can to ensure that this thread does not continue before the above thread has hit the synchronized
+ // block in the writeCommandFrameAndWaitForReply
+ Thread.yield();
+ Thread.sleep(1000);
+
+ _logger.info("Firing Erorr through state manager. There should be not state waiters here.");
+ _handler.getStateManager().error(trigger);
+
+ _logger.info("Setting state to be CONNECTION_CLOSED.");
+
+ _handler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
+
+ _logger.info("Firing exception");
+ _handler.propagateExceptionToFrameListeners(trigger);
+
+ _logger.info("Awaiting notifcation from handler that exception arrived.");
+
+ if (!_handleCountDown.await(2000, TimeUnit.MILLISECONDS))
+ {
+ fail("Failed to handle exception and timeout has not occured");
+ }
+
+
+ assertNotNull("The _Listener did not receive the exception", _listener.getReceivedException());
+
+ assertTrue("Received exception not an AMQException",
+ _listener.getReceivedException() instanceof AMQException);
+
+ AMQException receivedException = (AMQException) _listener.getReceivedException();
+
+ assertTrue("The _Listener did not receive the correct message",
+ receivedException.getMessage().startsWith(trigger.getMessage()));
+
+
+ assertEquals("The _Listener did not receive the correct cause",
+ trigger, receivedException.getCause());
+
+ assertEquals("The _Listener did not receive the correct sub cause",
+ trigger.getCause(), receivedException.getCause().getCause());
+
+ }
+
+ class BlockToAccessFrameListener extends BlockingMethodFrameListener
+ {
+ private Exception _receivedException = null;
+
+ /**
+ * Creates a new method listener, that filters incoming method to just those that match the specified channel id.
+ *
+ * @param channelId The channel id to filter incoming methods with.
+ */
+ public BlockToAccessFrameListener(int channelId)
+ {
+ super(channelId);
+ _logger.info("Creating a listener:" + this);
+ }
+
+ public boolean processMethod(int channelId, AMQMethodBody frame)
+ {
+ return true;
+ }
+
+ @Override
+ public void error(Exception e)
+ {
+ _logger.info("Exception(" + e + ") Received by:" + this);
+ // Create a new Thread to start the blocking registration.
+ new Thread(new Runnable()
+ {
+
+ public void run()
+ {
+ //Set an initial listener that will allow us to create a new blocking method
+ try
+ {
+ _handler.writeCommandFrameAndWaitForReply(_blockFrame, null, 2000L);
+ _logger.info("listener(" + this + ") Wait completed");
+ }
+ catch (Exception e)
+ {
+ _logger.info("listener(" + this + ") threw exception:" + e.getMessage());
+ _receivedException = e;
+ }
+
+ _logger.info("listener(" + this + ") completed");
+ _handleCountDown.countDown();
+ }
+ }).start();
+ }
+
+ public Exception getReceivedException()
+ {
+ return _receivedException;
+ }
+ }
+
+}
diff --git a/java/client/src/test/java/org/apache/qpid/client/protocol/MockIoSession.java b/java/client/src/test/java/org/apache/qpid/client/protocol/MockIoSession.java
new file mode 100644
index 0000000000..f0938a4bc0
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/protocol/MockIoSession.java
@@ -0,0 +1,312 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.protocol;
+
+import org.apache.mina.common.*;
+import org.apache.mina.common.support.DefaultCloseFuture;
+import org.apache.mina.common.support.DefaultWriteFuture;
+import org.apache.mina.common.support.AbstractIoFilterChain;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+import java.util.Set;
+
+public class MockIoSession implements IoSession
+{
+ private AMQProtocolSession _protocolSession;
+
+ /**
+ * Stores the last response written
+ */
+ private Object _lastWrittenObject;
+
+ private boolean _closing;
+ private IoFilterChain _filterChain;
+
+ public MockIoSession()
+ {
+ _filterChain = new AbstractIoFilterChain(this)
+ {
+ protected void doWrite(IoSession ioSession, IoFilter.WriteRequest writeRequest) throws Exception
+ {
+
+ }
+
+ protected void doClose(IoSession ioSession) throws Exception
+ {
+
+ }
+ };
+ }
+
+ public Object getLastWrittenObject()
+ {
+ return _lastWrittenObject;
+ }
+
+ public IoService getService()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public IoServiceConfig getServiceConfig()
+ {
+ return null;
+ }
+
+ public IoHandler getHandler()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public IoSessionConfig getConfig()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public IoFilterChain getFilterChain()
+ {
+ return _filterChain;
+ }
+
+ public WriteFuture write(Object message)
+ {
+ WriteFuture wf = new DefaultWriteFuture(null);
+ _lastWrittenObject = message;
+ return wf;
+ }
+
+ public CloseFuture close()
+ {
+ _closing = true;
+ CloseFuture cf = new DefaultCloseFuture(null);
+ cf.setClosed();
+ return cf;
+ }
+
+ public Object getAttachment()
+ {
+ return _protocolSession;
+ }
+
+ public Object setAttachment(Object attachment)
+ {
+ Object current = _protocolSession;
+ _protocolSession = (AMQProtocolSession) attachment;
+ return current;
+ }
+
+ public Object getAttribute(String key)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Object setAttribute(String key, Object value)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Object setAttribute(String key)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Object removeAttribute(String key)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean containsAttribute(String key)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Set getAttributeKeys()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public TransportType getTransportType()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isConnected()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isClosing()
+ {
+ return _closing;
+ }
+
+ public CloseFuture getCloseFuture()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return new InetSocketAddress("127.0.0.1", 1234); //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public SocketAddress getServiceAddress()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getIdleTime(IdleStatus status)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getIdleTimeInMillis(IdleStatus status)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setIdleTime(IdleStatus status, int idleTime)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getWriteTimeout()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getWriteTimeoutInMillis()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setWriteTimeout(int writeTimeout)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public TrafficMask getTrafficMask()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setTrafficMask(TrafficMask trafficMask)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void suspendRead()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void suspendWrite()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void resumeRead()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void resumeWrite()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getReadBytes()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getWrittenBytes()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getReadMessages()
+ {
+ return 0L;
+ }
+
+ public long getWrittenMessages()
+ {
+ return 0L;
+ }
+
+ public long getWrittenWriteRequests()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getScheduledWriteRequests()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getScheduledWriteBytes()
+ {
+ return 0; //TODO
+ }
+
+ public long getCreationTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getLastIoTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getLastReadTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getLastWriteTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isIdle(IdleStatus status)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getIdleCount(IdleStatus status)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getLastIdleTime(IdleStatus status)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
index 7bf96b99c1..1b27ff6300 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
@@ -20,14 +20,19 @@
*/
package org.apache.qpid.test.unit.client.BrokerDetails;
+import java.util.HashMap;
+import java.util.Map;
+
import junit.framework.TestCase;
import org.apache.qpid.client.AMQBrokerDetails;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.url.URLSyntaxException;
public class BrokerDetailsTest extends TestCase
{
-
public void testMultiParameters() throws URLSyntaxException
{
String url = "tcp://localhost:5672?timeout='200',immediatedelivery='true'";
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
index 6f4c26945c..7400b524fd 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
@@ -375,6 +375,19 @@ public class ConnectionURLTest extends TestCase
assertTrue(connectionurl.getBrokerCount() == 1);
}
+ public void testClientIDWithUnderscore() throws URLSyntaxException
+ {
+ String url = "amqp://user:pass@client_id/test?brokerlist='tcp://localhost:5672'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getUsername().equals("user"));
+ assertTrue(connectionurl.getPassword().equals("pass"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+ assertTrue(connectionurl.getClientName().equals("client_id"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+ }
public void testWrongOptionSeparatorInOptions()
{
@@ -486,7 +499,8 @@ public class ConnectionURLTest extends TestCase
assertNotNull(curl.getBrokerDetails(0));
assertEquals(BrokerDetails.SOCKET, curl.getBrokerDetails(0).getTransport());
assertEquals("VM-Unique-socketID", curl.getBrokerDetails(0).getHost());
- assertEquals("URL does not toString as expected", url, curl.toString());
+ assertEquals("URL does not toString as expected",
+ url.replace(":guest", ":********"), curl.toString());
}
catch (URLSyntaxException e)
{
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
index 2a66b86985..22e432a44f 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
@@ -177,6 +177,18 @@ public class DestinationURLTest extends TestCase
assertTrue("Failed to throw an URISyntaxException when both the bindingkey and routingkey is specified",exceptionThrown);
}
+
+ public void testDestinationWithDurableTopic() throws URISyntaxException
+ {
+
+ String url = "topic://amq.topic//testTopicD?durable='true'&autodelete='true'&clientid='test'&subscription='testQueueD'";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(dest.getExchangeClass().equals("topic"));
+ assertTrue(dest.getExchangeName().equals("amq.topic"));
+ assertTrue(dest.getQueueName().equals("test:testQueueD"));
+ }
public static junit.framework.Test suite()
{
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java
index bbabf0b57d..65013e7e6d 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java
@@ -559,7 +559,7 @@ public class BytesMessageTest extends TestCase
JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
bm.reset();
String result = bm.toBodyString();
- assertNull(result);
+ assertEquals("\"\"", result);
}
public static junit.framework.Test suite()
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java
index 802f1e6c2e..085dd81079 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java
@@ -435,7 +435,7 @@ public class StreamMessageTest extends TestCase
JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
bm.reset();
String result = bm.toBodyString();
- assertNull(result);
+ assertEquals("\"\"", result);
}
private void checkConversionsFail(StreamMessage sm, int[] conversions) throws JMSException
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/jndi/ConnectionFactoryTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/ConnectionFactoryTest.java
new file mode 100644
index 0000000000..9e76b0d468
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/ConnectionFactoryTest.java
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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.test.unit.jndi;
+
+import junit.framework.TestCase;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.url.URLSyntaxException;
+
+public class ConnectionFactoryTest extends TestCase
+{
+
+ //URL will be returned with the password field swapped for '********'
+ // so ensure that these two strings are kept in sync.
+ public static final String URL = "amqp://guest:guest@clientID/test?brokerlist='tcp://localhost:5672'";
+ public static final String URL_STAR_PWD = "amqp://guest:********@clientID/test?brokerlist='tcp://localhost:5672'";
+
+ public void testConnectionURLString()
+ {
+ AMQConnectionFactory factory = new AMQConnectionFactory();
+
+ assertNull("ConnectionURL should have no value at start",
+ factory.getConnectionURL());
+
+ try
+ {
+ factory.setConnectionURLString(URL);
+ }
+ catch (URLSyntaxException e)
+ {
+ fail(e.getMessage());
+ }
+
+ //URL will be returned with the password field swapped for '********'
+ assertEquals("Connection URL not correctly set", URL_STAR_PWD, factory.getConnectionURLString());
+
+ // Further test that the processed ConnectionURL is as expected after
+ // the set call
+ ConnectionURL connectionurl = factory.getConnectionURL();
+
+ assertNull("Failover is set.", connectionurl.getFailoverMethod());
+ assertEquals("guest", connectionurl.getUsername());
+ assertEquals("guest", connectionurl.getPassword());
+ assertEquals("clientID", connectionurl.getClientName());
+ assertEquals("/test", connectionurl.getVirtualHost());
+
+ assertEquals(1, connectionurl.getBrokerCount());
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertEquals("tcp", service.getTransport());
+ assertEquals("localhost", service.getHost());
+ assertEquals(5672, service.getPort());
+
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDIPropertyFileTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDIPropertyFileTest.java
new file mode 100644
index 0000000000..a1b14d5723
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDIPropertyFileTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.test.unit.jndi;
+
+import java.util.Properties;
+
+import javax.jms.Queue;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.framing.AMQShortString;
+
+import junit.framework.TestCase;
+
+public class JNDIPropertyFileTest extends TestCase
+{
+ Context ctx;
+
+ public JNDIPropertyFileTest() throws Exception
+ {
+ Properties properties = new Properties();
+ properties.load(this.getClass().getResourceAsStream("JNDITest.properties"));
+
+ //Create the initial context
+ ctx = new InitialContext(properties);
+ }
+
+ public void testQueueNamesWithTrailingSpaces() throws Exception
+ {
+ Queue queue = (Queue)ctx.lookup("QueueNameWithSpace");
+ assertEquals("QueueNameWithSpace",queue.getQueueName());
+ }
+
+ public void testTopicNamesWithTrailingSpaces() throws Exception
+ {
+ Topic topic = (Topic)ctx.lookup("TopicNameWithSpace");
+ assertEquals("TopicNameWithSpace",topic.getTopicName());
+ }
+
+ public void testMultipleTopicNamesWithTrailingSpaces() throws Exception
+ {
+ Topic topic = (Topic)ctx.lookup("MultipleTopicNamesWithSpace");
+ int i = 0;
+ for (AMQShortString bindingKey: ((AMQDestination)topic).getBindingKeys())
+ {
+ i++;
+ assertEquals("Topic" + i + "WithSpace",bindingKey.asString());
+ }
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDITest.properties b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDITest.properties
new file mode 100644
index 0000000000..07017a05a6
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDITest.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
+
+# Queue name with spaces
+queue.QueueNameWithSpace = QueueNameWithSpace
+
+# Topic name with spaces
+topic.TopicNameWithSpace = TopicNameWithSpace
+
+# Multiple topic names with spaces
+topic.MultipleTopicNamesWithSpace = Topic1WithSpace , Topic2WithSpace , Topic3WithSpace
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java b/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
index a881f6a822..566a222897 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
@@ -44,7 +44,9 @@ public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMe
}
- public void sendQueueBind(AMQShortString queueName, AMQShortString routingKey, FieldTable arguments, AMQShortString exchangeName, AMQDestination destination) throws AMQException, FailoverException
+ public void sendQueueBind(AMQShortString queueName, AMQShortString routingKey, FieldTable arguments,
+ AMQShortString exchangeName, AMQDestination destination,
+ boolean nowait) throws AMQException, FailoverException
{
}
@@ -129,7 +131,8 @@ public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMe
}
- public void sendQueueDeclare(AMQDestination amqd, AMQProtocolHandler protocolHandler) throws AMQException, FailoverException
+ public void sendQueueDeclare(AMQDestination amqd, AMQProtocolHandler protocolHandler,
+ boolean nowait) throws AMQException, FailoverException
{
}