diff options
| author | Stephen D. Huston <shuston@apache.org> | 2011-10-21 01:19:00 +0000 |
|---|---|---|
| committer | Stephen D. Huston <shuston@apache.org> | 2011-10-21 01:19:00 +0000 |
| commit | ebfd9ff053b04ab379acfc0fefedee5a31b6d8a5 (patch) | |
| tree | dcfb94e75656c6c239fc3dcb754cd2015126424d /java/client/src | |
| parent | 5eb354b338bb8d8fcd35b6ac3fb33f8103e757c3 (diff) | |
| download | qpid-python-ebfd9ff053b04ab379acfc0fefedee5a31b6d8a5.tar.gz | |
Undo bad merge from trunk - merged at wrong level.
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-2519@1187150 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/client/src')
154 files changed, 10920 insertions, 5702 deletions
diff --git a/java/client/src/main/java/client.bnd b/java/client/src/main/java/client.bnd index 98696dc7d8..0ddd163d4f 100755 --- a/java/client/src/main/java/client.bnd +++ b/java/client/src/main/java/client.bnd @@ -17,7 +17,7 @@ # under the License. # -ver: 0.13.0 +ver: 0.9.0 Bundle-SymbolicName: qpid-client Bundle-Version: ${ver} diff --git a/java/client/src/main/java/org/apache/mina/transport/socket/nio/ExistingSocketConnector.java b/java/client/src/main/java/org/apache/mina/transport/socket/nio/ExistingSocketConnector.java new file mode 100644 index 0000000000..98716c0c3c --- /dev/null +++ b/java/client/src/main/java/org/apache/mina/transport/socket/nio/ExistingSocketConnector.java @@ -0,0 +1,478 @@ +/* + * 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.mina.transport.socket.nio; + +import edu.emory.mathcs.backport.java.util.concurrent.Executor; +import org.apache.mina.common.ConnectFuture; +import org.apache.mina.common.ExceptionMonitor; +import org.apache.mina.common.IoConnector; +import org.apache.mina.common.IoConnectorConfig; +import org.apache.mina.common.IoHandler; +import org.apache.mina.common.IoServiceConfig; +import org.apache.mina.common.support.BaseIoConnector; +import org.apache.mina.common.support.DefaultConnectFuture; +import org.apache.mina.util.NamePreservingRunnable; +import org.apache.mina.util.NewThreadExecutor; +import org.apache.mina.util.Queue; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.util.Iterator; +import java.util.Set; + +/** + * {@link IoConnector} for socket transport (TCP/IP). + * + * @author The Apache Directory Project (mina-dev@directory.apache.org) + * @version $Rev: 627427 $, $Date: 2008-02-13 14:39:10 +0000 (Wed, 13 Feb 2008) $ + */ +public class ExistingSocketConnector extends BaseIoConnector +{ + /** @noinspection StaticNonFinalField */ + private static volatile int nextId = 0; + + private final Object lock = new Object(); + private final int id = nextId++; + private final String threadName = "SocketConnector-" + id; + private SocketConnectorConfig defaultConfig = new SocketConnectorConfig(); + private final Queue connectQueue = new Queue(); + private final SocketIoProcessor[] ioProcessors; + private final int processorCount; + private final Executor executor; + + /** @noinspection FieldAccessedSynchronizedAndUnsynchronized */ + private Selector selector; + private Worker worker; + private int processorDistributor = 0; + private int workerTimeout = 60; // 1 min. + private Socket _openSocket = null; + + /** Create a connector with a single processing thread using a NewThreadExecutor */ + public ExistingSocketConnector() + { + this(1, new NewThreadExecutor()); + } + + /** + * Create a connector with the desired number of processing threads + * + * @param processorCount Number of processing threads + * @param executor Executor to use for launching threads + */ + public ExistingSocketConnector(int processorCount, Executor executor) + { + if (processorCount < 1) + { + throw new IllegalArgumentException("Must have at least one processor"); + } + + this.executor = executor; + this.processorCount = processorCount; + ioProcessors = new SocketIoProcessor[processorCount]; + + for (int i = 0; i < processorCount; i++) + { + ioProcessors[i] = new SocketIoProcessor("SocketConnectorIoProcessor-" + id + "." + i, executor); + } + } + + /** + * How many seconds to keep the connection thread alive between connection requests + * + * @return Number of seconds to keep connection thread alive + */ + public int getWorkerTimeout() + { + return workerTimeout; + } + + /** + * Set how many seconds the connection worker thread should remain alive once idle before terminating itself. + * + * @param workerTimeout Number of seconds to keep thread alive. Must be >=0 + */ + public void setWorkerTimeout(int workerTimeout) + { + if (workerTimeout < 0) + { + throw new IllegalArgumentException("Must be >= 0"); + } + this.workerTimeout = workerTimeout; + } + + public ConnectFuture connect(SocketAddress address, IoHandler handler, IoServiceConfig config) + { + return connect(address, null, handler, config); + } + + public ConnectFuture connect(SocketAddress address, SocketAddress localAddress, + IoHandler handler, IoServiceConfig config) + { + /** Changes here from the Mina OpenSocketConnector. + * Ignoreing all address as they are not needed */ + + if (handler == null) + { + throw new NullPointerException("handler"); + } + + + if (config == null) + { + config = getDefaultConfig(); + } + + if (_openSocket == null) + { + throw new IllegalArgumentException("Specifed Socket not active"); + } + + boolean success = false; + + try + { + DefaultConnectFuture future = new DefaultConnectFuture(); + newSession(_openSocket, handler, config, future); + success = true; + return future; + } + catch (IOException e) + { + return DefaultConnectFuture.newFailedFuture(e); + } + finally + { + if (!success && _openSocket != null) + { + try + { + _openSocket.close(); + } + catch (IOException e) + { + ExceptionMonitor.getInstance().exceptionCaught(e); + } + } + } + } + + public IoServiceConfig getDefaultConfig() + { + return defaultConfig; + } + + /** + * Sets the config this connector will use by default. + * + * @param defaultConfig the default config. + * + * @throws NullPointerException if the specified value is <code>null</code>. + */ + public void setDefaultConfig(SocketConnectorConfig defaultConfig) + { + if (defaultConfig == null) + { + throw new NullPointerException("defaultConfig"); + } + this.defaultConfig = defaultConfig; + } + + private synchronized void startupWorker() throws IOException + { + if (worker == null) + { + selector = Selector.open(); + worker = new Worker(); + executor.execute(new NamePreservingRunnable(worker)); + } + } + + private void registerNew() + { + if (connectQueue.isEmpty()) + { + return; + } + + for (; ;) + { + ConnectionRequest req; + synchronized (connectQueue) + { + req = (ConnectionRequest) connectQueue.pop(); + } + + if (req == null) + { + break; + } + + SocketChannel ch = req.channel; + try + { + ch.register(selector, SelectionKey.OP_CONNECT, req); + } + catch (IOException e) + { + req.setException(e); + } + } + } + + private void processSessions(Set keys) + { + Iterator it = keys.iterator(); + + while (it.hasNext()) + { + SelectionKey key = (SelectionKey) it.next(); + + if (!key.isConnectable()) + { + continue; + } + + SocketChannel ch = (SocketChannel) key.channel(); + ConnectionRequest entry = (ConnectionRequest) key.attachment(); + + boolean success = false; + try + { + ch.finishConnect(); + newSession(ch, entry.handler, entry.config, entry); + success = true; + } + catch (Throwable e) + { + entry.setException(e); + } + finally + { + key.cancel(); + if (!success) + { + try + { + ch.close(); + } + catch (IOException e) + { + ExceptionMonitor.getInstance().exceptionCaught(e); + } + } + } + } + + keys.clear(); + } + + private void processTimedOutSessions(Set keys) + { + long currentTime = System.currentTimeMillis(); + Iterator it = keys.iterator(); + + while (it.hasNext()) + { + SelectionKey key = (SelectionKey) it.next(); + + if (!key.isValid()) + { + continue; + } + + ConnectionRequest entry = (ConnectionRequest) key.attachment(); + + if (currentTime >= entry.deadline) + { + entry.setException(new ConnectException()); + try + { + key.channel().close(); + } + catch (IOException e) + { + ExceptionMonitor.getInstance().exceptionCaught(e); + } + finally + { + key.cancel(); + } + } + } + } + + private void newSession(Socket socket, IoHandler handler, IoServiceConfig config, ConnectFuture connectFuture) + throws IOException + { + SocketSessionImpl session = new SocketSessionImpl(this, + nextProcessor(), + getListeners(), + config, + socket.getChannel(), + handler, + socket.getRemoteSocketAddress()); + + newSession(session, config, connectFuture); + } + + private void newSession(SocketChannel ch, IoHandler handler, IoServiceConfig config, ConnectFuture connectFuture) + throws IOException + + { + SocketSessionImpl session = new SocketSessionImpl(this, + nextProcessor(), + getListeners(), + config, + ch, + handler, + ch.socket().getRemoteSocketAddress()); + + newSession(session, config, connectFuture); + } + + private void newSession(SocketSessionImpl session, IoServiceConfig config, ConnectFuture connectFuture) + throws IOException + { + try + { + getFilterChainBuilder().buildFilterChain(session.getFilterChain()); + config.getFilterChainBuilder().buildFilterChain(session.getFilterChain()); + config.getThreadModel().buildFilterChain(session.getFilterChain()); + } + catch (Throwable e) + { + throw (IOException) new IOException("Failed to create a session.").initCause(e); + } + session.getIoProcessor().addNew(session); + connectFuture.setSession(session); + } + + private SocketIoProcessor nextProcessor() + { + return ioProcessors[processorDistributor++ % processorCount]; + } + + public void setOpenSocket(Socket openSocket) + { + _openSocket = openSocket; + } + + private class Worker implements Runnable + { + private long lastActive = System.currentTimeMillis(); + + public void run() + { + Thread.currentThread().setName(ExistingSocketConnector.this.threadName); + + for (; ;) + { + try + { + int nKeys = selector.select(1000); + + registerNew(); + + if (nKeys > 0) + { + processSessions(selector.selectedKeys()); + } + + processTimedOutSessions(selector.keys()); + + if (selector.keys().isEmpty()) + { + if (System.currentTimeMillis() - lastActive > workerTimeout * 1000L) + { + synchronized (lock) + { + if (selector.keys().isEmpty() && + connectQueue.isEmpty()) + { + worker = null; + try + { + selector.close(); + } + catch (IOException e) + { + ExceptionMonitor.getInstance().exceptionCaught(e); + } + finally + { + selector = null; + } + break; + } + } + } + } + else + { + lastActive = System.currentTimeMillis(); + } + } + catch (IOException e) + { + ExceptionMonitor.getInstance().exceptionCaught(e); + + try + { + Thread.sleep(1000); + } + catch (InterruptedException e1) + { + ExceptionMonitor.getInstance().exceptionCaught(e1); + } + } + } + } + } + + private class ConnectionRequest extends DefaultConnectFuture + { + private final SocketChannel channel; + private final long deadline; + private final IoHandler handler; + private final IoServiceConfig config; + + private ConnectionRequest(SocketChannel channel, IoHandler handler, IoServiceConfig config) + { + this.channel = channel; + long timeout; + if (config instanceof IoConnectorConfig) + { + timeout = ((IoConnectorConfig) config).getConnectTimeoutMillis(); + } + else + { + timeout = ((IoConnectorConfig) getDefaultConfig()).getConnectTimeoutMillis(); + } + this.deadline = System.currentTimeMillis() + timeout; + this.handler = handler; + this.config = config; + } + } +} 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 index 999b22299c..a201f7d61e 100644 --- a/java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java +++ b/java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java @@ -72,17 +72,6 @@ public class AMQAnyDestination extends AMQDestination implements Queue, Topic public String getTopicName() throws JMSException { - if (getRoutingKey() != null) - { - return getRoutingKey().asString(); - } - else if (getSubject() != null) - { - return getSubject(); - } - else - { - return null; - } + return super.getRoutingKey().toString(); } } 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 c0d4d8a893..ee52cd50af 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,7 +26,7 @@ import java.util.HashMap; import java.util.Map; import org.apache.qpid.jms.BrokerDetails; -import org.apache.qpid.transport.ConnectionSettings; +import org.apache.qpid.jms.ConnectionURL; import org.apache.qpid.url.URLHelper; import org.apache.qpid.url.URLSyntaxException; @@ -38,6 +38,8 @@ public class AMQBrokerDetails implements BrokerDetails private Map<String, String> _options = new HashMap<String, String>(); + private SSLConfiguration _sslConfiguration; + public AMQBrokerDetails(){} public AMQBrokerDetails(String url) throws URLSyntaxException @@ -54,7 +56,9 @@ public class AMQBrokerDetails implements BrokerDetails if (transport != null) { //todo this list of valid transports should be enumerated somewhere - if (!(transport.equalsIgnoreCase(BrokerDetails.TCP))) + if ((!(transport.equalsIgnoreCase(BrokerDetails.VM) || + transport.equalsIgnoreCase(BrokerDetails.TCP) || + transport.equalsIgnoreCase(BrokerDetails.SOCKET)))) { if (transport.equalsIgnoreCase("localhost")) { @@ -101,21 +105,6 @@ public class AMQBrokerDetails implements BrokerDetails if (host == null) { host = ""; - - String auth = connection.getAuthority(); - if (auth != null) - { - // contains both host & port myhost:5672 - if (auth.contains(":")) - { - host = auth.substring(0,auth.indexOf(":")); - } - else - { - host = auth; - } - } - } setHost(host); @@ -178,7 +167,10 @@ public class AMQBrokerDetails implements BrokerDetails } else { - setPort(port); + if (!_transport.equalsIgnoreCase(SOCKET)) + { + setPort(port); + } } String queryString = connection.getQuery(); @@ -198,10 +190,11 @@ public class AMQBrokerDetails implements BrokerDetails } } - public AMQBrokerDetails(String host, int port) + public AMQBrokerDetails(String host, int port, SSLConfiguration sslConfiguration) { _host = host; _port = port; + _sslConfiguration = sslConfiguration; } public String getHost() @@ -277,15 +270,33 @@ public class AMQBrokerDetails implements BrokerDetails setProperty(OPTIONS_CONNECT_TIMEOUT, Long.toString(timeout)); } + public SSLConfiguration getSSLConfiguration() + { + return _sslConfiguration; + } + + public void setSSLConfiguration(SSLConfiguration sslConfig) + { + _sslConfiguration = sslConfig; + } + public String toString() { StringBuffer sb = new StringBuffer(); sb.append(_transport); sb.append("://"); - sb.append(_host); - sb.append(':'); - sb.append(_port); + + if (!(_transport.equalsIgnoreCase(VM))) + { + sb.append(_host); + } + + if (!(_transport.equalsIgnoreCase(SOCKET))) + { + sb.append(':'); + sb.append(_port); + } sb.append(printOptionsURL()); @@ -303,8 +314,9 @@ public class AMQBrokerDetails implements BrokerDetails return _host.equalsIgnoreCase(bd.getHost()) && (_port == bd.getPort()) && - _transport.equalsIgnoreCase(bd.getTransport()); - //TODO do we need to compare all the options as well? + _transport.equalsIgnoreCase(bd.getTransport()) && + compareSSLConfigurations(bd.getSSLConfiguration()); + //todo do we need to compare all the options as well? } @Override @@ -345,6 +357,24 @@ public class AMQBrokerDetails implements BrokerDetails return optionsURL.toString(); } + // Do we need to do a more in-depth comparison? + private boolean compareSSLConfigurations(SSLConfiguration other) + { + boolean retval = false; + if (_sslConfiguration == null && + other == null) + { + retval = true; + } + else if (_sslConfiguration != null && + other != null) + { + retval = true; + } + + return retval; + } + public static String checkTransport(String broker) { if ((!broker.contains("://"))) @@ -366,82 +396,4 @@ public class AMQBrokerDetails implements BrokerDetails { _options = props; } - - public ConnectionSettings buildConnectionSettings() - { - ConnectionSettings conSettings = new ConnectionSettings(); - - conSettings.setHost(getHost()); - conSettings.setPort(getPort()); - - // ------------ sasl options --------------- - if (getProperty(BrokerDetails.OPTIONS_SASL_MECHS) != null) - { - conSettings.setSaslMechs( - getProperty(BrokerDetails.OPTIONS_SASL_MECHS)); - } - - // Sun SASL Kerberos client uses the - // protocol + servername as the service key. - - if (getProperty(BrokerDetails.OPTIONS_SASL_PROTOCOL_NAME) != null) - { - conSettings.setSaslProtocol( - getProperty(BrokerDetails.OPTIONS_SASL_PROTOCOL_NAME)); - } - - - if (getProperty(BrokerDetails.OPTIONS_SASL_SERVER_NAME) != null) - { - conSettings.setSaslServerName( - getProperty(BrokerDetails.OPTIONS_SASL_SERVER_NAME)); - } - - conSettings.setUseSASLEncryption( - getBooleanProperty(BrokerDetails.OPTIONS_SASL_ENCRYPTION)); - - // ------------- ssl options --------------------- - conSettings.setUseSSL(getBooleanProperty(BrokerDetails.OPTIONS_SSL)); - - if (getProperty(BrokerDetails.OPTIONS_TRUST_STORE) != null) - { - conSettings.setTrustStorePath( - getProperty(BrokerDetails.OPTIONS_TRUST_STORE)); - } - - if (getProperty(BrokerDetails.OPTIONS_TRUST_STORE_PASSWORD) != null) - { - conSettings.setTrustStorePassword( - getProperty(BrokerDetails.OPTIONS_TRUST_STORE_PASSWORD)); - } - - if (getProperty(BrokerDetails.OPTIONS_KEY_STORE) != null) - { - conSettings.setKeyStorePath( - getProperty(BrokerDetails.OPTIONS_KEY_STORE)); - } - - if (getProperty(BrokerDetails.OPTIONS_KEY_STORE_PASSWORD) != null) - { - conSettings.setKeyStorePassword( - getProperty(BrokerDetails.OPTIONS_KEY_STORE_PASSWORD)); - } - - if (getProperty(BrokerDetails.OPTIONS_SSL_CERT_ALIAS) != null) - { - conSettings.setCertAlias( - getProperty(BrokerDetails.OPTIONS_SSL_CERT_ALIAS)); - } - // ---------------------------- - - conSettings.setVerifyHostname(getBooleanProperty(BrokerDetails.OPTIONS_SSL_VERIFY_HOSTNAME)); - - if (getProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY) != null) - { - conSettings.setTcpNodelay( - getBooleanProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY)); - } - - return conSettings; - } } 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 f15af72407..ab59fee020 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 @@ -111,7 +111,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect /** Maps from session id (Integer) to AMQSession instance */ private final ChannelToSessionMap _sessions = new ChannelToSessionMap(); - private final String _clientName; + private String _clientName; /** The user name to use for authentication */ private String _username; @@ -126,7 +126,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect private ConnectionListener _connectionListener; - private final ConnectionURL _connectionURL; + private ConnectionURL _connectionURL; /** * Whether this connection is started, i.e. whether messages are flowing to consumers. It has no meaning for message @@ -147,6 +147,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect */ private QpidConnectionMetaData _connectionMetaData; + /** Configuration info for SSL */ + private SSLConfiguration _sslConfiguration; + private AMQShortString _defaultTopicExchangeName = ExchangeDefaults.TOPIC_EXCHANGE_NAME; private AMQShortString _defaultQueueExchangeName = ExchangeDefaults.DIRECT_EXCHANGE_NAME; private AMQShortString _temporaryTopicExchangeName = ExchangeDefaults.TOPIC_EXCHANGE_NAME; @@ -170,8 +173,8 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect //Indicates the sync publish options (persistent|all) //By default it's async publish private String _syncPublish = ""; - - // Indicates whether to use the old map message format or the + + // Indicates whether to use the old map message format or the // new amqp-0-10 encoded format. private boolean _useLegacyMapMessageFormat; @@ -191,33 +194,69 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect this(new AMQConnectionURL( ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + ((clientName == null) ? "" : clientName) + "/" + virtualHost + "?brokerlist='" - + AMQBrokerDetails.checkTransport(broker) + "'")); + + AMQBrokerDetails.checkTransport(broker) + "'"), null); + } + + /** + * @param broker brokerdetails + * @param username username + * @param password password + * @param clientName clientid + * @param virtualHost virtualhost + * + * @throws AMQException + * @throws URLSyntaxException + */ + public AMQConnection(String broker, String username, String password, String clientName, String virtualHost, + SSLConfiguration sslConfig) throws AMQException, URLSyntaxException + { + this(new AMQConnectionURL( + ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + + ((clientName == null) ? "" : clientName) + "/" + virtualHost + "?brokerlist='" + + AMQBrokerDetails.checkTransport(broker) + "'"), sslConfig); } public AMQConnection(String host, int port, String username, String password, String clientName, String virtualHost) throws AMQException, URLSyntaxException { + this(host, port, false, username, password, clientName, virtualHost, null); + } + + public AMQConnection(String host, int port, String username, String password, String clientName, String virtualHost, + SSLConfiguration sslConfig) throws AMQException, URLSyntaxException + { + this(host, port, false, username, password, clientName, virtualHost, sslConfig); + } + + public AMQConnection(String host, int port, boolean useSSL, String username, String password, String clientName, + String virtualHost, SSLConfiguration sslConfig) throws AMQException, URLSyntaxException + { this(new AMQConnectionURL( - ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" - + ((clientName == null) ? "" : clientName) + virtualHost + "?brokerlist='tcp://" + host + ":" + port + "'")); + useSSL + ? (ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + + ((clientName == null) ? "" : clientName) + virtualHost + "?brokerlist='tcp://" + host + ":" + port + + "'" + "," + BrokerDetails.OPTIONS_SSL + "='true'") + : (ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + + ((clientName == null) ? "" : clientName) + virtualHost + "?brokerlist='tcp://" + host + ":" + port + + "'" + "," + BrokerDetails.OPTIONS_SSL + "='false'")), sslConfig); } public AMQConnection(String connection) throws AMQException, URLSyntaxException { - this(new AMQConnectionURL(connection)); + this(new AMQConnectionURL(connection), null); + } + + public AMQConnection(String connection, SSLConfiguration sslConfig) throws AMQException, URLSyntaxException + { + this(new AMQConnectionURL(connection), sslConfig); } /** * @todo Some horrible stuff going on here with setting exceptions to be non-null to detect if an exception * was thrown during the connection! Intention not clear. Use a flag anyway, not exceptions... Will fix soon. */ - public AMQConnection(ConnectionURL connectionURL) throws AMQException + public AMQConnection(ConnectionURL connectionURL, SSLConfiguration sslConfig) throws AMQException { - if (connectionURL == null) - { - throw new IllegalArgumentException("Connection must be specified"); - } - // set this connection maxPrefetch if (connectionURL.getOption(ConnectionURL.OPTIONS_MAXPREFETCH) != null) { @@ -225,7 +264,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } else { - // use the default value set for all connections + // use the defaul value set for all connections _maxPrefetch = Integer.parseInt(System.getProperties().getProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, ClientProperties.MAX_PREFETCH_DEFAULT)); } @@ -239,7 +278,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } else { - // use the default value set for all connections + // use the defaul value set for all connections _syncPersistence = Boolean.getBoolean(ClientProperties.SYNC_PERSISTENT_PROP_NAME); if (_syncPersistence) { @@ -254,7 +293,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } else { - // use the default value set for all connections + // use the defaul value set for all connections _syncAck = Boolean.getBoolean(ClientProperties.SYNC_ACK_PROP_NAME); } @@ -267,7 +306,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect // use the default value set for all connections _syncPublish = System.getProperty((ClientProperties.SYNC_PUBLISH_PROP_NAME),_syncPublish); } - + if (connectionURL.getOption(ConnectionURL.OPTIONS_USE_LEGACY_MAP_MESSAGE_FORMAT) != null) { _useLegacyMapMessageFormat = Boolean.parseBoolean( @@ -278,16 +317,16 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect // use the default value set for all connections _useLegacyMapMessageFormat = Boolean.getBoolean(ClientProperties.USE_LEGACY_MAP_MESSAGE_FORMAT); } - + String amqpVersion = System.getProperty((ClientProperties.AMQP_VERSION), "0-10"); _logger.debug("AMQP version " + amqpVersion); - + _failoverPolicy = new FailoverPolicy(connectionURL, this); BrokerDetails brokerDetails = _failoverPolicy.getCurrentBrokerDetails(); - if ("0-8".equals(amqpVersion)) + 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); @@ -306,6 +345,12 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect _logger.info("Connection:" + connectionURL); } + _sslConfiguration = sslConfig; + if (connectionURL == null) + { + throw new IllegalArgumentException("Connection must be specified"); + } + _connectionURL = connectionURL; _clientName = connectionURL.getClientName(); @@ -373,7 +418,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect brokerDetails = _failoverPolicy.getNextBrokerDetails(); } } - verifyClientID(); if (_logger.isDebugEnabled()) { @@ -460,7 +504,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); - //Update our session to use this new protocol version + //Update our session to use this new protocol version _protocolHandler.getProtocolSession().setProtocolVersion(_delegate.getProtocolVersion()); } @@ -491,6 +535,14 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } } + protected AMQConnection(String username, String password, String clientName, String virtualHost) + { + _clientName = clientName; + _username = username; + _password = password; + setVirtualHost(virtualHost); + } + private void setVirtualHost(String virtualHost) { if (virtualHost != null && virtualHost.startsWith("/")) @@ -503,7 +555,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect public boolean attemptReconnection(String host, int port) { - BrokerDetails bd = new AMQBrokerDetails(host, port); + BrokerDetails bd = new AMQBrokerDetails(host, port, _sslConfiguration); _failoverPolicy.setBroker(bd); @@ -644,6 +696,20 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } } + private void reopenChannel(int channelId, int prefetchHigh, int prefetchLow, boolean transacted) + throws AMQException, FailoverException + { + try + { + createChannelOverWire(channelId, prefetchHigh, prefetchLow, transacted); + } + catch (AMQException e) + { + deregisterSession(channelId); + throw new AMQException(null, "Error reopening channel " + channelId + " after failover: " + e, e); + } + } + public void setFailoverPolicy(FailoverPolicy policy) { _failoverPolicy = policy; @@ -1030,7 +1096,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { _username = id; } - + public String getPassword() { return _password; @@ -1183,7 +1249,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect if (code != null) { - je = new JMSException("Exception thrown against " + toString() + ": " + cause, Integer.toString(code.getCode())); + je = new JMSException(Integer.toString(code.getCode()), "Exception thrown against " + toString() + ": " + cause); } else { @@ -1206,7 +1272,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { je.setLinkedException((Exception) cause); } - + je.initCause(cause); } @@ -1239,7 +1305,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { _logger.info("Not a hard-error connection not closing: " + cause); } - + // deliver the exception if there is a listener if (_exceptionListener != null) { @@ -1249,7 +1315,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { _logger.error("Throwable Received but no listener set: " + cause); } - + // if we are closing the connection, close sessions first if (closer) { @@ -1306,20 +1372,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect return buf.toString(); } - /** - * Returns connection url. - * @return connection url - */ - public ConnectionURL getConnectionURL() - { - return _connectionURL; - } - - /** - * Returns stringified connection url. This url is suitable only for display - * as {@link AMQConnectionURL#toString()} converts any password to asterisks. - * @return connection url - */ public String toURL() { return _connectionURL.toString(); @@ -1331,6 +1383,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect AMQConnectionFactory.class.getName(), null); // factory location } + public SSLConfiguration getSSLConfiguration() + { + return _sslConfiguration; + } + public AMQShortString getDefaultTopicExchangeName() { return _defaultTopicExchangeName; @@ -1385,18 +1442,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { return _delegate.getProtocolVersion(); } - - public String getBrokerUUID() - { - if(getProtocolVersion().equals(ProtocolVersion.v0_10)) - { - return ((AMQConnectionDelegate_0_10)_delegate).getUUID(); - } - else - { - return null; - } - } + public boolean isFailingOver() { return (_protocolHandler.getFailoverLatch() != null); @@ -1439,27 +1485,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { return _sessions.getNextChannelId(); } - + public boolean isUseLegacyMapMessageFormat() { return _useLegacyMapMessageFormat; } - - private void verifyClientID() throws AMQException - { - if (Boolean.getBoolean(ClientProperties.QPID_VERIFY_CLIENT_ID)) - { - try - { - if (!_delegate.verifyClientID()) - { - throw new AMQException(AMQConstant.ALREADY_EXISTS,"ClientID must be unique"); - } - } - catch(JMSException e) - { - throw new AMQException(e.getMessage(),e); - } - } - } } 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 8768f93c8c..9560bd5c7c 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 @@ -57,12 +57,10 @@ public interface AMQConnectionDelegate void closeConnection(long timeout) throws JMSException, AMQException; <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E; - + int getMaxChannelID(); int getMinChannelID(); ProtocolVersion getProtocolVersion(); - - boolean verifyClientID() throws JMSException, AMQException; } 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 0ed3db6ecb..b0bd8f8e97 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,6 +1,6 @@ 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 @@ -8,16 +8,16 @@ package org.apache.qpid.client; * 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. - * + * */ @@ -35,7 +35,6 @@ 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.client.transport.ClientConnectionDelegate; import org.apache.qpid.configuration.ClientProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.jms.BrokerDetails; @@ -44,13 +43,10 @@ import org.apache.qpid.jms.Session; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.ConnectionClose; -import org.apache.qpid.transport.ConnectionCloseCode; import org.apache.qpid.transport.ConnectionException; import org.apache.qpid.transport.ConnectionListener; import org.apache.qpid.transport.ConnectionSettings; import org.apache.qpid.transport.ProtocolVersionException; -import org.apache.qpid.transport.SessionDetachCode; -import org.apache.qpid.transport.SessionException; import org.apache.qpid.transport.TransportException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,10 +59,6 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec private static final Logger _logger = LoggerFactory.getLogger(AMQConnectionDelegate_0_10.class); /** - * The name of the UUID property - */ - private static final String UUID_NAME = "qpid.federation_tag"; - /** * The AMQ Connection. */ private AMQConnection _conn; @@ -77,12 +69,6 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec org.apache.qpid.transport.Connection _qpidConnection; private ConnectionException exception = null; - static - { - // Register any configured SASL client factories. - org.apache.qpid.client.security.DynamicSaslRegistrar.registerSaslProviders(); - } - //--- constructor public AMQConnectionDelegate_0_10(AMQConnection conn) { @@ -94,14 +80,7 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec /** * create a Session and start it if required. */ - public Session createSession(boolean transacted, int acknowledgeMode, int prefetchHigh, int prefetchLow) - throws JMSException - { - return createSession(transacted,acknowledgeMode,prefetchHigh,prefetchLow,null); - } - - public Session createSession(boolean transacted, int acknowledgeMode, int prefetchHigh, int prefetchLow, String name) throws JMSException { _conn.checkNotClosed(); @@ -116,7 +95,7 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec try { session = new AMQSession_0_10(_qpidConnection, _conn, channelId, transacted, acknowledgeMode, prefetchHigh, - prefetchLow,name); + prefetchLow); _conn.registerSession(channelId, session); if (_conn._started) { @@ -194,8 +173,8 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec + _conn.getPassword()); } - ConnectionSettings conSettings = retriveConnectionSettings(brokerDetail); - _qpidConnection.setConnectionDelegate(new ClientConnectionDelegate(conSettings, _conn.getConnectionURL())); + ConnectionSettings conSettings = new ConnectionSettings(); + retriveConnectionSettings(conSettings,brokerDetail); _qpidConnection.connect(conSettings); _conn._connected = true; @@ -232,8 +211,6 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec public void resubscribeSessions() throws JMSException, AMQException, FailoverException { - _logger.info("Resuming connection"); - getQpidConnection().resume(); List<AMQSession> sessions = new ArrayList<AMQSession>(_conn.getSessions().values()); _logger.info(String.format("Resubscribing sessions = %s sessions.size=%d", sessions, sessions.size())); for (AMQSession s : sessions) @@ -277,10 +254,10 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec } ConnectionClose close = exc.getClose(); - if (close == null || close.getReplyCode() == ConnectionCloseCode.CONNECTION_FORCED) + if (close == null) { _conn.getProtocolHandler().setFailoverLatch(new CountDownLatch(1)); - + try { if (_conn.firePreFailover(false) && _conn.attemptReconnection()) @@ -349,20 +326,78 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec { return ProtocolVersion.v0_10; } - - public String getUUID() - { - return (String)_qpidConnection.getServerProperties().get(UUID_NAME); - } - - private ConnectionSettings retriveConnectionSettings(BrokerDetails brokerDetail) + + private void retriveConnectionSettings(ConnectionSettings conSettings, BrokerDetails brokerDetail) { - ConnectionSettings conSettings = brokerDetail.buildConnectionSettings(); + conSettings.setHost(brokerDetail.getHost()); + conSettings.setPort(brokerDetail.getPort()); conSettings.setVhost(_conn.getVirtualHost()); conSettings.setUsername(_conn.getUsername()); conSettings.setPassword(_conn.getPassword()); + + // ------------ sasl options --------------- + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_MECHS) != null) + { + conSettings.setSaslMechs( + brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_MECHS)); + } + // Sun SASL Kerberos client uses the + // protocol + servername as the service key. + + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_PROTOCOL_NAME) != null) + { + conSettings.setSaslProtocol( + brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_PROTOCOL_NAME)); + } + + + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_SERVER_NAME) != null) + { + conSettings.setSaslServerName( + brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_SERVER_NAME)); + } + + conSettings.setUseSASLEncryption( + brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SASL_ENCRYPTION)); + + // ------------- ssl options --------------------- + conSettings.setUseSSL(brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SSL)); + + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_TRUST_STORE) != null) + { + conSettings.setTrustStorePath( + brokerDetail.getProperty(BrokerDetails.OPTIONS_TRUST_STORE)); + } + + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_TRUST_STORE_PASSWORD) != null) + { + conSettings.setTrustStorePassword( + brokerDetail.getProperty(BrokerDetails.OPTIONS_TRUST_STORE_PASSWORD)); + } + + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_KEY_STORE) != null) + { + conSettings.setKeyStorePath( + brokerDetail.getProperty(BrokerDetails.OPTIONS_KEY_STORE)); + } + + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_KEY_STORE_PASSWORD) != null) + { + conSettings.setKeyStorePassword( + brokerDetail.getProperty(BrokerDetails.OPTIONS_KEY_STORE_PASSWORD)); + } + + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_SSL_CERT_ALIAS) != null) + { + conSettings.setCertAlias( + brokerDetail.getProperty(BrokerDetails.OPTIONS_SSL_CERT_ALIAS)); + } + // ---------------------------- + + conSettings.setVerifyHostname(brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SSL_VERIFY_HOSTNAME)); + // Pass client name from connection URL Map<String, Object> clientProps = new HashMap<String, Object>(); try @@ -374,12 +409,16 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec { // Ignore } - + + if (brokerDetail.getProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY) != null) + { + conSettings.setTcpNodelay( + brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY)); + } + conSettings.setHeartbeatInterval(getHeartbeatInterval(brokerDetail)); - - return conSettings; } - + // The idle_timeout prop is in milisecs while // the new heartbeat prop is in secs private int getHeartbeatInterval(BrokerDetails brokerDetail) @@ -394,7 +433,7 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec { heartbeat = Integer.parseInt(brokerDetail.getProperty(BrokerDetails.OPTIONS_HEARTBEAT)); } - else if (Integer.getInteger(ClientProperties.IDLE_TIMEOUT_PROP_NAME) != null) + else if (Integer.getInteger(ClientProperties.IDLE_TIMEOUT_PROP_NAME) != null) { heartbeat = Integer.getInteger(ClientProperties.IDLE_TIMEOUT_PROP_NAME)/1000; _logger.warn("JVM arg -Didle_timeout=<mili_secs> is deprecated, please use -Dqpid.heartbeat=<secs>"); @@ -402,37 +441,12 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec else { heartbeat = Integer.getInteger(ClientProperties.HEARTBEAT,ClientProperties.HEARTBEAT_DEFAULT); - } + } return heartbeat; } - + protected org.apache.qpid.transport.Connection getQpidConnection() { return _qpidConnection; } - - public boolean verifyClientID() throws JMSException, AMQException - { - int prefetch = (int)_conn.getMaxPrefetch(); - AMQSession_0_10 ssn = (AMQSession_0_10)createSession(false, 1,prefetch,prefetch,_conn.getClientID()); - org.apache.qpid.transport.Session ssn_0_10 = ssn.getQpidSession(); - try - { - ssn_0_10.awaitOpen(); - } - catch(SessionException se) - { - //if due to non unique client id for user return false, otherwise wrap and re-throw. - if (ssn_0_10.getDetachCode() != null && - ssn_0_10.getDetachCode() == SessionDetachCode.SESSION_BUSY) - { - return false; - } - else - { - throw new AMQException(AMQConstant.INTERNAL_ERROR, "Unexpected SessionException thrown while awaiting session opening", se); - } - } - return true; - } } 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 b1a22155d6..40b332d216 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 @@ -23,8 +23,6 @@ package org.apache.qpid.client; import java.io.IOException; import java.net.ConnectException; import java.nio.channels.UnresolvedAddressException; -import java.security.GeneralSecurityException; -import java.security.Security; import java.text.MessageFormat; import java.util.ArrayList; import java.util.EnumSet; @@ -33,17 +31,15 @@ import java.util.Set; import javax.jms.JMSException; import javax.jms.XASession; -import javax.net.ssl.SSLContext; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQTimeoutException; import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.failover.FailoverProtectedOperation; import org.apache.qpid.client.failover.FailoverRetrySupport; import org.apache.qpid.client.protocol.AMQProtocolSession; import org.apache.qpid.client.state.AMQState; -import org.apache.qpid.client.state.AMQStateManager; import org.apache.qpid.client.state.StateWaiter; +import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.framing.BasicQosBody; import org.apache.qpid.framing.BasicQosOkBody; import org.apache.qpid.framing.ChannelOpenBody; @@ -53,13 +49,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.ssl.SSLContextFactory; -import org.apache.qpid.transport.ConnectionSettings; -import org.apache.qpid.transport.network.NetworkConnection; -import org.apache.qpid.transport.network.OutgoingNetworkTransport; -import org.apache.qpid.transport.network.Transport; -import org.apache.qpid.transport.network.security.SecurityLayer; -import org.apache.qpid.transport.network.security.SecurityLayerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,30 +60,8 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate public void closeConnection(long timeout) throws JMSException, AMQException { - final AMQStateManager stateManager = _conn.getProtocolHandler().getStateManager(); - final AMQState currentState = stateManager.getCurrentState(); + _conn.getProtocolHandler().closeConnection(timeout); - if (currentState.equals(AMQState.CONNECTION_CLOSED)) - { - _logger.debug("Connection already closed."); - } - else if (currentState.equals(AMQState.CONNECTION_CLOSING)) - { - _logger.debug("Connection already closing, awaiting closed state."); - final StateWaiter closeWaiter = new StateWaiter(stateManager, currentState, EnumSet.of(AMQState.CONNECTION_CLOSED)); - try - { - closeWaiter.await(timeout); - } - catch (AMQTimeoutException te) - { - throw new AMQTimeoutException("Close did not complete in timely fashion", te); - } - } - else - { - _conn.getProtocolHandler().closeConnection(timeout); - } } public AMQConnectionDelegate_8_0(AMQConnection conn) @@ -122,34 +89,15 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate StateWaiter waiter = _conn._protocolHandler.createWaiter(openOrClosedStates); - ConnectionSettings settings = brokerDetail.buildConnectionSettings(); - settings.setProtocol(brokerDetail.getTransport()); - - SSLContext sslContext = null; - if (settings.isUseSSL()) + // TODO: use system property thingy for this + if (System.getProperty("UseTransportIo", "false").equals("false")) { - try - { - sslContext = SSLContextFactory.buildClientContext( - settings.getTrustStorePath(), - settings.getTrustStorePassword(), - settings.getTrustStoreCertType(), - settings.getKeyStorePath(), - settings.getKeyStorePassword(), - settings.getKeyStoreCertType(), - settings.getCertAlias()); - } - catch (GeneralSecurityException e) - { - throw new AMQException("Unable to create SSLContext: " + e.getMessage(), e); - } + TransportConnection.getInstance(brokerDetail).connect(_conn._protocolHandler, brokerDetail); + } + else + { + _conn.getProtocolHandler().createIoTransportSession(brokerDetail); } - - SecurityLayer securityLayer = SecurityLayerFactory.newInstance(settings); - - OutgoingNetworkTransport transport = Transport.getOutgoingTransportInstance(getProtocolVersion()); - NetworkConnection network = transport.connect(settings, securityLayer.receiver(_conn._protocolHandler), sslContext); - _conn._protocolHandler.setNetworkConnection(network, securityLayer.sender(network.getSender())); _conn._protocolHandler.getProtocolSession().init(); // this blocks until the connection has been set up or when an error // has prevented the connection being set up @@ -374,9 +322,4 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate { return ProtocolVersion.v8_0; } - - public boolean verifyClientID() throws JMSException - { - return true; - } } 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 f0c003e02a..ec4c668d7e 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 @@ -44,34 +44,210 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF ObjectFactory, Referenceable, XATopicConnectionFactory, XAQueueConnectionFactory, XAConnectionFactory { - private final ConnectionURL _connectionDetails; + private String _host; + private int _port; + private String _defaultUsername; + private String _defaultPassword; + private String _virtualPath; - public AMQConnectionFactory(final String url) throws URLSyntaxException + private ConnectionURL _connectionDetails; + private SSLConfiguration _sslConfig; + + public AMQConnectionFactory() { - if (url == null) - { - throw new IllegalArgumentException("url cannot be null"); - } + } + /** + * This is the Only constructor used! + * It is used form the context and from the JNDI objects. + */ + public AMQConnectionFactory(String url) throws URLSyntaxException + { _connectionDetails = new AMQConnectionURL(url); } + /** + * This constructor is never used! + */ public AMQConnectionFactory(ConnectionURL url) { - if (url == null) + _connectionDetails = url; + } + + /** + * This constructor is never used! + */ + public AMQConnectionFactory(String broker, String username, String password, String clientName, String virtualHost) + throws URLSyntaxException + { + this(new AMQConnectionURL( + ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + clientName + "/" + virtualHost + "?brokerlist='" + broker + "'")); + } + + /** + * This constructor is never used! + */ + public AMQConnectionFactory(String host, int port, String virtualPath) + { + this(host, port, "guest", "guest", virtualPath); + } + + /** + * This constructor is never used! + */ + public AMQConnectionFactory(String host, int port, String defaultUsername, String defaultPassword, + String virtualPath) + { + _host = host; + _port = port; + _defaultUsername = defaultUsername; + _defaultPassword = defaultPassword; + _virtualPath = virtualPath; + +//todo when setting Host/Port has been resolved then we can use this otherwise those methods won't work with the following line. +// _connectionDetails = new AMQConnectionURL( +// ConnectionURL.AMQ_PROTOCOL + "://" + +// _defaultUsername + ":" + _defaultPassword + "@" + +// virtualPath + "?brokerlist='tcp://" + host + ":" + port + "'"); + } + + /** + * @return The _defaultPassword. + */ + public final String getDefaultPassword(String password) + { + if (_connectionDetails != null) { - throw new IllegalArgumentException("url cannot be null"); + return _connectionDetails.getPassword(); } + else + { + return _defaultPassword; + } + } - _connectionDetails = url; + /** + * @param password The _defaultPassword to set. + */ + public final void setDefaultPassword(String password) + { + if (_connectionDetails != null) + { + _connectionDetails.setPassword(password); + } + _defaultPassword = password; + } + + /** + * Getter for SSLConfiguration + * + * @return SSLConfiguration if set, otherwise null + */ + public final SSLConfiguration getSSLConfiguration() + { + return _sslConfig; + } + + /** + * Setter for SSLConfiguration + * + * @param sslConfig config to store + */ + public final void setSSLConfiguration(SSLConfiguration sslConfig) + { + _sslConfig = sslConfig; + } + + /** + * @return The _defaultPassword. + */ + public final String getDefaultUsername(String password) + { + if (_connectionDetails != null) + { + return _connectionDetails.getUsername(); + } + else + { + return _defaultUsername; + } + } + + /** + * @param username The _defaultUsername to set. + */ + public final void setDefaultUsername(String username) + { + if (_connectionDetails != null) + { + _connectionDetails.setUsername(username); + } + _defaultUsername = username; + } + + /** + * @return The _host . + */ + public final String getHost() + { + //todo this doesn't make sense in a multi broker URL as we have no current as that is done by AMQConnection + return _host; } /** - * @return the virtualPath of the connection details. + * @param host The _host to set. + */ + public final void setHost(String host) + { + //todo if _connectionDetails is set then run _connectionDetails.addBrokerDetails() + // Should perhaps have this method changed to setBroker(host,port) + _host = host; + } + + /** + * @return _port The _port to set. + */ + public final int getPort() + { + //todo see getHost + return _port; + } + + /** + * @param port The port to set. + */ + public final void setPort(int port) + { + //todo see setHost + _port = port; + } + + /** + * @return he _virtualPath. */ public final String getVirtualPath() { - return _connectionDetails.getVirtualHost(); + if (_connectionDetails != null) + { + return _connectionDetails.getVirtualHost(); + } + else + { + return _virtualPath; + } + } + + /** + * @param path The _virtualPath to set. + */ + public final void setVirtualPath(String path) + { + if (_connectionDetails != null) + { + _connectionDetails.setVirtualHost(path); + } + + _virtualPath = path; } public static String getUniqueClientID() @@ -91,11 +267,19 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF { try { - if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals("")) + if (_connectionDetails != null) { - _connectionDetails.setClientName(getUniqueClientID()); + if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals("")) + { + _connectionDetails.setClientName(getUniqueClientID()); + } + return new AMQConnection(_connectionDetails, _sslConfig); + } + else + { + return new AMQConnection(_host, _port, _defaultUsername, _defaultPassword, getUniqueClientID(), + _virtualPath); } - return new AMQConnection(_connectionDetails); } catch (Exception e) { @@ -104,6 +288,8 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF jmse.initCause(e); throw jmse; } + + } public Connection createConnection(String userName, String password) throws JMSException @@ -113,35 +299,34 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF public Connection createConnection(String userName, String password, String id) throws JMSException { - if (_connectionDetails != null) + try { - try + if (_connectionDetails != null) { - ConnectionURL connectionDetails = new AMQConnectionURL(_connectionDetails.toString()); - connectionDetails.setUsername(userName); - connectionDetails.setPassword(password); + _connectionDetails.setUsername(userName); + _connectionDetails.setPassword(password); if (id != null && !id.equals("")) { - connectionDetails.setClientName(id); + _connectionDetails.setClientName(id); } - else if (connectionDetails.getClientName() == null || connectionDetails.getClientName().equals("")) + else if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals("")) { - connectionDetails.setClientName(getUniqueClientID()); + _connectionDetails.setClientName(getUniqueClientID()); } - return new AMQConnection(connectionDetails); + return new AMQConnection(_connectionDetails, _sslConfig); } - catch (Exception e) + else { - JMSException jmse = new JMSException("Error creating connection: " + e.getMessage()); - jmse.setLinkedException(e); - jmse.initCause(e); - throw jmse; + return new AMQConnection(_host, _port, userName, password, (id != null ? id : getUniqueClientID()), _virtualPath); } } - else + catch (Exception e) { - throw new JMSException("The connection factory wasn't created with a proper URL, the connection details are empty"); + JMSException jmse = new JMSException("Error creating connection: " + e.getMessage()); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; } } @@ -176,6 +361,12 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF return _connectionDetails.toString(); } + + public final void setConnectionURLString(String url) throws URLSyntaxException + { + _connectionDetails = new AMQConnectionURL(url); + } + /** * JNDI interface to create objects from References. * @@ -266,7 +457,7 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF { try { - return new XAConnectionImpl(_connectionDetails); + return new XAConnectionImpl(_connectionDetails, _sslConfig); } catch (Exception e) { @@ -293,30 +484,19 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF { if (_connectionDetails != null) { - try - { - ConnectionURL connectionDetails = new AMQConnectionURL(_connectionDetails.toString()); - connectionDetails.setUsername(username); - connectionDetails.setPassword(password); - - if (connectionDetails.getClientName() == null || connectionDetails.getClientName().equals("")) - { - connectionDetails.setClientName(getUniqueClientID()); - } - return new XAConnectionImpl(connectionDetails); - } - catch (Exception e) + _connectionDetails.setUsername(username); + _connectionDetails.setPassword(password); + + if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals("")) { - JMSException jmse = new JMSException("Error creating XA Connection: " + e.getMessage()); - jmse.setLinkedException(e); - jmse.initCause(e); - throw jmse; + _connectionDetails.setClientName(getUniqueClientID()); } } else { - throw new JMSException("The connection factory wasn't created with a proper URL, the connection details are empty"); - } + throw new JMSException("A URL must be specified to access XA connections"); + } + return createXAConnection(); } 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 f9f50d9150..93b4c51a8f 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 @@ -27,14 +27,18 @@ import java.util.Map; import org.apache.qpid.client.url.URLParser; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.jms.BrokerDetails; import org.apache.qpid.jms.ConnectionURL; import org.apache.qpid.url.URLHelper; import org.apache.qpid.url.URLSyntaxException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class AMQConnectionURL implements ConnectionURL { - + private static final Logger _logger = LoggerFactory.getLogger(AMQConnectionURL.class); + private String _url; private String _failoverMethod; private Map<String, String> _failoverOptions; @@ -291,4 +295,17 @@ public class AMQConnectionURL implements ConnectionURL return sb.toString(); } + + public static void main(String[] args) throws URLSyntaxException + { + String url2 = + "amqp://ritchiem:bob@temp/testHost?brokerlist='tcp://localhost:5672;tcp://fancyserver:3000/',failover='roundrobin'"; + // "amqp://user:pass@clientid/virtualhost?brokerlist='tcp://host:1?option1=\'value\',option2=\'value\';vm://:3?option1=\'value\'',failover='method?option1=\'value\',option2='value''"; + + ConnectionURL connectionurl2 = new AMQConnectionURL(url2); + + System.out.println(url2); + System.out.println(connectionurl2); + + } } 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 acd46da11a..eb9682a3cf 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 @@ -21,6 +21,8 @@ package org.apache.qpid.client; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import javax.jms.Destination; @@ -32,6 +34,8 @@ import javax.naming.StringRefAddr; import org.apache.qpid.client.messaging.address.AddressHelper; import org.apache.qpid.client.messaging.address.Link; import org.apache.qpid.client.messaging.address.Node; +import org.apache.qpid.client.messaging.address.QpidExchangeOptions; +import org.apache.qpid.client.messaging.address.QpidQueueOptions; import org.apache.qpid.configuration.ClientProperties; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -74,6 +78,11 @@ public abstract class AMQDestination implements Destination, Referenceable private boolean _exchangeExistsChecked; + private byte[] _byteEncoding; + private static final int IS_DURABLE_MASK = 0x1; + private static final int IS_EXCLUSIVE_MASK = 0x2; + private static final int IS_AUTODELETE_MASK = 0x4; + public static final int QUEUE_TYPE = 1; public static final int TOPIC_TYPE = 2; public static final int UNKNOWN_TYPE = 3; @@ -314,11 +323,7 @@ public abstract class AMQDestination implements Destination, Referenceable { if(_urlAsShortString == null) { - if (_url == null) - { - toURL(); - } - _urlAsShortString = new AMQShortString(_url); + toURL(); } return _urlAsShortString; } @@ -365,6 +370,7 @@ public abstract class AMQDestination implements Destination, Referenceable // calculated URL now out of date _url = null; _urlAsShortString = null; + _byteEncoding = null; } public AMQShortString getRoutingKey() @@ -502,10 +508,59 @@ public abstract class AMQDestination implements Destination, Referenceable sb.deleteCharAt(sb.length() - 1); url = sb.toString(); _url = url; + _urlAsShortString = new AMQShortString(url); } return url; } + public byte[] toByteEncoding() + { + byte[] encoding = _byteEncoding; + if(encoding == null) + { + int size = _exchangeClass.length() + 1 + + _exchangeName.length() + 1 + + 0 + // in place of the destination name + (_queueName == null ? 0 : _queueName.length()) + 1 + + 1; + encoding = new byte[size]; + int pos = 0; + + pos = _exchangeClass.writeToByteArray(encoding, pos); + pos = _exchangeName.writeToByteArray(encoding, pos); + + encoding[pos++] = (byte)0; + + if(_queueName == null) + { + encoding[pos++] = (byte)0; + } + else + { + pos = _queueName.writeToByteArray(encoding,pos); + } + byte options = 0; + if(_isDurable) + { + options |= IS_DURABLE_MASK; + } + if(_isExclusive) + { + options |= IS_EXCLUSIVE_MASK; + } + if(_isAutoDelete) + { + options |= IS_AUTODELETE_MASK; + } + encoding[pos] = options; + + + _byteEncoding = encoding; + + } + return encoding; + } + public boolean equals(Object o) { if (this == o) @@ -559,6 +614,53 @@ public abstract class AMQDestination implements Destination, Referenceable null); // factory location } + + public static Destination createDestination(byte[] byteEncodedDestination) + { + AMQShortString exchangeClass; + AMQShortString exchangeName; + AMQShortString routingKey; + AMQShortString queueName; + boolean isDurable; + boolean isExclusive; + boolean isAutoDelete; + + int pos = 0; + exchangeClass = AMQShortString.readFromByteArray(byteEncodedDestination, pos); + pos+= exchangeClass.length() + 1; + exchangeName = AMQShortString.readFromByteArray(byteEncodedDestination, pos); + pos+= exchangeName.length() + 1; + routingKey = AMQShortString.readFromByteArray(byteEncodedDestination, pos); + pos+= (routingKey == null ? 0 : routingKey.length()) + 1; + queueName = AMQShortString.readFromByteArray(byteEncodedDestination, pos); + pos+= (queueName == null ? 0 : queueName.length()) + 1; + int options = byteEncodedDestination[pos]; + isDurable = (options & IS_DURABLE_MASK) != 0; + isExclusive = (options & IS_EXCLUSIVE_MASK) != 0; + isAutoDelete = (options & IS_AUTODELETE_MASK) != 0; + + if (exchangeClass.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS)) + { + return new AMQQueue(exchangeName,routingKey,queueName,isExclusive,isAutoDelete,isDurable); + } + else if (exchangeClass.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS)) + { + return new AMQTopic(exchangeName,routingKey,isAutoDelete,queueName,isDurable); + } + else if (exchangeClass.equals(ExchangeDefaults.HEADERS_EXCHANGE_CLASS)) + { + return new AMQHeadersExchange(routingKey); + } + else + { + return new AMQAnyDestination(exchangeName,exchangeClass, + routingKey,isExclusive, + isAutoDelete,queueName, + isDurable, new AMQShortString[0]); + } + + } + public static Destination createDestination(BindingURL binding) { AMQShortString type = binding.getExchangeClass(); @@ -793,7 +895,7 @@ public abstract class AMQDestination implements Destination, Referenceable return _browseOnly; } - private void setBrowseOnly(boolean b) + public void setBrowseOnly(boolean b) { _browseOnly = b; } 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 d34290e007..1f940b62f0 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 @@ -70,6 +70,7 @@ import org.apache.qpid.AMQDisconnectedException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQInvalidArgumentException; import org.apache.qpid.AMQInvalidRoutingKeyException; +import org.apache.qpid.client.AMQDestination.AddressOption; import org.apache.qpid.client.AMQDestination.DestSyntax; import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.failover.FailoverNoopSupport; @@ -87,6 +88,8 @@ 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.state.AMQState; +import org.apache.qpid.client.state.AMQStateManager; import org.apache.qpid.client.util.FlowControllingBlockingQueue; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.framing.AMQShortString; @@ -94,10 +97,7 @@ 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.protocol.AMQConstant; import org.apache.qpid.thread.Threading; -import org.apache.qpid.transport.SessionException; -import org.apache.qpid.transport.TransportException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -213,6 +213,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic */ 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 @@ -308,7 +310,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic protected final FlowControllingBlockingQueue _queue; /** Holds the highest received delivery tag. */ - protected final AtomicLong _highestDeliveryTag = new AtomicLong(-1); + private final AtomicLong _highestDeliveryTag = new AtomicLong(-1); private final AtomicLong _rollbackMark = new AtomicLong(-1); /** All the not yet acknowledged message tags */ @@ -362,13 +364,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic * Set when recover is called. This is to handle the case where recover() is called by application code during * onMessage() processing to ensure that an auto ack is not sent. */ - private volatile boolean _sessionInRecovery; - - /** - * Set when the dispatcher should direct incoming messages straight into the UnackedMessage list instead of - * to the syncRecieveQueue or MessageListener. Used during cleanup, e.g. in Session.recover(). - */ - private volatile boolean _usingDispatcherForCleanup; + private boolean _inRecovery; /** Used to indicates that the connection to which this session belongs, has been stopped. */ private boolean _connectionStopped; @@ -571,8 +567,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic close(-1); } - public abstract AMQException getLastException(); - public void checkNotClosed() throws JMSException { try @@ -581,20 +575,16 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic } catch (IllegalStateException ise) { - AMQException ex = getLastException(); - if (ex != null) - { - IllegalStateException ssnClosed = new IllegalStateException( - "Session has been closed", ex.getErrorCode().toString()); + // if the Connection has closed then we should throw any exception that has occurred that we were not waiting for + AMQStateManager manager = _connection.getProtocolHandler().getStateManager(); - ssnClosed.setLinkedException(ex); - ssnClosed.initCause(ex); - throw ssnClosed; - } - else + if (manager.getCurrentState().equals(AMQState.CONNECTION_CLOSED) && manager.getLastException() != null) { - throw ise; + ise.setLinkedException(manager.getLastException()); + ise.initCause(ise.getLinkedException()); } + + throw ise; } } @@ -610,36 +600,29 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic * Acknowledges all unacknowledged messages on the session, for all message consumers on the session. * * @throws IllegalStateException If the session is closed. - * @throws JMSException if there is a problem during acknowledge process. */ - public void acknowledge() throws IllegalStateException, JMSException + public void acknowledge() throws IllegalStateException { if (isClosed()) { throw new IllegalStateException("Session is already closed"); } - else if (hasFailedOverDirty()) + else if (hasFailedOver()) { - //perform an implicit recover in this scenario - recover(); - - //notify the consumer throw new IllegalStateException("has failed over"); } - try - { - acknowledgeImpl(); - markClean(); - } - catch (TransportException e) + while (true) { - throw toJMSException("Exception while acknowledging message(s):" + e.getMessage(), e); + Long tag = _unacknowledgedMessageTags.poll(); + if (tag == null) + { + break; + } + acknowledgeMessage(tag, false); } } - protected abstract void acknowledgeImpl() throws JMSException; - /** * Acknowledge one or many messages. * @@ -774,10 +757,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic _logger.debug( "Got FailoverException during channel close, ignored as channel already marked as closed."); } - catch (TransportException e) - { - throw toJMSException("Error closing session:" + e.getMessage(), e); - } finally { _connection.deregisterSession(_channelId); @@ -848,44 +827,51 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic * @throws JMSException If the JMS provider fails to commit the transaction due to some internal error. This does * not mean that the commit is known to have failed, merely that it is not known whether it * failed or not. + * @todo Be aware of possible changes to parameter order as versions change. */ public void commit() throws JMSException { checkTransacted(); - //Check that we are clean to commit. - if (_failedOverDirty) + try { - if (_logger.isDebugEnabled()) + //Check that we are clean to commit. + if (_failedOverDirty) { - _logger.debug("Session " + _channelId + " was dirty whilst failing over. Rolling back."); + rollback(); + + throw new TransactionRolledBackException("Connection failover has occured since last send. " + + "Forced rollback"); } - rollback(); - throw new TransactionRolledBackException("Connection failover has occured with uncommitted transaction activity." + - "The session transaction was rolled back."); - } - try - { - commitImpl(); + // Acknowledge all delivered messages + while (true) + { + Long tag = _deliveredMessageTags.poll(); + if (tag == null) + { + break; + } + + acknowledgeMessage(tag, false); + } + // Commits outstanding messages and acknowledgments + sendCommit(); markClean(); } catch (AMQException e) { - throw new JMSAMQException("Exception during commit: " + e.getMessage() + ":" + e.getCause(), e); + throw new JMSAMQException("Failed to commit: " + e.getMessage() + ":" + e.getCause(), e); } catch (FailoverException e) { throw new JMSAMQException("Fail-over interrupted commit. Status of the commit is uncertain.", e); } - catch(TransportException e) - { - throw toJMSException("Session exception occured while trying to commit: " + e.getMessage(), e); - } } - protected abstract void commitImpl() throws AMQException, FailoverException, TransportException; + public abstract void sendCommit() throws AMQException, FailoverException; + public void confirmConsumerCancelled(int consumerTag) { @@ -963,7 +949,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic return new AMQQueueBrowser(this, (AMQQueue) queue, messageSelector); } - protected MessageConsumer createBrowserConsumer(Destination destination, String messageSelector, boolean noLocal) + public MessageConsumer createBrowserConsumer(Destination destination, String messageSelector, boolean noLocal) throws JMSException { checkValidDestination(destination); @@ -977,7 +963,15 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic checkValidDestination(destination); return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic), null, null, - isBrowseOnlyDestination(destination), false); + ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); + } + + public C createExclusiveConsumer(Destination destination) throws JMSException + { + checkValidDestination(destination); + + return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, true, null, null, + ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException @@ -985,7 +979,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic checkValidDestination(destination); return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic), - messageSelector, null, isBrowseOnlyDestination(destination), false); + messageSelector, null, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal) @@ -994,7 +988,16 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic checkValidDestination(destination); return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, (destination instanceof Topic), - messageSelector, null, isBrowseOnlyDestination(destination), false); + messageSelector, null, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); + } + + public MessageConsumer createExclusiveConsumer(Destination destination, String messageSelector, boolean noLocal) + throws JMSException + { + checkValidDestination(destination); + + return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, true, + messageSelector, null, false, false); } public MessageConsumer createConsumer(Destination destination, int prefetch, boolean noLocal, boolean exclusive, @@ -1002,15 +1005,23 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { checkValidDestination(destination); - return createConsumerImpl(destination, prefetch, prefetch / 2, noLocal, exclusive, selector, null, isBrowseOnlyDestination(destination), false); + return createConsumerImpl(destination, prefetch, prefetch / 2, noLocal, exclusive, selector, null, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, int prefetchHigh, int prefetchLow, boolean noLocal, - boolean exclusive, String selector) throws JMSException + boolean exclusive, String selector) throws JMSException { checkValidDestination(destination); - return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, null, isBrowseOnlyDestination(destination), false); + return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, null, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); + } + + public MessageConsumer createConsumer(Destination destination, int prefetch, boolean noLocal, boolean exclusive, + String selector, FieldTable rawSelector) throws JMSException + { + checkValidDestination(destination); + + return createConsumerImpl(destination, prefetch, prefetch / 2, noLocal, exclusive, selector, rawSelector, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, int prefetchHigh, int prefetchLow, boolean noLocal, @@ -1018,7 +1029,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { checkValidDestination(destination); - return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, rawSelector, isBrowseOnlyDestination(destination), + return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, rawSelector, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } @@ -1032,33 +1043,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic throws JMSException { checkNotClosed(); - Topic origTopic = checkValidTopic(topic, true); - + AMQTopic origTopic = checkValidTopic(topic, true); AMQTopic dest = AMQTopic.createDurableTopic(origTopic, name, _connection); - if (dest.getDestSyntax() == DestSyntax.ADDR && - !dest.isAddressResolved()) - { - try - { - handleAddressBasedDestination(dest,false,true); - if (dest.getAddressType() != AMQDestination.TOPIC_TYPE) - { - throw new JMSException("Durable subscribers can only be created for Topics"); - } - dest.getSourceNode().setDurable(true); - } - catch(AMQException e) - { - JMSException ex = new JMSException("Error when verifying destination"); - ex.initCause(e); - ex.setLinkedException(e); - throw ex; - } - catch(TransportException e) - { - throw toJMSException("Error when verifying destination", e); - } - } String messageSelector = ((selector == null) || (selector.trim().length() == 0)) ? null : selector; @@ -1070,9 +1056,15 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic // Not subscribed to this name in the current session if (subscriber == null) { - // After the address is resolved routing key will not be null. - AMQShortString topicName = dest.getRoutingKey(); - + AMQShortString topicName; + if (topic instanceof AMQTopic) + { + topicName = ((AMQTopic) topic).getRoutingKey(); + } else + { + topicName = new AMQShortString(topic.getTopicName()); + } + if (_strictAMQP) { if (_strictAMQPFATAL) @@ -1143,10 +1135,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic return subscriber; } - catch (TransportException e) - { - throw toJMSException("Exception while creating durable subscriber:" + e.getMessage(), e); - } finally { _subscriberDetails.unlock(); @@ -1207,6 +1195,12 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic return createProducerImpl(destination, mandatory, immediate); } + public P createProducer(Destination destination, boolean mandatory, boolean immediate, + boolean waitUntilSent) throws JMSException + { + return createProducerImpl(destination, mandatory, immediate, waitUntilSent); + } + public TopicPublisher createPublisher(Topic topic) throws JMSException { checkNotClosed(); @@ -1231,6 +1225,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic else { AMQQueue queue = new AMQQueue(queueName); + queue.setCreate(AddressOption.ALWAYS); return queue; } @@ -1312,8 +1307,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic public QueueReceiver createQueueReceiver(Destination destination) throws JMSException { checkValidDestination(destination); - Queue dest = validateQueue(destination); - C consumer = (C) createConsumer(dest); + AMQQueue dest = (AMQQueue) destination; + C consumer = (C) createConsumer(destination); return new QueueReceiverAdaptor(dest, consumer); } @@ -1331,8 +1326,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic public QueueReceiver createQueueReceiver(Destination destination, String messageSelector) throws JMSException { checkValidDestination(destination); - Queue dest = validateQueue(destination); - C consumer = (C) createConsumer(dest, messageSelector); + AMQQueue dest = (AMQQueue) destination; + C consumer = (C) createConsumer(destination, messageSelector); return new QueueReceiverAdaptor(dest, consumer); } @@ -1349,7 +1344,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic public QueueReceiver createReceiver(Queue queue) throws JMSException { checkNotClosed(); - Queue dest = validateQueue(queue); + AMQQueue dest = (AMQQueue) queue; C consumer = (C) createConsumer(dest); return new QueueReceiverAdaptor(dest, consumer); @@ -1368,28 +1363,17 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException { checkNotClosed(); - Queue dest = validateQueue(queue); + AMQQueue dest = (AMQQueue) queue; C consumer = (C) createConsumer(dest, messageSelector); return new QueueReceiverAdaptor(dest, consumer); } - - private Queue validateQueue(Destination dest) throws InvalidDestinationException - { - if (dest instanceof AMQDestination && dest instanceof javax.jms.Queue) - { - return (Queue)dest; - } - else - { - throw new InvalidDestinationException("The destination object used is not from this provider or of type javax.jms.Queue"); - } - } public QueueSender createSender(Queue queue) throws JMSException { checkNotClosed(); + // return (QueueSender) createProducer(queue); return new QueueSenderAdapter(createProducer(queue), queue); } @@ -1424,10 +1408,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic public TopicSubscriber createSubscriber(Topic topic) throws JMSException { checkNotClosed(); - checkValidTopic(topic); + AMQTopic dest = checkValidTopic(topic); - return new TopicSubscriberAdaptor<C>(topic, - createConsumerImpl(topic, _prefetchHighMark, _prefetchLowMark, false, true, null, null, false, false)); + // AMQTopic dest = new AMQTopic(topic.getTopicName()); + return new TopicSubscriberAdaptor(dest, (C) createExclusiveConsumer(dest)); } /** @@ -1444,11 +1428,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException { checkNotClosed(); - checkValidTopic(topic); + AMQTopic dest = checkValidTopic(topic); - return new TopicSubscriberAdaptor<C>(topic, - createConsumerImpl(topic, _prefetchHighMark, _prefetchLowMark, noLocal, - true, messageSelector, null, false, false)); + // AMQTopic dest = new AMQTopic(topic.getTopicName()); + return new TopicSubscriberAdaptor(dest, (C) createExclusiveConsumer(dest, messageSelector, noLocal)); } public TemporaryQueue createTemporaryQueue() throws JMSException @@ -1550,8 +1533,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic abstract public void sync() throws AMQException; - public int getAcknowledgeMode() + public int getAcknowledgeMode() throws JMSException { + checkNotClosed(); + return _acknowledgeMode; } @@ -1611,8 +1596,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic return _ticket; } - public boolean getTransacted() + public boolean getTransacted() throws JMSException { + checkNotClosed(); + return _transacted; } @@ -1708,14 +1695,13 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic // Ensure that the session is not transacted. checkNotTransacted(); - + // flush any acks we are holding in the buffer. + flushAcknowledgments(); + + // this is set only here, and the before the consumer's onMessage is called it is set to false + _inRecovery = true; try { - // flush any acks we are holding in the buffer. - flushAcknowledgments(); - - // this is only set true here, and only set false when the consumers preDeliver method is called - _sessionInRecovery = true; boolean isSuspended = isSuspended(); @@ -1723,18 +1709,9 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { suspendChannel(true); } - - // Set to true to short circuit delivery of anything currently - //in the pre-dispatch queue. - _usingDispatcherForCleanup = true; - + syncDispatchQueue(); - - // Set to false before sending the recover as 0-8/9/9-1 will - //send messages back before the recover completes, and we - //probably shouldn't clean those! ;-) - _usingDispatcherForCleanup = false; - + if (_dispatcher != null) { _dispatcher.recover(); @@ -1743,7 +1720,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic sendRecover(); markClean(); - + + // Set inRecovery to false before you start message flow again again. + _inRecovery = false; + if (!isSuspended) { suspendChannel(false); @@ -1757,10 +1737,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { throw new JMSAMQException("Recovery was interrupted by fail-over. Recovery status is not known.", e); } - catch(TransportException e) - { - throw toJMSException("Recover failed: " + e.getMessage(), e); - } + } protected abstract void sendRecover() throws AMQException, FailoverException; @@ -1818,7 +1795,9 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic suspendChannel(true); } - setRollbackMark(); + // Let the dispatcher know that all the incomming messages + // should be rolled back(reject/release) + _rollbackMark.set(_highestDeliveryTag.get()); syncDispatchQueue(); @@ -1843,10 +1822,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { throw new JMSAMQException("Fail-over interrupted rollback. Status of the rollback is uncertain.", e); } - catch (TransportException e) - { - throw toJMSException("Failure to rollback:" + e.getMessage(), e); - } } } @@ -1893,14 +1868,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic */ public void unsubscribe(String name) throws JMSException { - try - { - unsubscribe(name, false); - } - catch (TransportException e) - { - throw toJMSException("Exception while unsubscribing:" + e.getMessage(), e); - } + unsubscribe(name, false); } /** @@ -1977,12 +1945,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { checkTemporaryDestination(destination); - if(!noConsume && isBrowseOnlyDestination(destination)) - { - throw new InvalidDestinationException("The consumer being created is not 'noConsume'," + - "but a 'browseOnly' Destination has been supplied."); - } - final String messageSelector; if (_strictAMQP && !((selector == null) || selector.equals(""))) @@ -2027,16 +1989,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic // argument, as specifying null for the arguments when querying means they should not be checked at all ft.put(AMQPFilterTypes.JMS_SELECTOR.getValue(), messageSelector == null ? "" : messageSelector); - C consumer; - try - { - consumer = createMessageConsumer(amqd, prefetchHigh, prefetchLow, - noLocal, exclusive, messageSelector, ft, noConsume, autoClose); - } - catch(TransportException e) - { - throw toJMSException("Exception while creating consumer: " + e.getMessage(), e); - } + C consumer = createMessageConsumer(amqd, prefetchHigh, prefetchLow, + noLocal, exclusive, messageSelector, ft, noConsume, autoClose); if (_messageListener != null) { @@ -2073,10 +2027,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic ex.initCause(e); throw ex; } - catch (TransportException e) - { - throw toJMSException("Exception while registering consumer:" + e.getMessage(), e); - } + return consumer; } }, _connection).execute(); @@ -2141,7 +2092,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic boolean isInRecovery() { - return _sessionInRecovery; + return _inRecovery; } boolean isQueueBound(AMQShortString exchangeName, AMQShortString queueName) throws JMSException @@ -2263,7 +2214,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic void setInRecovery(boolean inRecovery) { - _sessionInRecovery = inRecovery; + _inRecovery = inRecovery; } boolean isStarted() @@ -2444,7 +2395,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 Topic checkValidTopic(Topic topic, boolean durable) throws JMSException + protected AMQTopic checkValidTopic(Topic topic, boolean durable) throws JMSException { if (topic == null) { @@ -2463,17 +2414,17 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic ("Cannot create a durable subscription with a temporary topic: " + topic); } - if (!(topic instanceof AMQDestination && topic instanceof javax.jms.Topic)) + if (!(topic instanceof AMQTopic)) { throw new javax.jms.InvalidDestinationException( "Cannot create a subscription on topic created for another JMS Provider, class of topic provided is: " + topic.getClass().getName()); } - return topic; + return (AMQTopic) topic; } - protected Topic checkValidTopic(Topic topic) throws JMSException + protected AMQTopic checkValidTopic(Topic topic) throws JMSException { return checkValidTopic(topic, false); } @@ -2602,9 +2553,15 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic public abstract void sendConsume(C consumer, AMQShortString queueName, AMQProtocolHandler protocolHandler, boolean nowait, String messageSelector, int tag) throws AMQException, FailoverException; - private P createProducerImpl(final Destination destination, final boolean mandatory, final boolean immediate) + private P createProducerImpl(Destination destination, boolean mandatory, boolean immediate) throws JMSException { + return createProducerImpl(destination, mandatory, immediate, DEFAULT_WAIT_ON_SEND); + } + + private P createProducerImpl(final Destination destination, final boolean mandatory, + final boolean immediate, final boolean waitUntilSent) throws JMSException + { return new FailoverRetrySupport<P, JMSException>( new FailoverProtectedOperation<P, JMSException>() { @@ -2612,18 +2569,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { checkNotClosed(); long producerId = getNextProducerId(); - - P producer; - try - { - producer = createMessageProducer(destination, mandatory, - immediate, producerId); - } - catch (TransportException e) - { - throw toJMSException("Exception while creating producer:" + e.getMessage(), e); - } - + P producer = createMessageProducer(destination, mandatory, + immediate, waitUntilSent, producerId); registerProducer(producerId, producer); return producer; @@ -2632,7 +2579,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic } public abstract P createMessageProducer(final Destination destination, final boolean mandatory, - final boolean immediate, final long producerId) throws JMSException; + final boolean immediate, final boolean waitUntilSent, long producerId) throws JMSException; private void declareExchange(AMQDestination amqd, AMQProtocolHandler protocolHandler, boolean nowait) throws AMQException { @@ -2775,21 +2722,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic } } - /** - * Undeclares the specified temporary queue/topic. - * - * <p/>Note that this operation automatically retries in the event of fail-over. - * - * @param amqQueue The name of the temporary destination to delete. - * - * @throws JMSException If the queue could not be deleted for any reason. - * @todo Be aware of possible changes to parameter order as versions change. - */ - protected void deleteTemporaryDestination(final TemporaryDestination amqQueue) throws JMSException - { - deleteQueue(amqQueue.getAMQQueueName()); - } - public abstract void sendQueueDelete(final AMQShortString queueName) throws AMQException, FailoverException; private long getNextProducerId() @@ -2887,7 +2819,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { declareQueue(amqd, protocolHandler, consumer.isNoLocal(), nowait); } - bindQueue(amqd.getAMQQueueName(), amqd.getRoutingKey(), consumer.getArguments(), amqd.getExchangeName(), amqd, nowait); } AMQShortString queueName = amqd.getAMQQueueName(); @@ -2895,6 +2826,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic // store the consumer queue name consumer.setQueuename(queueName); + 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) { @@ -3045,10 +2978,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { throw new AMQException(null, "Fail-over interrupted suspend/unsuspend channel.", e); } - catch (TransportException e) - { - throw new AMQException(AMQConstant.getConstant(getErrorCode(e)), e.getMessage(), e); - } } } @@ -3087,11 +3016,21 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic * * @return boolean true if failover has occured. */ - public boolean hasFailedOverDirty() + public boolean hasFailedOver() { return _failedOverDirty; } + /** + * Check to see if any message have been sent in this transaction and have not been commited. + * + * @return boolean true if a message has been sent but not commited + */ + public boolean isDirty() + { + return _dirty; + } + public void setTicket(int ticket) { _ticket = ticket; @@ -3204,7 +3143,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic setConnectionStopped(true); } - setRollbackMark(); + _rollbackMark.set(_highestDeliveryTag.get()); _dispatcherLogger.debug("Session Pre Dispatch Queue cleared"); @@ -3353,14 +3292,9 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic if (!(message instanceof CloseConsumerMessage) && tagLE(deliveryTag, _rollbackMark.get())) { - if (_logger.isDebugEnabled()) - { - _logger.debug("Rejecting message because delivery tag " + deliveryTag - + " <= rollback mark " + _rollbackMark.get()); - } rejectMessage(message, true); } - else if (_usingDispatcherForCleanup) + else if (isInRecovery()) { _unacknowledgedMessageTags.add(deliveryTag); } @@ -3419,11 +3353,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic // Don't reject if we're already closing if (!_closed.get()) { - if (_logger.isDebugEnabled()) - { - _logger.debug("Rejecting message with delivery tag " + message.getDeliveryTag() - + " for closing consumer " + String.valueOf(consumer == null? null: consumer._consumerTag)); - } rejectMessage(message, true); } } @@ -3521,48 +3450,4 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { return _closing.get()|| _connection.isClosing(); } - - public boolean isDeclareExchanges() - { - return DECLARE_EXCHANGES; - } - - JMSException toJMSException(String message, TransportException e) - { - int code = getErrorCode(e); - JMSException jmse = new JMSException(message, Integer.toString(code)); - jmse.setLinkedException(e); - jmse.initCause(e); - return jmse; - } - - private int getErrorCode(TransportException e) - { - int code = AMQConstant.INTERNAL_ERROR.getCode(); - if (e instanceof SessionException) - { - SessionException se = (SessionException) e; - if(se.getException() != null && se.getException().getErrorCode() != null) - { - code = se.getException().getErrorCode().getValue(); - } - } - return code; - } - - private boolean isBrowseOnlyDestination(Destination destination) - { - return ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()); - } - - private void setRollbackMark() - { - // Let the dispatcher know that all the incomming messages - // should be rolled back(reject/release) - _rollbackMark.set(_highestDeliveryTag.get()); - if (_logger.isDebugEnabled()) - { - _logger.debug("Rollback mark is set to " + _rollbackMark.get()); - } - } } 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 c6a64ec894..517a7a5ce8 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 @@ -47,8 +47,6 @@ import org.apache.qpid.client.message.AMQMessageDelegateFactory; import org.apache.qpid.client.message.FieldTableSupport; import org.apache.qpid.client.message.MessageFactoryRegistry; import org.apache.qpid.client.message.UnprocessedMessage_0_10; -import org.apache.qpid.client.messaging.address.Link; -import org.apache.qpid.client.messaging.address.Link.Reliability; import org.apache.qpid.client.messaging.address.Node.ExchangeNode; import org.apache.qpid.client.messaging.address.Node.QueueNode; import org.apache.qpid.client.protocol.AMQProtocolHandler; @@ -58,7 +56,6 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.transport.ExchangeBoundResult; import org.apache.qpid.transport.ExchangeQueryResult; -import org.apache.qpid.transport.ExecutionErrorCode; import org.apache.qpid.transport.ExecutionException; import org.apache.qpid.transport.MessageAcceptMode; import org.apache.qpid.transport.MessageAcquireMode; @@ -72,7 +69,6 @@ import org.apache.qpid.transport.RangeSet; import org.apache.qpid.transport.Session; import org.apache.qpid.transport.SessionException; import org.apache.qpid.transport.SessionListener; -import org.apache.qpid.transport.TransportException; import org.apache.qpid.util.Serial; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -160,20 +156,13 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic */ AMQSession_0_10(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId, boolean transacted, int acknowledgeMode, MessageFactoryRegistry messageFactoryRegistry, - int defaultPrefetchHighMark, int defaultPrefetchLowMark,String name) + int defaultPrefetchHighMark, int defaultPrefetchLowMark) { super(con, channelId, transacted, acknowledgeMode, messageFactoryRegistry, defaultPrefetchHighMark, defaultPrefetchLowMark); _qpidConnection = qpidConnection; - if (name == null) - { - _qpidSession = _qpidConnection.createSession(1); - } - else - { - _qpidSession = _qpidConnection.createSession(name,1); - } + _qpidSession = _qpidConnection.createSession(1); _qpidSession.setSessionListener(this); if (_transacted) { @@ -200,12 +189,11 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic * @param qpidConnection The connection */ AMQSession_0_10(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId, - boolean transacted, int acknowledgeMode, int defaultPrefetchHigh, int defaultPrefetchLow, - String name) + boolean transacted, int acknowledgeMode, int defaultPrefetchHigh, int defaultPrefetchLow) { this(qpidConnection, con, channelId, transacted, acknowledgeMode, MessageFactoryRegistry.newDefaultRegistry(), - defaultPrefetchHigh, defaultPrefetchLow,name); + defaultPrefetchHigh, defaultPrefetchLow); } private void addUnacked(int id) @@ -270,7 +258,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic long prefetch = getAMQConnection().getMaxPrefetch(); - if (unackedCount >= prefetch/2 || maxAckDelay <= 0 || _acknowledgeMode == javax.jms.Session.AUTO_ACKNOWLEDGE) + if (unackedCount >= prefetch/2 || maxAckDelay <= 0) { flushAcknowledgments(); } @@ -294,34 +282,23 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic } } - void messageAcknowledge(final RangeSet ranges, final boolean accept) + void messageAcknowledge(RangeSet ranges, boolean accept) { messageAcknowledge(ranges,accept,false); } - void messageAcknowledge(final RangeSet ranges, final boolean accept, final boolean setSyncBit) + void messageAcknowledge(RangeSet ranges, boolean accept,boolean setSyncBit) { - final Session ssn = getQpidSession(); - flushProcessed(ranges,accept); - if (accept) + Session ssn = getQpidSession(); + for (Range range : ranges) { - ssn.messageAccept(ranges, UNRELIABLE, setSyncBit ? SYNC : NONE); + ssn.processed(range); } - } - - /** - * Flush any outstanding commands. This causes session complete to be sent. - * @param ranges the range of command ids. - * @param batch true if batched. - */ - void flushProcessed(final RangeSet ranges, final boolean batch) - { - final Session ssn = getQpidSession(); - for (final Range range : ranges) + ssn.flushProcessed(accept ? BATCH : NONE); + if (accept) { - ssn.processed(range); + ssn.messageAccept(ranges, UNRELIABLE,setSyncBit? SYNC : NONE); } - ssn.flushProcessed(batch ? BATCH : NONE); } /** @@ -337,7 +314,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic public void sendQueueBind(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments, final AMQShortString exchangeName, final AMQDestination destination, final boolean nowait) - throws AMQException + throws AMQException, FailoverException { if (destination.getDestSyntax() == DestSyntax.BURL) { @@ -423,6 +400,25 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic } } + + /** + * Commit the receipt and the delivery of all messages exchanged by this session resources. + */ + public void sendCommit() throws AMQException, FailoverException + { + getQpidSession().setAutoSync(true); + try + { + getQpidSession().txCommit(); + } + finally + { + getQpidSession().setAutoSync(false); + } + // We need to sync so that we get notify of an error. + sync(); + } + /** * Create a queue with a given name. * @@ -455,14 +451,6 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic public void sendRecover() throws AMQException, FailoverException { // release all unacked messages - RangeSet ranges = gatherUnackedRangeSet(); - getQpidSession().messageRelease(ranges, Option.SET_REDELIVERED); - // We need to sync so that we get notify of an error. - sync(); - } - - private RangeSet gatherUnackedRangeSet() - { RangeSet ranges = new RangeSet(); while (true) { @@ -471,11 +459,11 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic { break; } - - ranges.add(tag.intValue()); + ranges.add((int) (long) tag); } - - return ranges; + getQpidSession().messageRelease(ranges, Option.SET_REDELIVERED); + // We need to sync so that we get notify of an error. + sync(); } @@ -549,6 +537,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic } public boolean isQueueBound(final String exchangeName, final String queueName, final String bindingKey,Map<String,Object> args) + throws JMSException { boolean res; ExchangeBoundResult bindingQueryResult = @@ -611,16 +600,10 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic (Map<? extends String, ? extends Object>) consumer.getDestination().getLink().getSubscription().getArgs()); } - boolean acceptModeNone = getAcknowledgeMode() == NO_ACKNOWLEDGE; - - if (consumer.getDestination().getLink() != null) - { - acceptModeNone = consumer.getDestination().getLink().getReliability() == Link.Reliability.UNRELIABLE; - } getQpidSession().messageSubscribe (queueName.toString(), String.valueOf(tag), - acceptModeNone ? MessageAcceptMode.NONE : MessageAcceptMode.EXPLICIT, + getAcknowledgeMode() == NO_ACKNOWLEDGE ? MessageAcceptMode.NONE : MessageAcceptMode.EXPLICIT, preAcquire ? MessageAcquireMode.PRE_ACQUIRED : MessageAcquireMode.NOT_ACQUIRED, null, 0, arguments, consumer.isExclusive() ? Option.EXCLUSIVE : Option.NONE); } @@ -676,12 +659,13 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic * Create an 0_10 message producer */ public BasicMessageProducer_0_10 createMessageProducer(final Destination destination, final boolean mandatory, - final boolean immediate, final long producerId) throws JMSException + final boolean immediate, final boolean waitUntilSent, + long producerId) throws JMSException { try { return new BasicMessageProducer_0_10(_connection, (AMQDestination) destination, _transacted, _channelId, this, - getProtocolHandler(), producerId, immediate, mandatory); + getProtocolHandler(), producerId, immediate, mandatory, waitUntilSent); } catch (AMQException e) { @@ -691,10 +675,6 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic throw ex; } - catch(TransportException e) - { - throw toJMSException("Exception while creating message producer:" + e.getMessage(), e); - } } @@ -787,7 +767,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic else { QueueNode node = (QueueNode)amqd.getSourceNode(); - getQpidSession().queueDeclare(queueName.toString(), node.getAlternateExchange() , + getQpidSession().queueDeclare(queueName.toString(), "" , node.getDeclareArgs(), node.isAutoDelete() ? Option.AUTO_DELETE : Option.NONE, node.isDurable() ? Option.DURABLE : Option.NONE, @@ -924,26 +904,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic setCurrentException(exc); } - public void closed(Session ssn) - { - try - { - super.closed(null); - if (flushTask != null) - { - flushTask.cancel(); - flushTask = null; - } - } catch (Exception e) - { - _logger.error("Error closing JMS session", e); - } - } - - public AMQException getLastException() - { - return getCurrentException(); - } + public void closed(Session ssn) {} protected AMQShortString declareQueue(final AMQDestination amqd, final AMQProtocolHandler protocolHandler, final boolean noLocal, final boolean nowait) @@ -997,26 +958,27 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic } } - public void commitImpl() throws AMQException, FailoverException, TransportException + @Override public void commit() throws JMSException { - if( _txSize > 0 ) + checkTransacted(); + try { - messageAcknowledge(_txRangeSet, true); - _txRangeSet.clear(); - _txSize = 0; + if( _txSize > 0 ) + { + messageAcknowledge(_txRangeSet, true); + _txRangeSet.clear(); + _txSize = 0; + } + sendCommit(); } - - getQpidSession().setAutoSync(true); - try + catch (AMQException e) { - getQpidSession().txCommit(); + throw new JMSAMQException("Failed to commit: " + e.getMessage(), e); } - finally + catch (FailoverException e) { - getQpidSession().setAutoSync(false); + throw new JMSAMQException("Fail-over interrupted commit. Status of the commit is uncertain.", e); } - // We need to sync so that we get notify of an error. - sync(); } protected final boolean tagLE(long tag1, long tag2) @@ -1058,9 +1020,11 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic code = ee.getErrorCode().getValue(); } AMQException amqe = new AMQException(AMQConstant.getConstant(code), se.getMessage(), se.getCause()); + + _connection.exceptionReceived(amqe); + _currentException = amqe; } - _connection.exceptionReceived(_currentException); } public AMQMessageDelegateFactory getMessageDelegateFactory() @@ -1104,37 +1068,22 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic return match; } - public boolean isQueueExist(AMQDestination dest,QueueNode node,boolean assertNode) throws AMQException + public boolean isQueueExist(AMQDestination dest,QueueNode node,boolean assertNode) { boolean match = true; - try + QueueQueryResult result = getQpidSession().queueQuery(dest.getAddressName(), Option.NONE).get(); + match = dest.getAddressName().equals(result.getQueue()); + + if (match && assertNode) { - QueueQueryResult result = getQpidSession().queueQuery(dest.getAddressName(), Option.NONE).get(); - match = dest.getAddressName().equals(result.getQueue()); - - if (match && assertNode) - { - match = (result.getDurable() == node.isDurable()) && - (result.getAutoDelete() == node.isAutoDelete()) && - (result.getExclusive() == node.isExclusive()) && - (matchProps(result.getArguments(),node.getDeclareArgs())); - } - else if (match) - { - // should I use the queried details to update the local data structure. - } + match = (result.getDurable() == node.isDurable()) && + (result.getAutoDelete() == node.isAutoDelete()) && + (result.getExclusive() == node.isExclusive()) && + (matchProps(result.getArguments(),node.getDeclareArgs())); } - catch(SessionException e) + else if (match) { - if (e.getException().getErrorCode() == ExecutionErrorCode.RESOURCE_DELETED) - { - match = false; - } - else - { - throw new AMQException(AMQConstant.getConstant(e.getException().getErrorCode().getValue()), - "Error querying queue",e); - } + // should I use the queried details to update the local data structure. } return match; @@ -1200,22 +1149,6 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic int type = resolveAddressType(dest); - if (type == AMQDestination.QUEUE_TYPE && - dest.getLink().getReliability() == Reliability.UNSPECIFIED) - { - dest.getLink().setReliability(Reliability.AT_LEAST_ONCE); - } - else if (type == AMQDestination.TOPIC_TYPE && - dest.getLink().getReliability() == Reliability.UNSPECIFIED) - { - dest.getLink().setReliability(Reliability.UNRELIABLE); - } - else if (type == AMQDestination.TOPIC_TYPE && - dest.getLink().getReliability() == Reliability.AT_LEAST_ONCE) - { - throw new AMQException("AT-LEAST-ONCE is not yet supported for Topics"); - } - switch (type) { case AMQDestination.QUEUE_TYPE: @@ -1229,8 +1162,6 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic { setLegacyFiledsForQueueType(dest); send0_10QueueDeclare(dest,null,false,noWait); - sendQueueBind(dest.getAMQQueueName(), dest.getRoutingKey(), - null,dest.getExchangeName(),dest, false); break; } } @@ -1339,8 +1270,6 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic dest.getQueueName(),// should have one by now dest.getSubject(), Collections.<String,Object>emptyMap())); - sendQueueBind(dest.getAMQQueueName(), dest.getRoutingKey(), - null,dest.getExchangeName(),dest, false); } public void setLegacyFiledsForQueueType(AMQDestination dest) @@ -1378,26 +1307,5 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic sb.append(">"); return sb.toString(); } - - protected void acknowledgeImpl() - { - RangeSet range = gatherUnackedRangeSet(); - - if(range.size() > 0 ) - { - messageAcknowledge(range, true); - getQpidSession().sync(); - } - } - - @Override - void resubscribe() throws AMQException - { - // Also reset the delivery tag tracker, to insure we dont - // return the first <total number of msgs received on session> - // messages sent by the brokers following the first rollback - // after failover - _highestDeliveryTag.set(-1); - super.resubscribe(); - } + } 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 369c8a6e9d..f41b1c94fa 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 @@ -38,7 +38,6 @@ import org.apache.qpid.client.message.ReturnMessage; import org.apache.qpid.client.message.UnprocessedMessage; import org.apache.qpid.client.protocol.AMQProtocolHandler; import org.apache.qpid.client.state.AMQState; -import org.apache.qpid.client.state.AMQStateManager; import org.apache.qpid.client.state.listener.SpecificMethodFrameListener; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.framing.AMQFrame; @@ -76,12 +75,12 @@ import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91; import org.apache.qpid.jms.Session; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.transport.TransportException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> { + /** Used for debugging. */ private static final Logger _logger = LoggerFactory.getLogger(AMQSession.class); @@ -91,7 +90,7 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B * @param con The connection on which to create the session. * @param channelId The unique identifier for the session. * @param transacted Indicates whether or not the session is transactional. - * @param acknowledgeMode The acknowledgement mode for the session. + * @param acknowledgeMode The acknoledgement mode for the session. * @param messageFactoryRegistry The message factory factory for the session. * @param defaultPrefetchHighMark The maximum number of messages to prefetched before suspending the session. * @param defaultPrefetchLowMark The number of prefetched messages at which to resume the session. @@ -109,7 +108,7 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B * @param con The connection on which to create the session. * @param channelId The unique identifier for the session. * @param transacted Indicates whether or not the session is transactional. - * @param acknowledgeMode The acknowledgement mode for the session. + * @param acknowledgeMode The acknoledgement mode for the session. * @param defaultPrefetchHigh The maximum number of messages to prefetched before suspending the session. * @param defaultPrefetchLow The number of prefetched messages at which to resume the session. */ @@ -125,20 +124,6 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B return getProtocolHandler().getProtocolVersion(); } - protected void acknowledgeImpl() - { - while (true) - { - Long tag = _unacknowledgedMessageTags.poll(); - if (tag == null) - { - break; - } - - acknowledgeMessage(tag, false); - } - } - public void acknowledgeMessage(long deliveryTag, boolean multiple) { BasicAckBody body = getMethodRegistry().createBasicAckBody(deliveryTag, multiple); @@ -168,7 +153,7 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B // 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 already in the process of + // 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) @@ -184,20 +169,8 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B } } - public void commitImpl() throws AMQException, FailoverException, TransportException + public void sendCommit() throws AMQException, FailoverException { - // Acknowledge all delivered messages - while (true) - { - Long tag = _deliveredMessageTags.poll(); - if (tag == null) - { - break; - } - - acknowledgeMessage(tag, false); - } - final AMQProtocolHandler handler = getProtocolHandler(); handler.syncWrite(getProtocolHandler().getMethodRegistry().createTxCommitBody().generateFrame(_channelId), TxCommitOkBody.class); @@ -427,12 +400,12 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B public BasicMessageProducer_0_8 createMessageProducer(final Destination destination, final boolean mandatory, - final boolean immediate, long producerId) throws JMSException + final boolean immediate, final boolean waitUntilSent, long producerId) throws JMSException { try { return new BasicMessageProducer_0_8(_connection, (AMQDestination) destination, _transacted, _channelId, - this, getProtocolHandler(), producerId, immediate, mandatory); + this, getProtocolHandler(), producerId, immediate, mandatory, waitUntilSent); } catch (AMQException e) { @@ -604,18 +577,6 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B } - @Override - protected void deleteTemporaryDestination(final TemporaryDestination amqQueue) - throws JMSException - { - // Currently TemporaryDestination is set to be auto-delete which, for 0-8..0-9-1, means that the queue will be deleted - // by the server when there are no more subscriptions to that queue/topic (rather than when the client disconnects). - // This is not quite right for JMSCompliance as the queue/topic should remain until the connection closes, or the - // client explicitly deletes it. - - /* intentional no-op */ - } - public boolean isQueueBound(String exchangeName, String queueName, String bindingKey, Map<String, Object> args) throws JMSException { @@ -623,34 +584,4 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B queueName == null ? null : new AMQShortString(queueName), bindingKey == null ? null : new AMQShortString(bindingKey)); } - - - public AMQException getLastException() - { - // if the Connection has closed then we should throw any exception that - // has occurred that we were not waiting for - AMQStateManager manager = _connection.getProtocolHandler() - .getStateManager(); - - Exception e = manager.getLastException(); - if (manager.getCurrentState().equals(AMQState.CONNECTION_CLOSED) - && e != null) - { - if (e instanceof AMQException) - { - return (AMQException) e; - } - else - { - AMQException amqe = new AMQException(AMQConstant - .getConstant(AMQConstant.INTERNAL_ERROR.getCode()), - e.getMessage(), e.getCause()); - return amqe; - } - } - else - { - return null; - } - } } diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryQueue.java b/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryQueue.java index 28f838057e..f54cb782c8 100644 --- a/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryQueue.java +++ b/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryQueue.java @@ -20,13 +20,14 @@ */ package org.apache.qpid.client; -import java.util.UUID; - import javax.jms.JMSException; import javax.jms.TemporaryQueue; import org.apache.qpid.framing.AMQShortString; +import java.util.Random; +import java.util.UUID; + /** AMQ implementation of a TemporaryQueue. */ final class AMQTemporaryQueue extends AMQQueue implements TemporaryQueue, TemporaryDestination { @@ -49,15 +50,11 @@ final class AMQTemporaryQueue extends AMQQueue implements TemporaryQueue, Tempor { throw new JMSException("Temporary Queue has consumers so cannot be deleted"); } + _deleted = true; - try - { - _session.deleteTemporaryDestination(this); - } - finally - { - _deleted = true; - } + // Currently TemporaryQueue is set to be auto-delete which means that the queue will be deleted + // by the server when there are no more subscriptions to that queue. This is probably not + // quite right for JMSCompliance. } public AMQSession getSession() diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryTopic.java b/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryTopic.java index db54b320dc..7b5781530b 100644 --- a/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryTopic.java +++ b/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryTopic.java @@ -53,14 +53,10 @@ class AMQTemporaryTopic extends AMQTopic implements TemporaryTopic, TemporaryDes throw new JMSException("Temporary Topic has consumers so cannot be deleted"); } - try - { - _session.deleteTemporaryDestination(this); - } - finally - { - _deleted = true; - } + _deleted = true; + // Currently TemporaryQueue is set to be auto-delete which means that the queue will be deleted + // by the server when there are no more subscriptions to that queue. This is probably not + // quite right for JMSCompliance. } public AMQSession getSession() diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java b/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java index 780dbcafc2..6217cb534a 100644 --- a/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java +++ b/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java @@ -22,7 +22,6 @@ package org.apache.qpid.client; import java.net.URISyntaxException; -import javax.jms.InvalidDestinationException; import javax.jms.JMSException; import javax.jms.Topic; @@ -96,47 +95,39 @@ public class AMQTopic extends AMQDestination implements Topic super(exchangeName, exchangeClass, routingKey, isExclusive, isAutoDelete, queueName, isDurable,bindingKeys); } - public static AMQTopic createDurableTopic(Topic topic, String subscriptionName, AMQConnection connection) + public static AMQTopic createDurableTopic(AMQTopic topic, String subscriptionName, AMQConnection connection) throws JMSException { - if (topic instanceof AMQDestination && topic instanceof javax.jms.Topic) + if (topic.getDestSyntax() == DestSyntax.ADDR) { - AMQDestination qpidTopic = (AMQDestination)topic; - if (qpidTopic.getDestSyntax() == DestSyntax.ADDR) + try { - try - { - AMQTopic t = new AMQTopic(qpidTopic.getAddress()); - AMQShortString queueName = getDurableTopicQueueName(subscriptionName, connection); - // link is never null if dest was created using an address string. - t.getLink().setName(queueName.asString()); - t.getSourceNode().setAutoDelete(false); - t.getSourceNode().setDurable(true); - - // The legacy fields are also populated just in case. - t.setQueueName(queueName); - t.setAutoDelete(false); - t.setDurable(true); - return t; - } - catch(Exception e) - { - JMSException ex = new JMSException("Error creating durable topic"); - ex.initCause(e); - ex.setLinkedException(e); - throw ex; - } + AMQTopic t = new AMQTopic(topic.getAddress()); + AMQShortString queueName = getDurableTopicQueueName(subscriptionName, connection); + // link is never null if dest was created using an address string. + t.getLink().setName(queueName.asString()); + t.getSourceNode().setAutoDelete(false); + t.getSourceNode().setDurable(true); + + // The legacy fields are also populated just in case. + t.setQueueName(queueName); + t.setAutoDelete(false); + t.setDurable(true); + return t; } - else + catch(Exception e) { - return new AMQTopic(qpidTopic.getExchangeName(), qpidTopic.getRoutingKey(), false, - getDurableTopicQueueName(subscriptionName, connection), - true); + JMSException ex = new JMSException("Error creating durable topic"); + ex.initCause(e); + ex.setLinkedException(e); + throw ex; } } else { - throw new InvalidDestinationException("The destination object used is not from this provider or of type javax.jms.Topic"); + return new AMQTopic(topic.getExchangeName(), topic.getRoutingKey(), false, + getDurableTopicQueueName(subscriptionName, connection), + true); } } @@ -147,17 +138,13 @@ public class AMQTopic extends AMQDestination implements Topic public String getTopicName() throws JMSException { - if (getRoutingKey() != null) + if (super.getRoutingKey() == null && super.getSubject() != null) { - return getRoutingKey().asString(); - } - else if (getSubject() != null) - { - return getSubject(); + return super.getSubject(); } else { - return null; + return super.getRoutingKey().toString(); } } @@ -176,18 +163,12 @@ public class AMQTopic extends AMQDestination implements Topic public AMQShortString getRoutingKey() { - if (super.getRoutingKey() != null) - { - return super.getRoutingKey(); - } - else if (getSubject() != null) + if (super.getRoutingKey() == null && super.getSubject() != null) { - return new AMQShortString(getSubject()); + return new AMQShortString(super.getSubject()); } else { - setRoutingKey(new AMQShortString("")); - setSubject(""); return super.getRoutingKey(); } } 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 3b807591b0..0a78403268 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 @@ -27,7 +27,6 @@ import org.apache.qpid.client.protocol.AMQProtocolHandler; import org.apache.qpid.framing.*; import org.apache.qpid.jms.MessageConsumer; import org.apache.qpid.jms.Session; -import org.apache.qpid.transport.TransportException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +36,10 @@ import javax.jms.MessageListener; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.SortedSet; import java.util.ArrayList; +import java.util.Collections; +import java.util.TreeSet; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -115,10 +117,29 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa protected final int _acknowledgeMode; /** + * Number of messages unacknowledged in DUPS_OK_ACKNOWLEDGE mode + */ + private int _outstanding; + + /** + * Switch to enable sending of acknowledgements when using DUPS_OK_ACKNOWLEDGE mode. Enabled when _outstannding + * number of msgs >= _prefetchHigh and disabled at < _prefetchLow + */ + private boolean _dups_ok_acknowledge_send; + + /** * List of tags delievered, The last of which which should be acknowledged on commit in transaction mode. */ private ConcurrentLinkedQueue<Long> _receivedDeliveryTags = new ConcurrentLinkedQueue<Long>(); + /** The last tag that was "multiple" acknowledged on this session (if transacted) */ + private long _lastAcked; + + /** set of tags which have previously been acked; but not part of the multiple ack (transacted mode only) */ + private final SortedSet<Long> _previouslyAcked = new TreeSet<Long>(); + + private final Object _commitLock = new Object(); + /** * The thread that was used to call receive(). This is important for being able to interrupt that thread if a * receive() is in progress. @@ -268,6 +289,17 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa } } + protected void preApplicationProcessing(AbstractJMSMessage jmsMsg) throws JMSException + { + if (_session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) + { + _session.addUnacknowledgedMessage(jmsMsg.getDeliveryTag()); + } + + _session.setInRecovery(false); + preDeliver(jmsMsg); + } + /** * @param immediate if true then return immediately if the connection is failing over * @@ -290,14 +322,14 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa } } - if (isMessageListenerSet()) + if (!_receiving.compareAndSet(false, true)) { - throw new javax.jms.IllegalStateException("A listener has already been set."); + throw new javax.jms.IllegalStateException("Another thread is already receiving."); } - if (!_receiving.compareAndSet(false, true)) + if (isMessageListenerSet()) { - throw new javax.jms.IllegalStateException("Another thread is already receiving."); + throw new javax.jms.IllegalStateException("A listener has already been set."); } _receivingThread = Thread.currentThread(); @@ -376,7 +408,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa final AbstractJMSMessage m = returnMessageOrThrow(o); if (m != null) { - preDeliver(m); + preApplicationProcessing(m); postDeliver(m); } return m; @@ -387,10 +419,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa return null; } - catch(TransportException e) - { - throw _session.toJMSException("Exception while receiving:" + e.getMessage(), e); - } finally { releaseReceiving(); @@ -449,7 +477,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa final AbstractJMSMessage m = returnMessageOrThrow(o); if (m != null) { - preDeliver(m); + preApplicationProcessing(m); postDeliver(m); } @@ -461,10 +489,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa return null; } - catch(TransportException e) - { - throw _session.toJMSException("Exception while receiving:" + e.getMessage(), e); - } finally { releaseReceiving(); @@ -547,7 +571,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa if (!_session.isClosed() || _session.isClosing()) { sendCancel(); - cleanupQueue(); } } catch (AMQException e) @@ -558,10 +581,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa { throw new JMSAMQException("FailoverException interrupted basic cancel.", e); } - catch (TransportException e) - { - throw _session.toJMSException("Exception while closing consumer: " + e.getMessage(), e); - } } } else @@ -589,8 +608,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa } abstract void sendCancel() throws AMQException, FailoverException; - - abstract void cleanupQueue() throws AMQException, FailoverException; /** * Called when you need to invalidate a consumer. Used for example when failover has occurred and the client has @@ -701,7 +718,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa { if (isMessageListenerSet()) { - preDeliver(jmsMessage); + preApplicationProcessing(jmsMessage); getMessageListener().onMessage(jmsMessage); postDeliver(jmsMessage); } @@ -725,42 +742,49 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa } } - protected void preDeliver(AbstractJMSMessage msg) + void preDeliver(AbstractJMSMessage msg) { - _session.setInRecovery(false); - switch (_acknowledgeMode) { + case Session.PRE_ACKNOWLEDGE: _session.acknowledgeMessage(msg.getDeliveryTag(), false); break; - case Session.AUTO_ACKNOWLEDGE: - //fall through - case Session.DUPS_OK_ACKNOWLEDGE: - _session.addUnacknowledgedMessage(msg.getDeliveryTag()); - break; + case Session.CLIENT_ACKNOWLEDGE: // we set the session so that when the user calls acknowledge() it can call the method on session // to send out the appropriate frame msg.setAMQSession(_session); - _session.addUnacknowledgedMessage(msg.getDeliveryTag()); - _session.markDirty(); break; case Session.SESSION_TRANSACTED: - _session.addDeliveredMessage(msg.getDeliveryTag()); - _session.markDirty(); - break; - case Session.NO_ACKNOWLEDGE: - //do nothing. - //path used for NO-ACK consumers, and browsers (see constructor). + if (isNoConsume()) + { + _session.acknowledgeMessage(msg.getDeliveryTag(), false); + } + else + { + _session.addDeliveredMessage(msg.getDeliveryTag()); + _session.markDirty(); + } + break; } + } - void postDeliver(AbstractJMSMessage msg) + void postDeliver(AbstractJMSMessage msg) throws JMSException { switch (_acknowledgeMode) { + + case Session.CLIENT_ACKNOWLEDGE: + if (isNoConsume()) + { + _session.acknowledgeMessage(msg.getDeliveryTag(), false); + } + _session.markDirty(); + break; + case Session.DUPS_OK_ACKNOWLEDGE: case Session.AUTO_ACKNOWLEDGE: // we do not auto ack a message if the application code called recover() @@ -798,6 +822,63 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa return null; } + /** + * Acknowledge up to last message delivered (if any). Used when commiting. + */ + void acknowledgeDelivered() + { + synchronized(_commitLock) + { + ArrayList<Long> tagsToAck = new ArrayList<Long>(); + + while (!_receivedDeliveryTags.isEmpty()) + { + tagsToAck.add(_receivedDeliveryTags.poll()); + } + + Collections.sort(tagsToAck); + + long prevAcked = _lastAcked; + long oldAckPoint = -1; + + while(oldAckPoint != prevAcked) + { + oldAckPoint = prevAcked; + + Iterator<Long> tagsToAckIterator = tagsToAck.iterator(); + + while(tagsToAckIterator.hasNext() && tagsToAckIterator.next() == prevAcked+1) + { + tagsToAckIterator.remove(); + prevAcked++; + } + + Iterator<Long> previousAckIterator = _previouslyAcked.iterator(); + while(previousAckIterator.hasNext() && previousAckIterator.next() == prevAcked+1) + { + previousAckIterator.remove(); + prevAcked++; + } + + } + if(prevAcked != _lastAcked) + { + _session.acknowledgeMessage(prevAcked, true); + _lastAcked = prevAcked; + } + + Iterator<Long> tagsToAckIterator = tagsToAck.iterator(); + + while(tagsToAckIterator.hasNext()) + { + Long tag = tagsToAckIterator.next(); + _session.acknowledgeMessage(tag, false); + _previouslyAcked.add(tag); + } + } + } + + void notifyError(Throwable cause) { // synchronized (_closed) @@ -876,7 +957,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa public boolean isNoConsume() { - return _noConsume; + return _noConsume || _destination.isBrowseOnly() ; } public void rollback() 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 548e274571..b5f3501e5a 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 @@ -19,11 +19,10 @@ package org.apache.qpid.client; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.qpid.client.AMQDestination.AddressOption; import org.apache.qpid.client.AMQDestination.DestSyntax; -import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.message.*; import org.apache.qpid.client.protocol.AMQProtocolHandler; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; import org.apache.qpid.AMQInternalException; @@ -66,13 +65,19 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM private boolean _preAcquire = true; /** + * Indicate whether this consumer is started. + */ + private boolean _isStarted = false; + + /** * Specify whether this consumer is performing a sync receive */ private final AtomicBoolean _syncReceive = new AtomicBoolean(false); private String _consumerTagString; private long capacity = 0; - + + //--- constructor protected BasicMessageConsumer_0_10(int channelId, AMQConnection connection, AMQDestination destination, String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session, AMQProtocolHandler protocolHandler, @@ -98,6 +103,7 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM _preAcquire = false; } } + _isStarted = connection.started(); // Destination setting overrides connection defaults if (destination.getDestSyntax() == DestSyntax.ADDR && @@ -150,20 +156,13 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM { if (isMessageListenerSet() && capacity == 0) { - messageFlow(); + _0_10session.getQpidSession().messageFlow(getConsumerTagString(), + MessageCreditUnit.MESSAGE, 1, + Option.UNRELIABLE); } _logger.debug("messageOk, trying to notify"); super.notifyMessage(jmsMessage); } - else - { - // if we are synchronously waiting for a message - // and messages are not pre-fetched we then need to request another one - if(capacity == 0) - { - messageFlow(); - } - } } catch (AMQException e) { @@ -172,6 +171,8 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM } } + //----- overwritten methods + /** * This method is invoked when this consumer is stopped. * It tells the broker to stop delivering messages to this consumer. @@ -201,18 +202,11 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM super.notifyMessage(messageFrame); } - @Override - protected void preDeliver(AbstractJMSMessage jmsMsg) + @Override protected void preApplicationProcessing(AbstractJMSMessage jmsMsg) throws JMSException { - super.preDeliver(jmsMsg); - - if (_acknowledgeMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE) + super.preApplicationProcessing(jmsMsg); + if (!_session.getTransacted() && _session.getAcknowledgeMode() != org.apache.qpid.jms.Session.CLIENT_ACKNOWLEDGE) { - //For 0-10 we need to ensure that all messages are indicated processed in some way to - //ensure their AMQP command-id is marked completed, and so we must send a completion - //even for no-ack messages even though there isnt actually an 'acknowledgement' occurring. - //Add message to the unacked message list to ensure we dont lose record of it before - //sending a completion of some sort. _session.addUnacknowledgedMessage(jmsMsg.getDeliveryTag()); } } @@ -224,6 +218,7 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM return _messageFactory.createMessage(msg.getMessageTransfer()); } + // private methods /** * Check whether a message can be delivered to this consumer. * @@ -252,7 +247,6 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM _logger.debug("messageOk " + messageOk); _logger.debug("_preAcquire " + _preAcquire); } - if (!messageOk) { if (_preAcquire) @@ -269,12 +263,19 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM { if (_logger.isDebugEnabled()) { - _logger.debug("filterMessage - not ack'ing message as not acquired"); + _logger.debug("Message not OK, releasing"); } - flushUnwantedMessage(message); + releaseMessage(message); + } + // if we are syncrhonously waiting for a message + // and messages are not prefetched we then need to request another one + if(capacity == 0) + { + _0_10session.getQpidSession().messageFlow(getConsumerTagString(), + MessageCreditUnit.MESSAGE, 1, + Option.UNRELIABLE); } } - // now we need to acquire this message if needed // this is the case of queue with a message selector set if (!_preAcquire && messageOk && !isNoConsume()) @@ -286,7 +287,6 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM messageOk = acquireMessage(message); _logger.debug("filterMessage - message acquire status : " + messageOk); } - return messageOk; } @@ -297,38 +297,38 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM * @param message The message to be acknowledged * @throws AMQException If the message cannot be acquired due to some internal error. */ - private void acknowledgeMessage(final AbstractJMSMessage message) throws AMQException + private void acknowledgeMessage(AbstractJMSMessage message) throws AMQException { - final RangeSet ranges = new RangeSet(); - ranges.add((int) message.getDeliveryTag()); - _0_10session.messageAcknowledge - (ranges, - _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE); - - final AMQException amqe = _0_10session.getCurrentException(); - if (amqe != null) + if (!_preAcquire) { - throw amqe; + RangeSet ranges = new RangeSet(); + ranges.add((int) message.getDeliveryTag()); + _0_10session.messageAcknowledge + (ranges, + _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE); + + AMQException amqe = _0_10session.getCurrentException(); + if (amqe != null) + { + throw amqe; + } } } /** - * Flush an unwanted message. For 0-10 we need to ensure that all messages are indicated - * processed to ensure their AMQP command-id is marked completed. + * Release a message * - * @param message The unwanted message to be flushed - * @throws AMQException If the unwanted message cannot be flushed due to some internal error. + * @param message The message to be released + * @throws AMQException If the message cannot be released due to some internal error. */ - private void flushUnwantedMessage(final AbstractJMSMessage message) throws AMQException + private void releaseMessage(AbstractJMSMessage message) throws AMQException { - final RangeSet ranges = new RangeSet(); - ranges.add((int) message.getDeliveryTag()); - _0_10session.flushProcessed(ranges,false); - - final AMQException amqe = _0_10session.getCurrentException(); - if (amqe != null) + if (_preAcquire) { - throw amqe; + RangeSet ranges = new RangeSet(); + ranges.add((int) message.getDeliveryTag()); + _0_10session.getQpidSession().messageRelease(ranges); + _0_10session.sync(); } } @@ -339,52 +339,44 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM * @return true if the message has been acquired, false otherwise. * @throws AMQException If the message cannot be acquired due to some internal error. */ - private boolean acquireMessage(final AbstractJMSMessage message) throws AMQException + private boolean acquireMessage(AbstractJMSMessage message) throws AMQException { boolean result = false; - final RangeSet ranges = new RangeSet(); - ranges.add((int) message.getDeliveryTag()); + if (!_preAcquire) + { + RangeSet ranges = new RangeSet(); + ranges.add((int) message.getDeliveryTag()); - final Acquired acq = _0_10session.getQpidSession().messageAcquire(ranges).get(); + Acquired acq = _0_10session.getQpidSession().messageAcquire(ranges).get(); - final RangeSet acquired = acq.getTransfers(); - if (acquired != null && acquired.size() > 0) - { - result = true; + RangeSet acquired = acq.getTransfers(); + if (acquired != null && acquired.size() > 0) + { + result = true; + } } return result; } - private void messageFlow() - { - _0_10session.getQpidSession().messageFlow(getConsumerTagString(), - MessageCreditUnit.MESSAGE, 1, - Option.UNRELIABLE); - } public void setMessageListener(final MessageListener messageListener) throws JMSException { super.setMessageListener(messageListener); - try + if (messageListener != null && capacity == 0) { - if (messageListener != null && capacity == 0) - { - messageFlow(); - } - if (messageListener != null && !_synchronousQueue.isEmpty()) - { - Iterator messages=_synchronousQueue.iterator(); - while (messages.hasNext()) - { - AbstractJMSMessage message=(AbstractJMSMessage) messages.next(); - messages.remove(); - _session.rejectMessage(message, true); - } - } + _0_10session.getQpidSession().messageFlow(getConsumerTagString(), + MessageCreditUnit.MESSAGE, 1, + Option.UNRELIABLE); } - catch(TransportException e) + if (messageListener != null && !_synchronousQueue.isEmpty()) { - throw _session.toJMSException("Exception while setting message listener:"+ e.getMessage(), e); + Iterator messages=_synchronousQueue.iterator(); + while (messages.hasNext()) + { + AbstractJMSMessage message=(AbstractJMSMessage) messages.next(); + messages.remove(); + _session.rejectMessage(message, true); + } } } @@ -392,7 +384,9 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM { if (_0_10session.isStarted() && _syncReceive.get()) { - messageFlow(); + _0_10session.getQpidSession().messageFlow + (getConsumerTagString(), MessageCreditUnit.MESSAGE, 1, + Option.UNRELIABLE); } } @@ -413,7 +407,9 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM } if (_0_10session.isStarted() && capacity == 0 && _synchronousQueue.isEmpty()) { - messageFlow(); + _0_10session.getQpidSession().messageFlow(getConsumerTagString(), + MessageCreditUnit.MESSAGE, 1, + Option.UNRELIABLE); } Object o = super.getMessageFromQueue(l); if (o == null && _0_10session.isStarted()) @@ -444,7 +440,7 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM return o; } - void postDeliver(AbstractJMSMessage msg) + void postDeliver(AbstractJMSMessage msg) throws JMSException { super.postDeliver(msg); if (_acknowledgeMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE && !_session.isInRecovery()) @@ -453,8 +449,10 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM } if (_acknowledgeMode == org.apache.qpid.jms.Session.AUTO_ACKNOWLEDGE && - !_session.isInRecovery() && _session.getAMQConnection().getSyncAck()) + !_session.isInRecovery() && + _session.getAMQConnection().getSyncAck()) { + ((AMQSession_0_10) getSession()).flushAcknowledgments(); ((AMQSession_0_10) getSession()).getQpidSession().sync(); } } @@ -511,18 +509,4 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM return _exclusive; } } - - void cleanupQueue() throws AMQException, FailoverException - { - AMQDestination dest = this.getDestination(); - if (dest != null && dest.getDestSyntax() == AMQDestination.DestSyntax.ADDR) - { - if (dest.getDelete() == AddressOption.ALWAYS || - dest.getDelete() == AddressOption.RECEIVER ) - { - ((AMQSession_0_10) getSession()).getQpidSession().queueDelete( - this.getDestination().getQueueName()); - } - } - } } 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 00acd5e866..cdbf57769d 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 @@ -88,8 +88,4 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe return receive(); } - void cleanupQueue() throws AMQException, FailoverException - { - - } } 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 bf4de782a5..8756ac4d05 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 @@ -39,7 +39,6 @@ import org.apache.qpid.client.message.AbstractJMSMessage; import org.apache.qpid.client.message.MessageConverter; import org.apache.qpid.client.protocol.AMQProtocolHandler; import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.transport.TransportException; import org.apache.qpid.util.UUIDGen; import org.apache.qpid.util.UUIDs; import org.slf4j.Logger; @@ -114,6 +113,8 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac private final boolean _mandatory; + private final boolean _waitUntilSent; + private boolean _disableMessageId; private UUIDGen _messageIdGenerator = UUIDs.newGenerator(); @@ -125,7 +126,8 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac 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) throws AMQException + AMQSession session, AMQProtocolHandler protocolHandler, long producerId, boolean immediate, boolean mandatory, + boolean waitUntilSent) throws AMQException { _connection = connection; _destination = destination; @@ -141,6 +143,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac _immediate = immediate; _mandatory = mandatory; + _waitUntilSent = waitUntilSent; _userID = connection.getUsername(); setPublishMode(); } @@ -263,7 +266,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac return _destination; } - public void close() throws JMSException + public void close() { _closed.set(true); _session.deregisterProducer(_producerId); @@ -360,6 +363,19 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac } } + public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, + boolean mandatory, boolean immediate, boolean waitUntilSent) throws JMSException + { + checkPreConditions(); + checkDestination(destination); + synchronized (_connection.getFailoverMutex()) + { + validateDestination(destination); + sendImpl((AMQDestination) destination, message, deliveryMode, priority, timeToLive, mandatory, immediate, + waitUntilSent); + } + } + private AbstractJMSMessage convertToNativeMessage(Message message) throws JMSException { if (message instanceof AbstractJMSMessage) @@ -434,6 +450,12 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac } } + protected void sendImpl(AMQDestination destination, Message message, int deliveryMode, int priority, long timeToLive, + boolean mandatory, boolean immediate) throws JMSException + { + sendImpl(destination, message, deliveryMode, priority, timeToLive, mandatory, immediate, _waitUntilSent); + } + /** * The caller of this method must hold the failover mutex. * @@ -448,13 +470,23 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac * @throws JMSException */ protected void sendImpl(AMQDestination destination, Message origMessage, int deliveryMode, int priority, long timeToLive, - boolean mandatory, boolean immediate) throws JMSException + boolean mandatory, boolean immediate, boolean wait) throws JMSException { checkTemporaryDestination(destination); origMessage.setJMSDestination(destination); AbstractJMSMessage message = convertToNativeMessage(origMessage); + if (_transacted) + { + if (_session.hasFailedOver() && _session.isDirty()) + { + throw new JMSAMQException("Failover has occurred and session is dirty so unable to send.", + new AMQSessionDirtyException("Failover has occurred and session is dirty " + + "so unable to send.")); + } + } + UUID messageId = null; if (_disableMessageId) { @@ -466,14 +498,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac message.setJMSMessageID(messageId); } - try - { - sendMessage(destination, origMessage, message, messageId, deliveryMode, priority, timeToLive, mandatory, immediate); - } - catch (TransportException e) - { - throw getSession().toJMSException("Exception whilst sending:" + e.getMessage(), e); - } + sendMessage(destination, origMessage, message, messageId, deliveryMode, priority, timeToLive, mandatory, immediate, wait); if (message != origMessage) { @@ -493,7 +518,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac abstract void sendMessage(AMQDestination destination, Message origMessage, AbstractJMSMessage message, UUID messageId, int deliveryMode, int priority, long timeToLive, boolean mandatory, - boolean immediate) throws JMSException; + boolean immediate, boolean wait) throws JMSException; private void checkTemporaryDestination(AMQDestination destination) throws JMSException { @@ -571,13 +596,6 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac public boolean isBound(AMQDestination destination) throws JMSException { - try - { - return _session.isQueueBound(destination.getExchangeName(), null, destination.getRoutingKey()); - } - catch (TransportException e) - { - throw getSession().toJMSException("Exception whilst checking destination binding:" + e.getMessage(), e); - } + return _session.isQueueBound(destination.getExchangeName(), null, destination.getRoutingKey()); } } 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 57f64c2f92..53c0457120 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 @@ -19,7 +19,6 @@ package org.apache.qpid.client; import static org.apache.qpid.transport.Option.NONE; import static org.apache.qpid.transport.Option.SYNC; -import static org.apache.qpid.transport.Option.UNRELIABLE; import java.nio.ByteBuffer; import java.util.HashMap; @@ -31,12 +30,9 @@ import javax.jms.JMSException; import javax.jms.Message; import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination.AddressOption; import org.apache.qpid.client.AMQDestination.DestSyntax; import org.apache.qpid.client.message.AMQMessageDelegate_0_10; import org.apache.qpid.client.message.AbstractJMSMessage; -import org.apache.qpid.client.message.QpidMessageProperties; -import org.apache.qpid.client.messaging.address.Link.Reliability; import org.apache.qpid.client.protocol.AMQProtocolHandler; import org.apache.qpid.transport.DeliveryProperties; import org.apache.qpid.transport.Header; @@ -46,7 +42,6 @@ import org.apache.qpid.transport.MessageDeliveryMode; import org.apache.qpid.transport.MessageDeliveryPriority; import org.apache.qpid.transport.MessageProperties; import org.apache.qpid.transport.Option; -import org.apache.qpid.transport.TransportException; import org.apache.qpid.util.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,9 +56,10 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer BasicMessageProducer_0_10(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId, AMQSession session, AMQProtocolHandler protocolHandler, long producerId, - boolean immediate, boolean mandatory) throws AMQException + boolean immediate, boolean mandatory, boolean waitUntilSent) throws AMQException { - super(connection, destination, transacted, channelId, session, protocolHandler, producerId, immediate, mandatory); + super(connection, destination, transacted, channelId, session, protocolHandler, producerId, immediate, + mandatory, waitUntilSent); userIDBytes = Strings.toUTF8(_userID); } @@ -72,15 +68,12 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer { if (destination.getDestSyntax() == DestSyntax.BURL) { - if (getSession().isDeclareExchanges()) - { - String name = destination.getExchangeName().toString(); - ((AMQSession_0_10) getSession()).getQpidSession().exchangeDeclare - (name, - destination.getExchangeClass().toString(), - null, null, - name.startsWith("amq.") ? Option.PASSIVE : Option.NONE); - } + String name = destination.getExchangeName().toString(); + ((AMQSession_0_10) getSession()).getQpidSession().exchangeDeclare + (name, + destination.getExchangeClass().toString(), + null, null, + name.startsWith("amq.") ? Option.PASSIVE : Option.NONE); } else { @@ -103,7 +96,7 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer */ void sendMessage(AMQDestination destination, Message origMessage, AbstractJMSMessage message, UUID messageId, int deliveryMode, int priority, long timeToLive, boolean mandatory, - boolean immediate) throws JMSException + boolean immediate, boolean wait) throws JMSException { message.prepareForSending(); @@ -178,7 +171,7 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer if (destination.getDestSyntax() == AMQDestination.DestSyntax.ADDR && (destination.getSubject() != null || - (messageProps.getApplicationHeaders() != null && messageProps.getApplicationHeaders().get(QpidMessageProperties.QPID_SUBJECT) != null)) + (messageProps.getApplicationHeaders() != null && messageProps.getApplicationHeaders().get("qpid.subject") != null)) ) { Map<String,Object> appProps = messageProps.getApplicationHeaders(); @@ -188,21 +181,20 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer messageProps.setApplicationHeaders(appProps); } - if (appProps.get(QpidMessageProperties.QPID_SUBJECT) == null) + if (appProps.get("qpid.subject") == null) { // use default subject in address string - appProps.put(QpidMessageProperties.QPID_SUBJECT,destination.getSubject()); + appProps.put("qpid.subject",destination.getSubject()); } - if (destination.getAddressType() == AMQDestination.TOPIC_TYPE) + if (destination.getTargetNode().getType() == AMQDestination.TOPIC_TYPE) { deliveryProp.setRoutingKey((String) - messageProps.getApplicationHeaders().get(QpidMessageProperties.QPID_SUBJECT)); + messageProps.getApplicationHeaders().get("qpid.subject")); } } - - ByteBuffer data = message.getData(); - messageProps.setContentLength(data.remaining()); + + messageProps.setContentLength(message.getContentLength()); // send the message try @@ -218,17 +210,14 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer deliveryMode == DeliveryMode.PERSISTENT) ); - boolean unreliable = (destination.getDestSyntax() == DestSyntax.ADDR) && - (destination.getLink().getReliability() == Reliability.UNRELIABLE); - - - ByteBuffer buffer = data == null ? ByteBuffer.allocate(0) : data.slice(); + org.apache.mina.common.ByteBuffer data = message.getData(); + ByteBuffer buffer = data == null ? ByteBuffer.allocate(0) : data.buf().slice(); ssn.messageTransfer(destination.getExchangeName() == null ? "" : destination.getExchangeName().toString(), MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED, new Header(deliveryProp, messageProps), - buffer, sync ? SYNC : NONE, unreliable ? UNRELIABLE : NONE); + buffer, sync ? SYNC : NONE); if (sync) { ssn.sync(); @@ -245,34 +234,10 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer } } - @Override + public boolean isBound(AMQDestination destination) throws JMSException { return _session.isQueueBound(destination); } - - @Override - public void close() throws JMSException - { - super.close(); - AMQDestination dest = _destination; - if (dest != null && dest.getDestSyntax() == AMQDestination.DestSyntax.ADDR) - { - if (dest.getDelete() == AddressOption.ALWAYS || - dest.getDelete() == AddressOption.SENDER ) - { - try - { - ((AMQSession_0_10) getSession()).getQpidSession().queueDelete( - _destination.getQueueName()); - } - catch(TransportException e) - { - throw getSession().toJMSException("Exception while closing producer:" + e.getMessage(), e); - } - } - } - } - } 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 34d2ade723..27f7486890 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 @@ -27,13 +27,14 @@ import javax.jms.Message; import javax.jms.Topic; import javax.jms.Queue; -import java.nio.ByteBuffer; - +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.client.message.AbstractJMSMessage; +import org.apache.qpid.client.message.AMQMessageDelegate; import org.apache.qpid.client.message.AMQMessageDelegate_0_8; import org.apache.qpid.client.protocol.AMQProtocolHandler; import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicConsumeBody; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.CompositeAMQDataBlock; @@ -45,9 +46,10 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer { BasicMessageProducer_0_8(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId, - AMQSession session, AMQProtocolHandler protocolHandler, long producerId, boolean immediate, boolean mandatory) throws AMQException + AMQSession session, AMQProtocolHandler protocolHandler, long producerId, boolean immediate, boolean mandatory, + boolean waitUntilSent) throws AMQException { - super(connection, destination,transacted,channelId,session, protocolHandler, producerId, immediate, mandatory); + super(connection, destination,transacted,channelId,session, protocolHandler, producerId, immediate, mandatory,waitUntilSent); } void declareDestination(AMQDestination destination) @@ -72,7 +74,7 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer void sendMessage(AMQDestination destination, Message origMessage, AbstractJMSMessage message, UUID messageId, int deliveryMode,int priority, long timeToLive, boolean mandatory, - boolean immediate) throws JMSException + boolean immediate, boolean wait) throws JMSException { BasicPublishBody body = getSession().getMethodRegistry().createBasicPublishBody(_session.getTicket(), destination.getExchangeName(), @@ -167,7 +169,7 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer throw jmse; } - _protocolHandler.writeFrame(compositeFrame); + _protocolHandler.writeFrame(compositeFrame, wait); } /** @@ -184,9 +186,7 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer if (frames.length == (offset + 1)) { - byte[] data = new byte[payload.remaining()]; - payload.get(data); - frames[offset] = ContentBody.createAMQFrame(channelId, new ContentBody(data)); + frames[offset] = ContentBody.createAMQFrame(channelId, new ContentBody(payload)); } else { @@ -198,10 +198,7 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer payload.position((int) framePayloadMax * (i - offset)); int length = (remaining >= framePayloadMax) ? (int) framePayloadMax : (int) remaining; payload.limit(payload.position() + length); - byte[] data = new byte[payload.remaining()]; - payload.get(data); - - frames[i] = ContentBody.createAMQFrame(channelId, new ContentBody(data)); + frames[i] = ContentBody.createAMQFrame(channelId, new ContentBody(payload.slice())); remaining -= length; } diff --git a/java/client/src/main/java/org/apache/qpid/client/ChannelToSessionMap.java b/java/client/src/main/java/org/apache/qpid/client/ChannelToSessionMap.java index 2fdb35de49..2b7e3d44da 100644 --- a/java/client/src/main/java/org/apache/qpid/client/ChannelToSessionMap.java +++ b/java/client/src/main/java/org/apache/qpid/client/ChannelToSessionMap.java @@ -1,23 +1,3 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ package org.apache.qpid.client; import java.util.ArrayList; diff --git a/java/client/src/main/java/org/apache/qpid/client/CustomJMSXProperty.java b/java/client/src/main/java/org/apache/qpid/client/CustomJMSXProperty.java index e81e754da2..7cc548915c 100644 --- a/java/client/src/main/java/org/apache/qpid/client/CustomJMSXProperty.java +++ b/java/client/src/main/java/org/apache/qpid/client/CustomJMSXProperty.java @@ -23,7 +23,6 @@ package org.apache.qpid.client; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; -import java.util.List; import org.apache.qpid.framing.AMQShortString; @@ -35,18 +34,6 @@ public enum CustomJMSXProperty JMSXGroupSeq, JMSXUserID; - private static List<String> _names; - - static - { - CustomJMSXProperty[] properties = values(); - _names = new ArrayList<String>(properties.length); - for(CustomJMSXProperty property : properties) - { - _names.add(property.toString()); - } - - } private final AMQShortString _nameAsShortString; @@ -60,8 +47,20 @@ public enum CustomJMSXProperty return _nameAsShortString; } - public static Enumeration asEnumeration() + private static Enumeration _names; + + public static synchronized Enumeration asEnumeration() { - return Collections.enumeration(_names); + if(_names == null) + { + CustomJMSXProperty[] properties = values(); + ArrayList<String> nameList = new ArrayList<String>(properties.length); + for(CustomJMSXProperty property : properties) + { + nameList.add(property.toString()); + } + _names = Collections.enumeration(nameList); + } + return _names; } } diff --git a/java/client/src/main/java/org/apache/qpid/client/QpidConnectionMetaData.java b/java/client/src/main/java/org/apache/qpid/client/QpidConnectionMetaData.java index 5cf767ac35..3bb5707417 100644 --- a/java/client/src/main/java/org/apache/qpid/client/QpidConnectionMetaData.java +++ b/java/client/src/main/java/org/apache/qpid/client/QpidConnectionMetaData.java @@ -30,11 +30,9 @@ import org.apache.qpid.common.QpidProperties; public class QpidConnectionMetaData implements ConnectionMetaData { - private AMQConnection con; QpidConnectionMetaData(AMQConnection conn) { - this.con = conn; } public int getJMSMajorVersion() throws JMSException @@ -64,12 +62,12 @@ public class QpidConnectionMetaData implements ConnectionMetaData public int getProviderMajorVersion() throws JMSException { - return con.getProtocolVersion().getMajorVersion(); + return 0; } public int getProviderMinorVersion() throws JMSException { - return con.getProtocolVersion().getMinorVersion(); + return 8; } public String getProviderVersion() throws JMSException @@ -80,7 +78,8 @@ public class QpidConnectionMetaData implements ConnectionMetaData private String getProtocolVersion() { - return con.getProtocolVersion().toString(); + // TODO - Implement based on connection negotiated protocol + return "0.8"; } public String getBrokerVersion() diff --git a/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java b/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java index 295c6a4091..27783bcacf 100644 --- a/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java +++ b/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java @@ -50,25 +50,25 @@ public class QueueSenderAdapter implements QueueSender public void send(Message msg) throws JMSException { - checkQueuePreConditions(_queue); + checkPreConditions(); _delegate.send(msg); } public void send(Queue queue, Message msg) throws JMSException { - checkQueuePreConditions(queue); + checkPreConditions(queue); _delegate.send(queue, msg); } public void publish(Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException { - checkQueuePreConditions(_queue); + checkPreConditions(); _delegate.send(msg, deliveryMode, priority, timeToLive); } public void send(Queue queue, Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException { - checkQueuePreConditions(queue); + checkPreConditions(queue); _delegate.send(queue, msg, deliveryMode, priority, timeToLive); } @@ -122,19 +122,19 @@ public class QueueSenderAdapter implements QueueSender public void send(Destination dest, Message msg) throws JMSException { - checkQueuePreConditions((Queue) dest); + checkPreConditions((Queue) dest); _delegate.send(dest, msg); } public void send(Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException { - checkQueuePreConditions(_queue); + checkPreConditions(); _delegate.send(msg, deliveryMode, priority, timeToLive); } public void send(Destination dest, Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException { - checkQueuePreConditions((Queue) dest); + checkPreConditions((Queue) dest); _delegate.send(dest, msg, deliveryMode, priority, timeToLive); } @@ -170,6 +170,11 @@ public class QueueSenderAdapter implements QueueSender private void checkPreConditions() throws JMSException { + checkPreConditions(_queue); + } + + private void checkPreConditions(Queue queue) throws JMSException + { if (closed) { throw new javax.jms.IllegalStateException("Publisher is closed"); @@ -181,43 +186,39 @@ public class QueueSenderAdapter implements QueueSender { throw new javax.jms.IllegalStateException("Invalid Session"); } - } - private void checkQueuePreConditions(Queue queue) throws JMSException - { - checkPreConditions() ; - - if (queue == null) - { - throw new UnsupportedOperationException("Queue is null."); - } - - if (!(queue instanceof AMQDestination)) - { - throw new InvalidDestinationException("Queue: " + queue + " is not a valid Qpid queue"); - } - - AMQDestination destination = (AMQDestination) queue; - if (!destination.isCheckedForQueueBinding() && checkQueueBeforePublish()) - { - if (_delegate.getSession().isStrictAMQP()) - { - _delegate._logger.warn("AMQP does not support destination validation before publish, "); - destination.setCheckedForQueueBinding(true); - } - else - { - if (_delegate.isBound(destination)) - { - destination.setCheckedForQueueBinding(true); - } - else - { - throw new InvalidDestinationException("Queue: " + queue - + " is not a valid destination (no bindings on server"); - } - } - } + if (queue == null) + { + throw new UnsupportedOperationException("Queue is null."); + } + + if (!(queue instanceof AMQDestination)) + { + throw new InvalidDestinationException("Queue: " + queue + " is not a valid Qpid queue"); + } + + AMQDestination destination = (AMQDestination) queue; + if (!destination.isCheckedForQueueBinding() && checkQueueBeforePublish()) + { + + if (_delegate.getSession().isStrictAMQP()) + { + _delegate._logger.warn("AMQP does not support destination validation before publish, "); + destination.setCheckedForQueueBinding(true); + } + else + { + if (_delegate.isBound(destination)) + { + destination.setCheckedForQueueBinding(true); + } + else + { + throw new InvalidDestinationException("Queue: " + queue + + " is not a valid destination (no bindings on server"); + } + } + } } private boolean checkQueueBeforePublish() diff --git a/java/client/src/main/java/org/apache/qpid/client/SSLConfiguration.java b/java/client/src/main/java/org/apache/qpid/client/SSLConfiguration.java new file mode 100644 index 0000000000..2280cc9870 --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/SSLConfiguration.java @@ -0,0 +1,61 @@ +/* + * + * 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; + +public class SSLConfiguration { + + private String _keystorePath; + + private String _keystorePassword; + + private String _certType = "SunX509"; + + public void setKeystorePath(String path) + { + _keystorePath = path; + } + + public String getKeystorePath() + { + return _keystorePath; + } + + public void setKeystorePassword(String password) + { + _keystorePassword = password; + } + + public String getKeystorePassword() + { + return _keystorePassword; + } + + public void setCertType(String type) + { + _certType = type; + } + + public String getCertType() + { + return _certType; + } +} diff --git a/java/client/src/main/java/org/apache/qpid/client/TemporaryDestination.java b/java/client/src/main/java/org/apache/qpid/client/TemporaryDestination.java index ca137f5a51..7f8e80c73a 100644 --- a/java/client/src/main/java/org/apache/qpid/client/TemporaryDestination.java +++ b/java/client/src/main/java/org/apache/qpid/client/TemporaryDestination.java @@ -24,16 +24,13 @@ package org.apache.qpid.client; import javax.jms.Destination; import javax.jms.JMSException; -import org.apache.qpid.framing.AMQShortString; - /** - * Provides support for convenience interface implemented by both AMQTemporaryTopic and AMQTemporaryQueue + * Provides support for covenience interface implemented by both AMQTemporaryTopic and AMQTemporaryQueue * so that operations related to their "temporary-ness" can be abstracted out. */ interface TemporaryDestination extends Destination { - public AMQShortString getAMQQueueName(); public void delete() throws JMSException; public AMQSession getSession(); public boolean isDeleted(); 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 97048f39f4..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 @@ -31,9 +31,9 @@ public class XAConnectionImpl extends AMQConnection implements XAConnection, XAQ /** * Create a XAConnection from a connectionURL */ - public XAConnectionImpl(ConnectionURL connectionURL) throws AMQException + public XAConnectionImpl(ConnectionURL connectionURL, SSLConfiguration sslConfig) throws AMQException { - super(connectionURL); + super(connectionURL, sslConfig); } //-- interface XAConnection 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 5b94b342eb..8a75082202 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 @@ -21,14 +21,10 @@ import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; +import org.apache.qpid.AMQInvalidArgumentException; import org.apache.qpid.dtx.XidImpl; -import org.apache.qpid.transport.DtxXaStatus; -import org.apache.qpid.transport.ExecutionErrorCode; -import org.apache.qpid.transport.Future; -import org.apache.qpid.transport.Option; -import org.apache.qpid.transport.RecoverResult; -import org.apache.qpid.transport.SessionException; -import org.apache.qpid.transport.XaResult; +import org.apache.qpid.transport.*; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -215,28 +211,9 @@ public class XAResourceImpl implements XAResource * @throws XAException An error has occurred. Possible exception values are XAER_RMERR, XAER_RMFAIL. */ public boolean isSameRM(XAResource xaResource) throws XAException - { - if(this == xaResource) - { - return true; - } - if(!(xaResource instanceof XAResourceImpl)) - { - return false; - } - - XAResourceImpl other = (XAResourceImpl)xaResource; - - String myUUID = ((AMQSession_0_10)_xaSession).getAMQConnection().getBrokerUUID(); - String otherUUID = ((AMQSession_0_10)other._xaSession).getAMQConnection().getBrokerUUID(); - - if(_logger.isDebugEnabled()) - { - _logger.debug("Comparing my UUID " + myUUID + " with other UUID " + otherUUID); - } - - return (myUUID != null && otherUUID != null && myUUID.equals(otherUUID)); - + { + // TODO : get the server identity of xaResource and compare it with our own one + return false; } /** 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 6b9121811d..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 @@ -52,7 +52,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic { super(qpidConnection, con, channelId, false, // this is not a transacted session Session.AUTO_ACKNOWLEDGE, // the ack mode is transacted - MessageFactoryRegistry.newDefaultRegistry(), defaultPrefetchHigh, defaultPrefetchLow,null); + MessageFactoryRegistry.newDefaultRegistry(), defaultPrefetchHigh, defaultPrefetchLow); createSession(); _xaResource = new XAResourceImpl(this); } 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 28d19ce817..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 @@ -59,8 +59,8 @@ import org.slf4j.LoggerFactory; * <tr><td> Automatically retry the continuation accross fail-overs until it succeeds, or raises an exception. * </table> * - * @todo Another continuation. Could use an interface Continuation (as described in other todos) - * Then have a wrapping continuation (this), which blocks on an arbitrary + * @todo Another continuation. Could use an interface Continuation (as described in other todos, for example, see + * {@link org.apache.qpid.pool.Job}). Then have a wrapping continuation (this), which blocks on an arbitrary * Condition or Latch (specified in constructor call), that this blocks on before calling the wrapped Continuation. * Must work on Java 1.4, so check retrotranslator works on Lock/Condition or latch first. Argument and return type * to match wrapped condition as type parameters. Rename to AsyncConditionalContinuation or something like that. 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 b9d4d6fa95..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 @@ -78,7 +78,7 @@ public class ChannelCloseMethodHandler implements StateAwareMethodListener<Chann { throw new AMQNoRouteException("Error: " + reason, null, null); } - else if (errorCode == AMQConstant.ARGUMENT_INVALID) + else if (errorCode == AMQConstant.INVALID_ARGUMENT) { _logger.debug("Broker responded with Invalid Argument."); 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 939bd181a3..c81ad6422f 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 @@ -20,13 +20,6 @@ */ package org.apache.qpid.client.handler; -import java.io.UnsupportedEncodingException; -import java.util.StringTokenizer; - -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; - import org.apache.qpid.AMQException; import org.apache.qpid.client.protocol.AMQProtocolSession; import org.apache.qpid.client.security.AMQCallbackHandler; @@ -41,9 +34,18 @@ import org.apache.qpid.framing.ConnectionStartOkBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.FieldTableFactory; import org.apache.qpid.framing.ProtocolVersion; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +import java.io.UnsupportedEncodingException; +import java.util.HashSet; +import java.util.StringTokenizer; + public class ConnectionStartMethodHandler implements StateAwareMethodListener<ConnectionStartBody> { private static final Logger _log = LoggerFactory.getLogger(ConnectionStartMethodHandler.class); @@ -195,20 +197,40 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener<Co private String chooseMechanism(byte[] availableMechanisms) throws UnsupportedEncodingException { final String mechanisms = new String(availableMechanisms, "utf8"); - return CallbackHandlerRegistry.getInstance().selectMechanism(mechanisms); + StringTokenizer tokenizer = new StringTokenizer(mechanisms, " "); + HashSet mechanismSet = new HashSet(); + while (tokenizer.hasMoreTokens()) + { + mechanismSet.add(tokenizer.nextToken()); + } + + String preferredMechanisms = CallbackHandlerRegistry.getInstance().getMechanisms(); + StringTokenizer prefTokenizer = new StringTokenizer(preferredMechanisms, " "); + while (prefTokenizer.hasMoreTokens()) + { + String mech = prefTokenizer.nextToken(); + if (mechanismSet.contains(mech)) + { + return mech; + } + } + + return null; } private AMQCallbackHandler createCallbackHandler(String mechanism, AMQProtocolSession protocolSession) throws AMQException { + Class mechanismClass = CallbackHandlerRegistry.getInstance().getCallbackHandlerClass(mechanism); try { - AMQCallbackHandler instance = CallbackHandlerRegistry.getInstance().createCallbackHandler(mechanism); - instance.initialise(protocolSession.getAMQConnection().getConnectionURL()); + Object instance = mechanismClass.newInstance(); + AMQCallbackHandler cbh = (AMQCallbackHandler) instance; + cbh.initialise(protocolSession); - return instance; + return cbh; } - catch (IllegalArgumentException e) + catch (Exception e) { throw new AMQException(null, "Unable to create callback handler: " + e, e); } 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 a9434edf49..c2821591d8 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 @@ -26,7 +26,9 @@ import org.apache.qpid.client.AMQSession; import javax.jms.Destination; import javax.jms.JMSException; +import java.nio.ByteBuffer; import java.util.Enumeration; +import java.util.Map; import java.util.UUID; public interface AMQMessageDelegate @@ -128,9 +130,9 @@ public interface AMQMessageDelegate void removeProperty(final String propertyName) throws JMSException; - void setAMQSession(final AMQSession<?,?> s); + void setAMQSession(final AMQSession s); - AMQSession<?,?> getAMQSession(); + AMQSession getAMQSession(); long getDeliveryTag(); diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegateFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegateFactory.java index e5b95f54f4..8c3f2fd08f 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegateFactory.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegateFactory.java @@ -21,6 +21,11 @@ package org.apache.qpid.client.message; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.AMQException; + public interface AMQMessageDelegateFactory<D extends AMQMessageDelegate> { public static AMQMessageDelegateFactory DEFAULT_FACTORY = null; 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 f360b546b2..92e61984d2 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 @@ -22,12 +22,10 @@ package org.apache.qpid.client.message; import java.lang.ref.SoftReference; -import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -37,10 +35,12 @@ import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageFormatException; import javax.jms.MessageNotWriteableException; +import javax.jms.Session; import org.apache.qpid.AMQException; import org.apache.qpid.AMQPInvalidClassException; import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQSession_0_10; import org.apache.qpid.client.CustomJMSXProperty; import org.apache.qpid.framing.AMQShortString; @@ -53,9 +53,6 @@ import org.apache.qpid.transport.MessageDeliveryMode; import org.apache.qpid.transport.MessageDeliveryPriority; import org.apache.qpid.transport.MessageProperties; import org.apache.qpid.transport.ReplyTo; -import org.apache.qpid.transport.TransportException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * This extends AbstractAMQMessageDelegate which contains common code between @@ -64,7 +61,6 @@ import org.slf4j.LoggerFactory; */ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate { - private static final Logger _logger = LoggerFactory.getLogger(AMQMessageDelegate_0_10.class); private static final Map<ReplyTo, SoftReference<Destination>> _destinationCache = Collections.synchronizedMap(new HashMap<ReplyTo, SoftReference<Destination>>()); public static final String JMS_TYPE = "x-jms-type"; @@ -74,8 +70,13 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate private Destination _destination; + private MessageProperties _messageProps; private DeliveryProperties _deliveryProps; + /** If the acknowledge mode is CLIENT_ACKNOWLEDGE the session is required */ + private AMQSession _session; + private final long _deliveryTag; + protected AMQMessageDelegate_0_10() { @@ -85,29 +86,15 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate protected AMQMessageDelegate_0_10(MessageProperties messageProps, DeliveryProperties deliveryProps, long deliveryTag) { - super(deliveryTag); _messageProps = messageProps; _deliveryProps = deliveryProps; + _deliveryTag = deliveryTag; _readableProperties = (_messageProps != null); AMQDestination dest; - if (AMQDestination.getDefaultDestSyntax() == AMQDestination.DestSyntax.BURL) - { - dest = generateDestination(new AMQShortString(_deliveryProps.getExchange()), + dest = generateDestination(new AMQShortString(_deliveryProps.getExchange()), new AMQShortString(_deliveryProps.getRoutingKey())); - } - else - { - String subject = null; - if (messageProps != null && messageProps.getApplicationHeaders() != null) - { - subject = (String)messageProps.getApplicationHeaders().get(QpidMessageProperties.QPID_SUBJECT); - } - dest = (AMQDestination) convertToAddressBasedDestination(_deliveryProps.getExchange(), - _deliveryProps.getRoutingKey(), subject); - } - setJMSDestination(dest); } @@ -198,6 +185,7 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate } } + public long getJMSTimestamp() throws JMSException { return _deliveryProps.getTimestamp(); @@ -252,50 +240,13 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate String exchange = replyTo.getExchange(); String routingKey = replyTo.getRoutingKey(); - if (AMQDestination.getDefaultDestSyntax() == AMQDestination.DestSyntax.BURL) - { - - dest = generateDestination(new AMQShortString(exchange), new AMQShortString(routingKey)); - } - else - { - dest = convertToAddressBasedDestination(exchange,routingKey,null); - } + dest = generateDestination(new AMQShortString(exchange), new AMQShortString(routingKey)); _destinationCache.put(replyTo, new SoftReference<Destination>(dest)); } return dest; } } - - private Destination convertToAddressBasedDestination(String exchange, String routingKey, String subject) - { - String addr; - if ("".equals(exchange)) // type Queue - { - subject = (subject == null) ? "" : "/" + subject; - addr = routingKey + subject; - } - else - { - addr = exchange + "/" + routingKey; - } - - try - { - return AMQDestination.createDestination("ADDR:" + addr); - } - catch(Exception e) - { - // An exception is only thrown here if the address syntax is invalid. - // Logging the exception, but not throwing as this is only important to Qpid developers. - // An exception here means a bug in the code. - _logger.error("Exception when constructing an address string from the ReplyTo struct"); - - // falling back to the old way of doing it to ensure the application continues. - return generateDestination(new AMQShortString(exchange), new AMQShortString(routingKey)); - } - } public void setJMSReplyTo(Destination destination) throws JMSException { @@ -317,14 +268,14 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate { try { - int type = ((AMQSession_0_10)getAMQSession()).resolveAddressType(amqd); + int type = ((AMQSession_0_10)_session).resolveAddressType(amqd); if (type == AMQDestination.QUEUE_TYPE) { - ((AMQSession_0_10)getAMQSession()).setLegacyFiledsForQueueType(amqd); + ((AMQSession_0_10)_session).setLegacyFiledsForQueueType(amqd); } else { - ((AMQSession_0_10)getAMQSession()).setLegacyFiledsForTopicType(amqd); + ((AMQSession_0_10)_session).setLegacyFiledsForTopicType(amqd); } } catch(AMQException ex) @@ -334,14 +285,6 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate e.setLinkedException(ex); throw e; } - catch (TransportException e) - { - JMSException jmse = new JMSException("Exception occured while figuring out the node type:" + e.getMessage()); - jmse.initCause(e); - jmse.setLinkedException(e); - throw jmse; - } - } final ReplyTo replyTo = new ReplyTo(amqd.getExchangeName().toString(), amqd.getRoutingKey().toString()); @@ -392,7 +335,7 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate Destination replyTo = getJMSReplyTo(); if(replyTo != null) { - return ((AMQDestination)replyTo).toString(); + return ((AMQDestination)replyTo).toURL(); } else { @@ -689,16 +632,6 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate { return new String(_messageProps.getUserId()); } - else if (QpidMessageProperties.AMQP_0_10_APP_ID.equals(propertyName) && - _messageProps.getAppId() != null) - { - return new String(_messageProps.getAppId()); - } - else if (QpidMessageProperties.AMQP_0_10_ROUTING_KEY.equals(propertyName) && - _deliveryProps.getRoutingKey() != null) - { - return _deliveryProps.getRoutingKey(); - } else { checkPropertyName(propertyName); @@ -737,19 +670,7 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate public Enumeration getPropertyNames() throws JMSException { - List<String> props = new ArrayList<String>(); - Map<String, Object> propertyMap = getApplicationHeaders(); - for (String prop: getApplicationHeaders().keySet()) - { - Object value = propertyMap.get(prop); - if (value instanceof Boolean || value instanceof Number - || value instanceof String) - { - props.add(prop); - } - } - - return java.util.Collections.enumeration(props); + return java.util.Collections.enumeration(getApplicationHeaders().keySet()); } public void setBooleanProperty(String propertyName, boolean b) throws JMSException @@ -805,14 +726,7 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate { checkPropertyName(propertyName); checkWritableProperties(); - if (QpidMessageProperties.AMQP_0_10_APP_ID.equals(propertyName)) - { - _messageProps.setAppId(value.getBytes()); - } - else - { - setApplicationHeader(propertyName, value); - } + setApplicationHeader(propertyName, value); } private static final Set<Class> ALLOWED = new HashSet(); @@ -897,6 +811,64 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate _readableProperties = false; } + + public void acknowledgeThis() throws JMSException + { + // the JMS 1.1 spec says in section 3.6 that calls to acknowledge are ignored when client acknowledge + // is not specified. In our case, we only set the session field where client acknowledge mode is specified. + if (_session != null && _session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) + { + if (_session.getAMQConnection().isClosed()) + { + throw new javax.jms.IllegalStateException("Connection is already closed"); + } + + // we set multiple to true here since acknowledgment implies acknowledge of all previous messages + // received on the session + _session.acknowledgeMessage(_deliveryTag, true); + } + } + + public void acknowledge() throws JMSException + { + if (_session != null && _session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) + { + _session.acknowledge(); + } + } + + + /** + * The session is set when CLIENT_ACKNOWLEDGE mode is used so that the CHANNEL ACK can be sent when the user calls + * acknowledge() + * + * @param s the AMQ session that delivered this message + */ + public void setAMQSession(AMQSession s) + { + _session = s; + } + + public AMQSession getAMQSession() + { + return _session; + } + + /** + * Get the AMQ message number assigned to this message + * + * @return the message number + */ + public long getDeliveryTag() + { + return _deliveryTag; + } + + + + + + protected void checkPropertyName(CharSequence propertyName) { if (propertyName == null) 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 9ab03412fe..cec4268a7b 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 @@ -30,6 +30,7 @@ import java.util.UUID; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageNotWriteableException; +import javax.jms.Session; import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQQueue; @@ -59,12 +60,15 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, AMQSession.STRICT_AMQP_DEFAULT)); private ContentHeaderProperties _contentHeaderProperties; + /** If the acknowledge mode is CLIENT_ACKNOWLEDGE the session is required */ + 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) { - super(deliveryTag); _contentHeaderProperties = properties; + _deliveryTag = deliveryTag; _readableProperties = (_contentHeaderProperties != null); _headerAdapter = new JMSHeaderAdapter(_readableProperties ? ((BasicContentHeaderProperties) _contentHeaderProperties).getHeaders() : (new BasicContentHeaderProperties()).getHeaders() ); @@ -495,6 +499,7 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate { throw new MessageNotWriteableException("You need to call clearProperties() to make the message writable"); } + _contentHeaderProperties.updated(); } @@ -514,4 +519,58 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate _readableProperties = false; } + + + public void acknowledgeThis() throws JMSException + { + // the JMS 1.1 spec says in section 3.6 that calls to acknowledge are ignored when client acknowledge + // is not specified. In our case, we only set the session field where client acknowledge mode is specified. + if (_session != null && _session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) + { + if (_session.getAMQConnection().isClosed()) + { + throw new javax.jms.IllegalStateException("Connection is already closed"); + } + + // we set multiple to true here since acknowledgement implies acknowledge of all previous messages + // received on the session + _session.acknowledgeMessage(_deliveryTag, true); + } + } + + public void acknowledge() throws JMSException + { + if (_session != null && _session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) + { + _session.acknowledge(); + } + } + + + /** + * The session is set when CLIENT_ACKNOWLEDGE mode is used so that the CHANNEL ACK can be sent when the user calls + * acknowledge() + * + * @param s the AMQ session that delivered this message + */ + public void setAMQSession(AMQSession s) + { + _session = s; + } + + public AMQSession getAMQSession() + { + return _session; + } + + /** + * Get the AMQ message number assigned to this message + * + * @return the message number + */ + public long getDeliveryTag() + { + return _deliveryTag; + } + } diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java index be71c8c657..6e22292ee0 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java @@ -23,12 +23,11 @@ package org.apache.qpid.client.message; import java.util.List; import java.util.Map; -import java.util.UUID; -import java.nio.ByteBuffer; import javax.jms.JMSException; import javax.jms.MessageFormatException; +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.transport.codec.BBDecoder; import org.apache.qpid.transport.codec.BBEncoder; @@ -66,7 +65,7 @@ public class AMQPEncodedMapMessage extends JMSMapMessage if ((value instanceof Boolean) || (value instanceof Byte) || (value instanceof Short) || (value instanceof Integer) || (value instanceof Long) || (value instanceof Character) || (value instanceof Float) || (value instanceof Double) || (value instanceof String) || (value instanceof byte[]) - || (value instanceof List) || (value instanceof Map) || (value instanceof UUID) || (value == null)) + || (value instanceof List) || (value instanceof Map) || (value == null)) { _map.put(propName, value); } @@ -81,19 +80,18 @@ public class AMQPEncodedMapMessage extends JMSMapMessage @ Override public ByteBuffer getData() { - BBEncoder encoder = new BBEncoder(1024); - encoder.writeMap(_map); - return encoder.segment(); + writeMapToData(); + return _data; } @ Override - protected void populateMapFromData(ByteBuffer data) throws JMSException + protected void populateMapFromData() throws JMSException { - if (data != null) + if (_data != null) { - data.rewind(); + _data.rewind(); BBDecoder decoder = new BBDecoder(); - decoder.init(data); + decoder.init(_data.buf()); _map = decoder.readMap(); } else @@ -102,8 +100,16 @@ public class AMQPEncodedMapMessage extends JMSMapMessage } } + @ Override + protected void writeMapToData() + { + BBEncoder encoder = new BBEncoder(1024); + encoder.writeMap(_map); + _data = ByteBuffer.wrap(encoder.segment()); + } + // for testing - public Map<String,Object> getMap() + Map<String,Object> getMap() { return _map; } diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageFactory.java index 2c38f153cb..4978d1ce85 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageFactory.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageFactory.java @@ -1,6 +1,6 @@ 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 @@ -8,23 +8,22 @@ package org.apache.qpid.client.message; * 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 javax.jms.JMSException; -import java.nio.ByteBuffer; - +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; public class AMQPEncodedMapMessageFactory extends AbstractJMSMessageFactory @@ -37,7 +36,7 @@ public class AMQPEncodedMapMessageFactory extends AbstractJMSMessageFactory return new AMQPEncodedMapMessage(delegate,data); } - + @Override public AbstractJMSMessage createMessage( AMQMessageDelegateFactory delegateFactory) throws JMSException { 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 index 1b6c0c751d..89fbc9722c 100644 --- 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 @@ -23,13 +23,9 @@ package org.apache.qpid.client.message; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.jms.JMSException; -import javax.jms.Session; - import org.apache.qpid.client.AMQAnyDestination; import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -82,25 +78,7 @@ public abstract class AbstractAMQMessageDelegate implements AMQMessageDelegate new ExchangeInfo(ExchangeDefaults.HEADERS_EXCHANGE_NAME.toString(), ExchangeDefaults.HEADERS_EXCHANGE_CLASS.toString(), AMQDestination.QUEUE_TYPE)); - } - - /** If the acknowledge mode is CLIENT_ACKNOWLEDGE the session is required */ - private AMQSession<?,?> _session; - private final long _deliveryTag; - - protected AbstractAMQMessageDelegate(long deliveryTag) - { - _deliveryTag = deliveryTag; - } - - /** - * Get the AMQ message number assigned to this message - * - * @return the message number - */ - public long getDeliveryTag() - { - return _deliveryTag; + } /** @@ -179,47 +157,6 @@ public abstract class AbstractAMQMessageDelegate implements AMQMessageDelegate { return _exchangeMap.containsKey(exchange); } - - public void acknowledgeThis() throws JMSException - { - // the JMS 1.1 spec says in section 3.6 that calls to acknowledge are ignored when client acknowledge - // is not specified. In our case, we only set the session field where client acknowledge mode is specified. - if (_session != null && _session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) - { - if (_session.getAMQConnection().isClosed()) - { - throw new javax.jms.IllegalStateException("Connection is already closed"); - } - - // we set multiple to true here since acknowledgement implies acknowledge of all previous messages - // received on the session - _session.acknowledgeMessage(getDeliveryTag(), true); - } - } - - public void acknowledge() throws JMSException - { - if (_session != null && _session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) - { - _session.acknowledge(); - } - } - - /** - * The session is set when CLIENT_ACKNOWLEDGE mode is used so that the CHANNEL ACK can be sent when the user calls - * acknowledge() - * - * @param s the AMQ session that delivered this message - */ - public void setAMQSession(AMQSession<?,?> s) - { - _session = s; - } - - public AMQSession<?,?> getAMQSession() - { - return _session; - } } class ExchangeInfo @@ -265,5 +202,5 @@ class ExchangeInfo public void setDestType(int destType) { this.destType = destType; - } + } } 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 new file mode 100644 index 0000000000..3846ee043d --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java @@ -0,0 +1,124 @@ +/* + * + * 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 java.io.IOException; +import java.nio.charset.Charset; + +import javax.jms.JMSException; +import javax.jms.MessageEOFException; + +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 + */ +public abstract class AbstractBytesMessage extends AbstractJMSMessage +{ + + /** + * The default initial size of the buffer. The buffer expands automatically. + */ + private static final int DEFAULT_BUFFER_INITIAL_SIZE = 1024; + + AbstractBytesMessage(AMQMessageDelegateFactory delegateFactory) + { + this(delegateFactory, null); + } + + /** + * Construct a bytes message with existing data. + * + * @param delegateFactory + * @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is + */ + AbstractBytesMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data) + { + super(delegateFactory, data); // this instanties a content header + setContentType(getMimeType()); + + if (_data == null) + { + allocateInitialBuffer(); + } + } + + protected void allocateInitialBuffer() + { + _data = ByteBuffer.allocate(DEFAULT_BUFFER_INITIAL_SIZE); + _data.setAutoExpand(true); + } + + AbstractBytesMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException + { + super(delegate, data); + setContentType(getMimeType()); + } + + + public void clearBodyImpl() throws JMSException + { + allocateInitialBuffer(); + } + + public String toBodyString() throws JMSException + { + try + { + if (_data != null) + { + return Functions.str(_data.buf(), 100,0); + } + else + { + return ""; + } + + } + catch (Exception e) + { + JMSException jmse = new JMSException(e.toString()); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; + } + + } + + /** + * Check that there is at least a certain number of bytes available to read + * + * @param len the number of bytes + * @throws javax.jms.MessageEOFException if there are less than len bytes available to read + */ + protected void checkAvailable(int len) throws MessageEOFException + { + if (_data.remaining() < len) + { + throw new MessageEOFException("Unable to read " + len + " bytes"); + } + } +} diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesTypedMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesTypedMessage.java index ddeb62fbf6..85818dcd2b 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesTypedMessage.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesTypedMessage.java @@ -21,96 +21,784 @@ package org.apache.qpid.client.message; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; -import java.nio.ByteBuffer; import javax.jms.JMSException; +import javax.jms.MessageEOFException; +import javax.jms.MessageFormatException; import javax.jms.MessageNotReadableException; import javax.jms.MessageNotWriteableException; +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; -import org.apache.qpid.transport.util.Functions; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; /** * @author Apache Software Foundation */ -public abstract class AbstractBytesTypedMessage extends AbstractJMSMessage +public abstract class AbstractBytesTypedMessage extends AbstractBytesMessage { - protected boolean _readableMessage = false; - AbstractBytesTypedMessage(AMQMessageDelegateFactory delegateFactory, boolean fromReceivedMessage) + protected static final byte BOOLEAN_TYPE = (byte) 1; + + protected static final byte BYTE_TYPE = (byte) 2; + + protected static final byte BYTEARRAY_TYPE = (byte) 3; + + protected static final byte SHORT_TYPE = (byte) 4; + + protected static final byte CHAR_TYPE = (byte) 5; + + protected static final byte INT_TYPE = (byte) 6; + + protected static final byte LONG_TYPE = (byte) 7; + + protected static final byte FLOAT_TYPE = (byte) 8; + + protected static final byte DOUBLE_TYPE = (byte) 9; + + protected static final byte STRING_TYPE = (byte) 10; + + protected static final byte NULL_STRING_TYPE = (byte) 11; + + /** + * This is set when reading a byte array. The readBytes(byte[]) method supports multiple calls to read + * a byte array in multiple chunks, hence this is used to track how much is left to be read + */ + private int _byteArrayRemaining = -1; + + AbstractBytesTypedMessage(AMQMessageDelegateFactory delegateFactory) + { + + this(delegateFactory, null); + } + + /** + * Construct a stream message with existing data. + * + * @param delegateFactory + * @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is + */ + AbstractBytesTypedMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data) { - super(delegateFactory, fromReceivedMessage); // this instanties a content header - _readableMessage = fromReceivedMessage; + super(delegateFactory, data); // this instanties a content header } - AbstractBytesTypedMessage(AMQMessageDelegate delegate, boolean fromReceivedMessage) throws AMQException + AbstractBytesTypedMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException { - super(delegate, fromReceivedMessage); - _readableMessage = fromReceivedMessage; + super(delegate, data); + } + + protected byte readWireType() throws MessageFormatException, MessageEOFException, + MessageNotReadableException + { + checkReadable(); + checkAvailable(1); + return _data.get(); } - protected void checkReadable() throws MessageNotReadableException + protected void writeTypeDiscriminator(byte type) throws MessageNotWriteableException { - if (!_readableMessage) + checkWritable(); + _data.put(type); + _changedData = true; + } + + protected boolean readBoolean() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + boolean result; + try { - throw new MessageNotReadableException("You need to call reset() to make the message readable"); + switch (wireType) + { + case BOOLEAN_TYPE: + checkAvailable(1); + result = readBooleanImpl(); + break; + case STRING_TYPE: + checkAvailable(1); + result = Boolean.parseBoolean(readStringImpl()); + break; + default: + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to a boolean"); + } + return result; + } + catch (RuntimeException e) + { + _data.position(position); + throw e; } } - @Override - protected void checkWritable() throws MessageNotWriteableException + private boolean readBooleanImpl() { - super.checkWritable(); - if(_readableMessage) + return _data.get() != 0; + } + + protected byte readByte() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + byte result; + try { - throw new MessageNotWriteableException("You need to call clearBody() to make the message writable"); + switch (wireType) + { + case BYTE_TYPE: + checkAvailable(1); + result = readByteImpl(); + break; + case STRING_TYPE: + checkAvailable(1); + result = Byte.parseByte(readStringImpl()); + break; + default: + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to a byte"); + } } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + return result; } - public void clearBody() throws JMSException + private byte readByteImpl() { - super.clearBody(); - _readableMessage = false; + return _data.get(); } + protected short readShort() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + short result; + try + { + switch (wireType) + { + case SHORT_TYPE: + checkAvailable(2); + result = readShortImpl(); + break; + case STRING_TYPE: + checkAvailable(1); + result = Short.parseShort(readStringImpl()); + break; + case BYTE_TYPE: + checkAvailable(1); + result = readByteImpl(); + break; + default: + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to a short"); + } + } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + return result; + } - public String toBodyString() throws JMSException + private short readShortImpl() { + return _data.getShort(); + } + + /** + * Note that this method reads a unicode character as two bytes from the stream + * + * @return the character read from the stream + * @throws javax.jms.JMSException + */ + protected char readChar() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); try { - ByteBuffer data = getData(); - if (data != null) - { - return Functions.str(data, 100, 0); - } - else - { - return ""; + if(wireType == NULL_STRING_TYPE){ + throw new NullPointerException(); } + if (wireType != CHAR_TYPE) + { + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to a char"); + } + else + { + checkAvailable(2); + return readCharImpl(); + } + } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + } + + private char readCharImpl() + { + return _data.getChar(); + } + + protected int readInt() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + int result; + try + { + switch (wireType) + { + case INT_TYPE: + checkAvailable(4); + result = readIntImpl(); + break; + case SHORT_TYPE: + checkAvailable(2); + result = readShortImpl(); + break; + case STRING_TYPE: + checkAvailable(1); + result = Integer.parseInt(readStringImpl()); + break; + case BYTE_TYPE: + checkAvailable(1); + result = readByteImpl(); + break; + default: + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to an int"); + } + return result; + } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + } + + protected int readIntImpl() + { + return _data.getInt(); + } + + protected long readLong() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + long result; + try + { + switch (wireType) + { + case LONG_TYPE: + checkAvailable(8); + result = readLongImpl(); + break; + case INT_TYPE: + checkAvailable(4); + result = readIntImpl(); + break; + case SHORT_TYPE: + checkAvailable(2); + result = readShortImpl(); + break; + case STRING_TYPE: + checkAvailable(1); + result = Long.parseLong(readStringImpl()); + break; + case BYTE_TYPE: + checkAvailable(1); + result = readByteImpl(); + break; + default: + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to a long"); + } + return result; + } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + } + + private long readLongImpl() + { + return _data.getLong(); + } + + protected float readFloat() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + float result; + try + { + switch (wireType) + { + case FLOAT_TYPE: + checkAvailable(4); + result = readFloatImpl(); + break; + case STRING_TYPE: + checkAvailable(1); + result = Float.parseFloat(readStringImpl()); + break; + default: + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to a float"); + } + return result; + } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + } + + private float readFloatImpl() + { + return _data.getFloat(); + } + + protected double readDouble() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + double result; + try + { + switch (wireType) + { + case DOUBLE_TYPE: + checkAvailable(8); + result = readDoubleImpl(); + break; + case FLOAT_TYPE: + checkAvailable(4); + result = readFloatImpl(); + break; + case STRING_TYPE: + checkAvailable(1); + result = Double.parseDouble(readStringImpl()); + break; + default: + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to a double"); + } + return result; + } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + } + + private double readDoubleImpl() + { + return _data.getDouble(); + } + + protected String readString() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + String result; + try + { + switch (wireType) + { + case STRING_TYPE: + checkAvailable(1); + result = readStringImpl(); + break; + case NULL_STRING_TYPE: + result = null; + throw new NullPointerException("data is null"); + case BOOLEAN_TYPE: + checkAvailable(1); + result = String.valueOf(readBooleanImpl()); + break; + case LONG_TYPE: + checkAvailable(8); + result = String.valueOf(readLongImpl()); + break; + case INT_TYPE: + checkAvailable(4); + result = String.valueOf(readIntImpl()); + break; + case SHORT_TYPE: + checkAvailable(2); + result = String.valueOf(readShortImpl()); + break; + case BYTE_TYPE: + checkAvailable(1); + result = String.valueOf(readByteImpl()); + break; + case FLOAT_TYPE: + checkAvailable(4); + result = String.valueOf(readFloatImpl()); + break; + case DOUBLE_TYPE: + checkAvailable(8); + result = String.valueOf(readDoubleImpl()); + break; + case CHAR_TYPE: + checkAvailable(2); + result = String.valueOf(readCharImpl()); + break; + default: + _data.position(position); + throw new MessageFormatException("Unable to convert " + wireType + " to a String"); + } + return result; + } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + } + + protected String readStringImpl() throws JMSException + { + try + { + return _data.getString(Charset.forName("UTF-8").newDecoder()); } - catch (Exception e) + catch (CharacterCodingException e) { - JMSException jmse = new JMSException(e.toString()); + JMSException jmse = new JMSException("Error decoding byte stream as a UTF8 string: " + e); jmse.setLinkedException(e); jmse.initCause(e); throw jmse; } + } + + protected int readBytes(byte[] bytes) throws JMSException + { + if (bytes == null) + { + throw new IllegalArgumentException("byte array must not be null"); + } + checkReadable(); + // first call + if (_byteArrayRemaining == -1) + { + // type discriminator checked separately so you get a MessageFormatException rather than + // an EOF even in the case where both would be applicable + checkAvailable(1); + byte wireType = readWireType(); + if (wireType != BYTEARRAY_TYPE) + { + throw new MessageFormatException("Unable to convert " + wireType + " to a byte array"); + } + checkAvailable(4); + int size = _data.getInt(); + // length of -1 indicates null + if (size == -1) + { + return -1; + } + else + { + if (size > _data.remaining()) + { + throw new MessageEOFException("Byte array has stated length " + size + " but message only contains " + + _data.remaining() + " bytes"); + } + else + { + _byteArrayRemaining = size; + } + } + } + else if (_byteArrayRemaining == 0) + { + _byteArrayRemaining = -1; + return -1; + } + + int returnedSize = readBytesImpl(bytes); + if (returnedSize < bytes.length) + { + _byteArrayRemaining = -1; + } + return returnedSize; + } + + private int readBytesImpl(byte[] bytes) + { + int count = (_byteArrayRemaining >= bytes.length ? bytes.length : _byteArrayRemaining); + _byteArrayRemaining -= count; + + if (count == 0) + { + return 0; + } + else + { + _data.get(bytes, 0, count); + return count; + } + } + + protected Object readObject() throws JMSException + { + int position = _data.position(); + byte wireType = readWireType(); + Object result = null; + try + { + switch (wireType) + { + case BOOLEAN_TYPE: + checkAvailable(1); + result = readBooleanImpl(); + break; + case BYTE_TYPE: + checkAvailable(1); + result = readByteImpl(); + break; + case BYTEARRAY_TYPE: + checkAvailable(4); + int size = _data.getInt(); + if (size == -1) + { + result = null; + } + else + { + _byteArrayRemaining = size; + byte[] bytesResult = new byte[size]; + readBytesImpl(bytesResult); + result = bytesResult; + } + break; + case SHORT_TYPE: + checkAvailable(2); + result = readShortImpl(); + break; + case CHAR_TYPE: + checkAvailable(2); + result = readCharImpl(); + break; + case INT_TYPE: + checkAvailable(4); + result = readIntImpl(); + break; + case LONG_TYPE: + checkAvailable(8); + result = readLongImpl(); + break; + case FLOAT_TYPE: + checkAvailable(4); + result = readFloatImpl(); + break; + case DOUBLE_TYPE: + checkAvailable(8); + result = readDoubleImpl(); + break; + case NULL_STRING_TYPE: + result = null; + break; + case STRING_TYPE: + checkAvailable(1); + result = readStringImpl(); + break; + } + return result; + } + catch (RuntimeException e) + { + _data.position(position); + throw e; + } + } + + protected void writeBoolean(boolean b) throws JMSException + { + writeTypeDiscriminator(BOOLEAN_TYPE); + _data.put(b ? (byte) 1 : (byte) 0); + } + + protected void writeByte(byte b) throws JMSException + { + writeTypeDiscriminator(BYTE_TYPE); + _data.put(b); + } + + protected void writeShort(short i) throws JMSException + { + writeTypeDiscriminator(SHORT_TYPE); + _data.putShort(i); + } + + protected void writeChar(char c) throws JMSException + { + writeTypeDiscriminator(CHAR_TYPE); + _data.putChar(c); + } + + protected void writeInt(int i) throws JMSException + { + writeTypeDiscriminator(INT_TYPE); + writeIntImpl(i); + } + + protected void writeIntImpl(int i) + { + _data.putInt(i); + } + + protected void writeLong(long l) throws JMSException + { + writeTypeDiscriminator(LONG_TYPE); + _data.putLong(l); + } + protected void writeFloat(float v) throws JMSException + { + writeTypeDiscriminator(FLOAT_TYPE); + _data.putFloat(v); } + protected void writeDouble(double v) throws JMSException + { + writeTypeDiscriminator(DOUBLE_TYPE); + _data.putDouble(v); + } - abstract public void reset(); + protected void writeString(String string) throws JMSException + { + if (string == null) + { + writeTypeDiscriminator(NULL_STRING_TYPE); + } + else + { + writeTypeDiscriminator(STRING_TYPE); + try + { + writeStringImpl(string); + } + catch (CharacterCodingException e) + { + JMSException jmse = new JMSException("Unable to encode string: " + e); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; + } + } + } + + protected void writeStringImpl(String string) + throws CharacterCodingException + { + _data.putString(string, Charset.forName("UTF-8").newEncoder()); + // we must write the null terminator ourselves + _data.put((byte) 0); + } + protected void writeBytes(byte[] bytes) throws JMSException + { + writeBytes(bytes, 0, bytes == null ? 0 : bytes.length); + } + protected void writeBytes(byte[] bytes, int offset, int length) throws JMSException + { + writeTypeDiscriminator(BYTEARRAY_TYPE); + if (bytes == null) + { + _data.putInt(-1); + } + else + { + _data.putInt(length); + _data.put(bytes, offset, length); + } + } + protected void writeObject(Object object) throws JMSException + { + checkWritable(); + Class clazz; + if (object == null) + { + // string handles the output of null values + clazz = String.class; + } + else + { + clazz = object.getClass(); + } + + if (clazz == Byte.class) + { + writeByte((Byte) object); + } + else if (clazz == Boolean.class) + { + writeBoolean((Boolean) object); + } + else if (clazz == byte[].class) + { + writeBytes((byte[]) object); + } + else if (clazz == Short.class) + { + writeShort((Short) object); + } + else if (clazz == Character.class) + { + writeChar((Character) object); + } + else if (clazz == Integer.class) + { + writeInt((Integer) object); + } + else if (clazz == Long.class) + { + writeLong((Long) object); + } + else if (clazz == Float.class) + { + writeFloat((Float) object); + } + else if (clazz == Double.class) + { + writeDouble((Double) object); + } + else if (clazz == String.class) + { + writeString((String) object); + } + else + { + throw new MessageFormatException("Only primitives plus byte arrays and String are valid types"); + } + } } 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 f713554bfb..6ba55b207a 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 @@ -20,38 +20,66 @@ */ package org.apache.qpid.client.message; -import java.nio.ByteBuffer; +import java.io.IOException; import java.util.Enumeration; import java.util.UUID; import javax.jms.Destination; import javax.jms.JMSException; +import javax.jms.MessageNotReadableException; import javax.jms.MessageNotWriteableException; +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message { + + protected ByteBuffer _data; + protected boolean _readableMessage = false; + protected boolean _changedData = true; + /** If the acknowledge mode is CLIENT_ACKNOWLEDGE the session is required */ + + + protected AMQMessageDelegate _delegate; private boolean _redelivered; - private boolean _receivedFromServer; - protected AbstractJMSMessage(AMQMessageDelegateFactory delegateFactory, boolean fromReceivedData) + protected AbstractJMSMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data) { _delegate = delegateFactory.createDelegate(); - setContentType(getMimeType()); + _data = data; + if (_data != null) + { + _data.acquire(); + } + + + _readableMessage = (data != null); + _changedData = (data == null); + } - protected AbstractJMSMessage(AMQMessageDelegate delegate, boolean fromReceivedData) throws AMQException + protected AbstractJMSMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException { _delegate = delegate; - setContentType(getMimeType()); + + _data = data; + if (_data != null) + { + _data.acquire(); + } + + _readableMessage = data != null; + } public String getJMSMessageID() throws JMSException @@ -301,9 +329,12 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message public void clearBody() throws JMSException { - _receivedFromServer = false; + clearBodyImpl(); + _readableMessage = false; + } + public void acknowledgeThis() throws JMSException { _delegate.acknowledgeThis(); @@ -314,7 +345,14 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message _delegate.acknowledge(); } - /* + /** + * This forces concrete classes to implement clearBody() + * + * @throws JMSException + */ + public abstract void clearBodyImpl() throws JMSException; + + /** * Get a String representation of the body of the message. Used in the toString() method which outputs this before * message properties. */ @@ -375,24 +413,63 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message return _delegate; } - abstract public ByteBuffer getData() throws JMSException; + public ByteBuffer getData() + { + // make sure we rewind the data just in case any method has moved the + // position beyond the start + if (_data != null) + { + reset(); + } + return _data; + } + + protected void checkReadable() throws MessageNotReadableException + { + if (!_readableMessage) + { + throw new MessageNotReadableException("You need to call reset() to make the message readable"); + } + } protected void checkWritable() throws MessageNotWriteableException { - if (_receivedFromServer) + if (_readableMessage) { throw new MessageNotWriteableException("You need to call clearBody() to make the message writable"); } } - - public void setReceivedFromServer() + public void reset() { - _receivedFromServer = true; + if (!_changedData) + { + _data.rewind(); + } + else + { + _data.flip(); + _changedData = false; + } } + public int getContentLength() + { + if(_data != null) + { + return _data.remaining(); + } + else + { + return 0; + } + } + public void receivedFromServer() + { + _changedData = false; + } /** * The session is set when CLIENT_ACKNOWLEDGE mode is used so that the CHANNEL ACK can be sent when the user calls 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 967a1fb49f..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 @@ -20,6 +20,8 @@ */ package org.apache.qpid.client.message; +import org.apache.mina.common.ByteBuffer; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentBody; @@ -36,8 +38,6 @@ import javax.jms.JMSException; import java.util.Iterator; import java.util.List; -import java.nio.ByteBuffer; - public abstract class AbstractJMSMessageFactory implements MessageFactory { private static final Logger _logger = LoggerFactory.getLogger(AbstractJMSMessageFactory.class); @@ -57,7 +57,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory _logger.debug("Non-fragmented message body (bodySize=" + contentHeader.bodySize + ")"); } - data = ByteBuffer.wrap(((ContentBody) bodies.get(0))._payload); + data = ((ContentBody) bodies.get(0)).payload; } else if (bodies != null) { @@ -72,7 +72,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory while (it.hasNext()) { ContentBody cb = (ContentBody) it.next(); - final ByteBuffer payload = ByteBuffer.wrap(cb._payload); + final ByteBuffer payload = cb.payload; if(payload.isDirect() || payload.isReadOnly()) { data.put(payload); @@ -82,6 +82,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory data.put(payload.array(), payload.arrayOffset(), payload.limit()); } + payload.release(); } data.flip(); @@ -98,7 +99,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory } AMQMessageDelegate delegate = new AMQMessageDelegate_0_8(messageNbr, - (BasicContentHeaderProperties) contentHeader.getProperties(), + (BasicContentHeaderProperties) contentHeader.properties, exchange, routingKey); return createMessage(delegate, data); @@ -108,7 +109,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory protected AbstractJMSMessage create010MessageWithBody(long messageNbr, MessageProperties msgProps, - DeliveryProperties deliveryProps, + DeliveryProperties deliveryProps, java.nio.ByteBuffer body) throws AMQException { ByteBuffer data; @@ -117,7 +118,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory if (body != null) { - data = body; + data = ByteBuffer.wrap(body); } else // body == null { @@ -154,7 +155,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory { final AbstractJMSMessage msg = create08MessageWithBody(messageNbr, contentHeader, exchange, routingKey, bodies); msg.setJMSRedelivered(redelivered); - msg.setReceivedFromServer(); + msg.receivedFromServer(); return msg; } @@ -165,7 +166,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory final AbstractJMSMessage msg = create010MessageWithBody(messageNbr,msgProps,deliveryProps, body); msg.setJMSRedelivered(redelivered); - msg.setReceivedFromServer(); + msg.receivedFromServer(); return msg; } 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 e252bdb719..b87275a9ce 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 @@ -20,7 +20,6 @@ */ package org.apache.qpid.client.message; -import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; @@ -29,56 +28,47 @@ import java.nio.charset.CharsetEncoder; import javax.jms.BytesMessage; import javax.jms.JMSException; -import javax.jms.MessageEOFException; import javax.jms.MessageFormatException; +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 JMSBytesMessage extends AbstractBytesTypedMessage implements BytesMessage +public class JMSBytesMessage extends AbstractBytesMessage implements BytesMessage { public static final String MIME_TYPE = "application/octet-stream"; - private TypedBytesContentReader _typedBytesContentReader; - private TypedBytesContentWriter _typedBytesContentWriter; - public JMSBytesMessage(AMQMessageDelegateFactory delegateFactory) { - super(delegateFactory,false); - _typedBytesContentWriter = new TypedBytesContentWriter(); + this(delegateFactory,null); + + } + + /** + * Construct a bytes message with existing data. + * + * @param delegateFactory + * @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is + */ + JMSBytesMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data) + { + + super(delegateFactory, data); // this instanties a content header } JMSBytesMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException { - super(delegate, data!=null); - _typedBytesContentReader = new TypedBytesContentReader(data); + super(delegate, data); } public void reset() { + super.reset(); _readableMessage = true; - - if(_typedBytesContentReader != null) - { - _typedBytesContentReader.reset(); - } - else if (_typedBytesContentWriter != null) - { - _typedBytesContentReader = new TypedBytesContentReader(_typedBytesContentWriter.getData()); - } - } - - @Override - public void clearBody() throws JMSException - { - super.clearBody(); - _typedBytesContentReader = null; - _typedBytesContentWriter = new TypedBytesContentWriter(); - } protected String getMimeType() @@ -86,57 +76,45 @@ public class JMSBytesMessage extends AbstractBytesTypedMessage implements BytesM return MIME_TYPE; } - @Override - public java.nio.ByteBuffer getData() throws JMSException - { - return _typedBytesContentWriter == null ? _typedBytesContentReader.getData() : _typedBytesContentWriter.getData(); - } - public long getBodyLength() throws JMSException { checkReadable(); - return _typedBytesContentReader.size(); + return _data.limit(); } public boolean readBoolean() throws JMSException { checkReadable(); checkAvailable(1); - - return _typedBytesContentReader.readBooleanImpl(); - } - - private void checkAvailable(final int i) throws MessageEOFException - { - _typedBytesContentReader.checkAvailable(1); + return _data.get() != 0; } public byte readByte() throws JMSException { checkReadable(); checkAvailable(1); - return _typedBytesContentReader.readByteImpl(); + return _data.get(); } public int readUnsignedByte() throws JMSException { checkReadable(); checkAvailable(1); - return _typedBytesContentReader.readByteImpl() & 0xFF; + return _data.getUnsigned(); } public short readShort() throws JMSException { checkReadable(); checkAvailable(2); - return _typedBytesContentReader.readShortImpl(); + return _data.getShort(); } public int readUnsignedShort() throws JMSException { checkReadable(); checkAvailable(2); - return _typedBytesContentReader.readShortImpl() & 0xFFFF; + return _data.getUnsignedShort(); } /** @@ -149,35 +127,35 @@ public class JMSBytesMessage extends AbstractBytesTypedMessage implements BytesM { checkReadable(); checkAvailable(2); - return _typedBytesContentReader.readCharImpl(); + return _data.getChar(); } public int readInt() throws JMSException { checkReadable(); checkAvailable(4); - return _typedBytesContentReader.readIntImpl(); + return _data.getInt(); } public long readLong() throws JMSException { checkReadable(); checkAvailable(8); - return _typedBytesContentReader.readLongImpl(); + return _data.getLong(); } public float readFloat() throws JMSException { checkReadable(); checkAvailable(4); - return _typedBytesContentReader.readFloatImpl(); + return _data.getFloat(); } public double readDouble() throws JMSException { checkReadable(); checkAvailable(8); - return _typedBytesContentReader.readDoubleImpl(); + return _data.getDouble(); } public String readUTF() throws JMSException @@ -186,7 +164,34 @@ public class JMSBytesMessage extends AbstractBytesTypedMessage implements BytesM // we check only for one byte since theoretically the string could be only a // single byte when using UTF-8 encoding - return _typedBytesContentReader.readLengthPrefixedUTF(); + try + { + short length = readShort(); + if(length == 0) + { + return ""; + } + else + { + CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); + ByteBuffer encodedString = _data.slice(); + encodedString.limit(length); + _data.position(_data.position()+length); + CharBuffer string = decoder.decode(encodedString.buf()); + + return string.toString(); + } + + + + } + catch (CharacterCodingException e) + { + JMSException jmse = new JMSException("Error decoding byte stream as a UTF8 string: " + e); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; + } } public int readBytes(byte[] bytes) throws JMSException @@ -196,14 +201,14 @@ public class JMSBytesMessage extends AbstractBytesTypedMessage implements BytesM throw new IllegalArgumentException("byte array must not be null"); } checkReadable(); - int count = (_typedBytesContentReader.remaining() >= bytes.length ? bytes.length : _typedBytesContentReader.remaining()); + int count = (_data.remaining() >= bytes.length ? bytes.length : _data.remaining()); if (count == 0) { return -1; } else { - _typedBytesContentReader.readRawBytes(bytes, 0, count); + _data.get(bytes, 0, count); return count; } } @@ -219,82 +224,110 @@ public class JMSBytesMessage extends AbstractBytesTypedMessage implements BytesM throw new IllegalArgumentException("maxLength must be <= bytes.length"); } checkReadable(); - int count = (_typedBytesContentReader.remaining() >= maxLength ? maxLength : _typedBytesContentReader.remaining()); + int count = (_data.remaining() >= maxLength ? maxLength : _data.remaining()); if (count == 0) { return -1; } else { - _typedBytesContentReader.readRawBytes(bytes, 0, count); + _data.get(bytes, 0, count); return count; } } - public void writeBoolean(boolean b) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeBooleanImpl(b); + _changedData = true; + _data.put(b ? (byte) 1 : (byte) 0); } public void writeByte(byte b) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeByteImpl(b); + _changedData = true; + _data.put(b); } public void writeShort(short i) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeShortImpl(i); + _changedData = true; + _data.putShort(i); } public void writeChar(char c) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeCharImpl(c); + _changedData = true; + _data.putChar(c); } public void writeInt(int i) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeIntImpl(i); + _changedData = true; + _data.putInt(i); } public void writeLong(long l) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeLongImpl(l); + _changedData = true; + _data.putLong(l); } public void writeFloat(float v) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeFloatImpl(v); + _changedData = true; + _data.putFloat(v); } public void writeDouble(double v) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeDoubleImpl(v); + _changedData = true; + _data.putDouble(v); } public void writeUTF(String string) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeLengthPrefixedUTF(string); + try + { + CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); + java.nio.ByteBuffer encodedString = encoder.encode(CharBuffer.wrap(string)); + + _data.putShort((short)encodedString.limit()); + _data.put(encodedString); + _changedData = true; + //_data.putString(string, Charset.forName("UTF-8").newEncoder()); + // we must add the null terminator manually + //_data.put((byte)0); + } + catch (CharacterCodingException e) + { + JMSException jmse = new JMSException("Unable to encode string: " + e); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; + } } public void writeBytes(byte[] bytes) throws JMSException { - writeBytes(bytes, 0, bytes.length); + checkWritable(); + _data.put(bytes); + _changedData = true; } public void writeBytes(byte[] bytes, int offset, int length) throws JMSException { checkWritable(); - _typedBytesContentWriter.writeBytesRaw(bytes, offset, length); + _data.put(bytes, offset, length); + _changedData = true; } public void writeObject(Object object) throws JMSException diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessageFactory.java index 89561b88eb..cb04ebee1b 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessageFactory.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessageFactory.java @@ -22,12 +22,11 @@ package org.apache.qpid.client.message; import javax.jms.JMSException; +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; -import java.nio.ByteBuffer; - public class JMSBytesMessageFactory extends AbstractJMSMessageFactory { protected AbstractJMSMessage createMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java index 52c0eb263b..e295d4a2a0 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java @@ -20,15 +20,12 @@ */ package org.apache.qpid.client.message; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStream; import java.util.Enumeration; import javax.jms.JMSException; import javax.jms.MessageFormatException; -import java.nio.ByteBuffer; +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQPInvalidClassException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; @@ -285,7 +282,7 @@ public final class JMSHeaderAdapter s = String.valueOf(o); } } - }//else return s // null; + }//else return s // null; } return s; @@ -461,29 +458,9 @@ public final class JMSHeaderAdapter return getHeaders().isEmpty(); } - public void writeToBuffer(final ByteBuffer data) + public void writeToBuffer(ByteBuffer data) { - try - { - getHeaders().writeToBuffer(new DataOutputStream(new OutputStream() - { - @Override - public void write(final int b) - { - data.put((byte)b); - } - - @Override - public void write(final byte[] b, final int off, final int len) - { - data.put(b, off, len); - } - })); - } - catch (IOException e) - { - throw new IllegalArgumentException("Unexpected IO Exception - should never happen", e); - } + getHeaders().writeToBuffer(data); } public Enumeration getMapNames() diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessage.java index fad24a968e..306ffeeadf 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessage.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessage.java @@ -20,8 +20,11 @@ */ package org.apache.qpid.client.message; -import org.apache.qpid.AMQException; +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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,14 +32,13 @@ import org.slf4j.LoggerFactory; import javax.jms.JMSException; import javax.jms.MessageFormatException; -import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; -public class JMSMapMessage extends AbstractJMSMessage implements javax.jms.MapMessage +public class JMSMapMessage extends AbstractBytesTypedMessage implements javax.jms.MapMessage { private static final Logger _logger = LoggerFactory.getLogger(JMSMapMessage.class); @@ -52,10 +54,10 @@ public class JMSMapMessage extends AbstractJMSMessage implements javax.jms.MapMe JMSMapMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data) throws JMSException { - super(delegateFactory, data!=null); // this instantiates a content header + super(delegateFactory, data); // this instantiates a content header if(data != null) { - populateMapFromData(data); + populateMapFromData(); } } @@ -63,10 +65,10 @@ public class JMSMapMessage extends AbstractJMSMessage implements javax.jms.MapMe JMSMapMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException { - super(delegate, data != null); + super(delegate, data); try { - populateMapFromData(data); + populateMapFromData(); } catch (JMSException je) { @@ -87,10 +89,18 @@ public class JMSMapMessage extends AbstractJMSMessage implements javax.jms.MapMe return MIME_TYPE; } + public ByteBuffer getData() + { + // What if _data is null? + writeMapToData(); + + return super.getData(); + } + @Override - public void clearBody() throws JMSException + public void clearBodyImpl() throws JMSException { - super.clearBody(); + super.clearBodyImpl(); _map.clear(); } @@ -448,18 +458,17 @@ public class JMSMapMessage extends AbstractJMSMessage implements javax.jms.MapMe return _map.containsKey(propName); } - protected void populateMapFromData(ByteBuffer data) throws JMSException + protected void populateMapFromData() throws JMSException { - TypedBytesContentReader reader = new TypedBytesContentReader(data); - if (data != null) + if (_data != null) { - data.rewind(); + _data.rewind(); - final int entries = reader.readIntImpl(); + final int entries = readIntImpl(); for (int i = 0; i < entries; i++) { - String propName = reader.readStringImpl(); - Object value = reader.readObject(); + String propName = readStringImpl(); + Object value = readObject(); _map.put(propName, value); } } @@ -469,21 +478,35 @@ public class JMSMapMessage extends AbstractJMSMessage implements javax.jms.MapMe } } - public ByteBuffer getData() - throws JMSException + protected void writeMapToData() { - TypedBytesContentWriter writer = new TypedBytesContentWriter(); - + allocateInitialBuffer(); final int size = _map.size(); - writer.writeIntImpl(size); + writeIntImpl(size); for (Map.Entry<String, Object> entry : _map.entrySet()) { - writer.writeNullTerminatedStringImpl(entry.getKey()); + try + { + writeStringImpl(entry.getKey()); + } + catch (CharacterCodingException e) + { + throw new IllegalArgumentException("Cannot encode property key name " + entry.getKey(), e); + + } - writer.writeObject(entry.getValue()); + try + { + writeObject(entry.getValue()); + } + catch (JMSException e) + { + Object value = entry.getValue(); + throw new IllegalArgumentException("Cannot encode property key name " + entry.getKey() + " value : " + value + + " (type: " + value.getClass().getName() + ").", e); + } } - return writer.getData(); } } diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessageFactory.java index 89408a5c3c..eccb90560b 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessageFactory.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessageFactory.java @@ -14,16 +14,18 @@ * "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. - * + * under the License. * + * */ package org.apache.qpid.client.message; import javax.jms.JMSException; -import java.nio.ByteBuffer; +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 JMSMapMessageFactory extends AbstractJMSMessageFactory { 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 c981c951c3..637d9dd692 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 @@ -20,28 +20,26 @@ */ package org.apache.qpid.client.message; -import java.io.*; -import java.nio.ByteBuffer; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import javax.jms.JMSException; import javax.jms.MessageFormatException; import javax.jms.ObjectMessage; +import org.apache.mina.common.ByteBuffer; + import org.apache.qpid.AMQException; -import org.apache.qpid.client.util.ClassLoadingAwareObjectInputStream; public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessage { public static final String MIME_TYPE = "application/java-object-stream"; - private static final int DEFAULT_OUTPUT_BUFFER_SIZE = 256; - - private Serializable _readData; - private ByteBuffer _data; - private Exception _exception; - - private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0); + private static final int DEFAULT_BUFFER_SIZE = 1024; /** * Creates empty, writable message for use by producers @@ -49,57 +47,41 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag */ public JMSObjectMessage(AMQMessageDelegateFactory delegateFactory) { - super(delegateFactory, false); + this(delegateFactory, null); + } + + private JMSObjectMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data) + { + super(delegateFactory, data); + if (data == null) + { + _data = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE); + _data.setAutoExpand(true); + } + + setContentType(getMimeType()); } /** * Creates read only message for delivery to consumers */ - JMSObjectMessage(AMQMessageDelegate delegate, final ByteBuffer data) throws AMQException + JMSObjectMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException { - super(delegate, data!=null); - - try - { - ClassLoadingAwareObjectInputStream in = new ClassLoadingAwareObjectInputStream(new InputStream() - { - - - @Override - public int read() throws IOException - { - return data.get(); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException - { - len = data.remaining() < len ? data.remaining() : len; - data.get(b, off, len); - return len; - } - }); - - _readData = (Serializable) in.readObject(); - } - catch (IOException e) - { - _exception = e; - } - catch (ClassNotFoundException e) - { - _exception = e; - } + super(delegate, data); } - public void clearBody() throws JMSException + public void clearBodyImpl() throws JMSException { - super.clearBody(); - _exception = null; - _readData = null; - _data = null; + if (_data != null) + { + _data.release(); + _data = null; + } + + + } public String toBodyString() throws JMSException @@ -112,116 +94,83 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag return MIME_TYPE; } - @Override - public ByteBuffer getData() throws JMSException + public void setObject(Serializable serializable) throws JMSException { - if(_exception != null) - { - final MessageFormatException messageFormatException = - new MessageFormatException("Unable to deserialize message"); - messageFormatException.setLinkedException(_exception); - throw messageFormatException; - } - if(_readData == null) - { + checkWritable(); - return _data == null ? EMPTY_BYTE_BUFFER : _data.duplicate(); + if (_data == null) + { + _data = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE); + _data.setAutoExpand(true); } else { - try - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(DEFAULT_OUTPUT_BUFFER_SIZE); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(_readData); - oos.flush(); - return ByteBuffer.wrap(baos.toByteArray()); - } - catch (IOException e) - { - final JMSException jmsException = new JMSException("Unable to encode object of type: " + - _readData.getClass().getName() + ", value " + _readData); - jmsException.setLinkedException(e); - throw jmsException; - } + _data.rewind(); } - } - - public void setObject(Serializable serializable) throws JMSException - { - checkWritable(); - clearBody(); try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(DEFAULT_OUTPUT_BUFFER_SIZE); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(serializable); - oos.flush(); - _data = ByteBuffer.wrap(baos.toByteArray()); + ObjectOutputStream out = new ObjectOutputStream(_data.asOutputStream()); + out.writeObject(serializable); + out.flush(); + out.close(); } catch (IOException e) { - final JMSException jmsException = new JMSException("Unable to encode object of type: " + - serializable.getClass().getName() + ", value " + serializable); - jmsException.setLinkedException(e); - throw jmsException; + MessageFormatException mfe = new MessageFormatException("Message not serializable: " + e); + mfe.setLinkedException(e); + mfe.initCause(e); + throw mfe; } } public Serializable getObject() throws JMSException { - if(_exception != null) + ObjectInputStream in = null; + if (_data == null) { - final MessageFormatException messageFormatException = new MessageFormatException("Unable to deserialize message"); - messageFormatException.setLinkedException(_exception); - throw messageFormatException; + return null; } - else if(_readData != null || _data == null) + + try { - return _readData; + _data.rewind(); + in = new ObjectInputStream(_data.asInputStream()); + + return (Serializable) in.readObject(); } - else + catch (IOException e) + { + MessageFormatException mfe = new MessageFormatException("Could not deserialize message: " + e); + mfe.setLinkedException(e); + mfe.initCause(e); + throw mfe; + } + catch (ClassNotFoundException e) + { + MessageFormatException mfe = new MessageFormatException("Could not deserialize message: " + e); + mfe.setLinkedException(e); + mfe.initCause(e); + throw mfe; + } + finally { - Exception exception = null; + // _data.rewind(); + close(in); + } + } - final ByteBuffer data = _data.duplicate(); - try - { - ClassLoadingAwareObjectInputStream in = new ClassLoadingAwareObjectInputStream(new InputStream() - { - @Override - public int read() throws IOException - { - return data.get(); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException - { - len = data.remaining() < len ? data.remaining() : len; - data.get(b, off, len); - return len; - } - }); - - return (Serializable) in.readObject(); - } - catch (ClassNotFoundException e) - { - exception = e; - } - catch (IOException e) + private static void close(InputStream in) + { + try + { + if (in != null) { - exception = e; + in.close(); } - - JMSException jmsException = new JMSException("Could not deserialize object"); - jmsException.setLinkedException(exception); - throw jmsException; } - + catch (IOException ignore) + { } } - } diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java index 4660c91c1f..03851dfa01 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,8 +22,10 @@ package org.apache.qpid.client.message; import javax.jms.JMSException; -import java.nio.ByteBuffer; +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 JMSObjectMessageFactory extends AbstractJMSMessageFactory { diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessage.java index 5c93f6b6f0..ad2620852b 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessage.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessage.java @@ -23,8 +23,7 @@ package org.apache.qpid.client.message; import javax.jms.JMSException; import javax.jms.StreamMessage; -import java.nio.ByteBuffer; - +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -37,76 +36,65 @@ public class JMSStreamMessage extends AbstractBytesTypedMessage implements Strea public static final String MIME_TYPE="jms/stream-message"; - private TypedBytesContentReader _typedBytesContentReader; - private TypedBytesContentWriter _typedBytesContentWriter; + + /** + * This is set when reading a byte array. The readBytes(byte[]) method supports multiple calls to read + * a byte array in multiple chunks, hence this is used to track how much is left to be read + */ + private int _byteArrayRemaining = -1; public JMSStreamMessage(AMQMessageDelegateFactory delegateFactory) { - super(delegateFactory,false); - _typedBytesContentWriter = new TypedBytesContentWriter(); + this(delegateFactory,null); } + /** + * Construct a stream message with existing data. + * + * @param delegateFactory + * @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is + */ + JMSStreamMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data) + { + super(delegateFactory, data); // this instanties a content header + } JMSStreamMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException { - super(delegate, data!=null); - _typedBytesContentReader = new TypedBytesContentReader(data); + + super(delegate, data); } + public void reset() { + super.reset(); _readableMessage = true; - - if(_typedBytesContentReader != null) - { - _typedBytesContentReader.reset(); - } - else if (_typedBytesContentWriter != null) - { - _typedBytesContentReader = new TypedBytesContentReader(_typedBytesContentWriter.getData()); - } - } - - @Override - public void clearBody() throws JMSException - { - super.clearBody(); - _typedBytesContentReader = null; - _typedBytesContentWriter = new TypedBytesContentWriter(); - } - protected String getMimeType() { return MIME_TYPE; } - @Override - public java.nio.ByteBuffer getData() throws JMSException - { - return _typedBytesContentWriter == null ? _typedBytesContentReader.getData() : _typedBytesContentWriter.getData(); - } + public boolean readBoolean() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readBoolean(); + return super.readBoolean(); } public byte readByte() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readByte(); + return super.readByte(); } public short readShort() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readShort(); + return super.readShort(); } /** @@ -117,127 +105,102 @@ public class JMSStreamMessage extends AbstractBytesTypedMessage implements Strea */ public char readChar() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readChar(); + return super.readChar(); } public int readInt() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readInt(); + return super.readInt(); } public long readLong() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readLong(); + return super.readLong(); } public float readFloat() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readFloat(); + return super.readFloat(); } public double readDouble() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readDouble(); + return super.readDouble(); } public String readString() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readString(); + return super.readString(); } public int readBytes(byte[] bytes) throws JMSException { - if(bytes == null) - { - throw new IllegalArgumentException("Must provide non-null array to read into"); - } - - checkReadable(); - return _typedBytesContentReader.readBytes(bytes); + return super.readBytes(bytes); } public Object readObject() throws JMSException { - checkReadable(); - return _typedBytesContentReader.readObject(); + return super.readObject(); } public void writeBoolean(boolean b) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeBoolean(b); + super.writeBoolean(b); } public void writeByte(byte b) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeByte(b); + super.writeByte(b); } public void writeShort(short i) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeShort(i); + super.writeShort(i); } public void writeChar(char c) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeChar(c); + super.writeChar(c); } public void writeInt(int i) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeInt(i); + super.writeInt(i); } public void writeLong(long l) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeLong(l); + super.writeLong(l); } public void writeFloat(float v) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeFloat(v); + super.writeFloat(v); } public void writeDouble(double v) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeDouble(v); + super.writeDouble(v); } public void writeString(String string) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeString(string); + super.writeString(string); } public void writeBytes(byte[] bytes) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeBytes(bytes); + super.writeBytes(bytes); } public void writeBytes(byte[] bytes, int offset, int length) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeBytes(bytes, offset, length); + super.writeBytes(bytes,offset,length); } public void writeObject(Object object) throws JMSException { - checkWritable(); - _typedBytesContentWriter.writeObject(object); + super.writeObject(object); } } diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessageFactory.java index 359f5157f3..5e25db9ae0 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessageFactory.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessageFactory.java @@ -22,9 +22,10 @@ package org.apache.qpid.client.message; import javax.jms.JMSException; -import java.nio.ByteBuffer; - +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 JMSStreamMessageFactory extends AbstractJMSMessageFactory { 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 acf3a0ca14..fc2006a119 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 @@ -20,21 +20,15 @@ */ package org.apache.qpid.client.message; -import java.io.DataInputStream; import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; import javax.jms.JMSException; -import javax.jms.MessageFormatException; +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.client.CustomJMSXProperty; -import org.apache.qpid.framing.AMQFrameDecodingException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.util.Strings; @@ -43,7 +37,6 @@ public class JMSTextMessage extends AbstractJMSMessage implements javax.jms.Text { private static final String MIME_TYPE = "text/plain"; - private Exception _exception; private String _decodedValue; /** @@ -52,41 +45,36 @@ public class JMSTextMessage extends AbstractJMSMessage implements javax.jms.Text private static final String PAYLOAD_NULL_PROPERTY = CustomJMSXProperty.JMS_AMQP_NULL.toString(); private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); - private CharsetDecoder _decoder = DEFAULT_CHARSET.newDecoder(); - private CharsetEncoder _encoder = DEFAULT_CHARSET.newEncoder(); - - private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0); - public JMSTextMessage(AMQMessageDelegateFactory delegateFactory) throws JMSException { - super(delegateFactory, false); // this instantiates a content header + this(delegateFactory, null, null); + } + + JMSTextMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data, String encoding) throws JMSException + { + super(delegateFactory, data); // this instantiates a content header + setContentType(getMimeType()); + setEncoding(encoding); } JMSTextMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException { - super(delegate, data!=null); + super(delegate, data); + setContentType(getMimeType()); + _data = data; + } - try - { - if(propertyExists(PAYLOAD_NULL_PROPERTY)) - { - _decodedValue = null; - } - else - { - _decodedValue = _decoder.decode(data).toString(); - } - } - catch (CharacterCodingException e) - { - _exception = e; - } - catch (JMSException e) + + public void clearBodyImpl() throws JMSException + { + if (_data != null) { - _exception = e; + _data.release(); + _data = null; } + _decodedValue = null; } public String toBodyString() throws JMSException @@ -99,62 +87,95 @@ public class JMSTextMessage extends AbstractJMSMessage implements javax.jms.Text return MIME_TYPE; } - @Override - public ByteBuffer getData() throws JMSException + public void setText(String text) throws JMSException { - _encoder.reset(); + checkWritable(); + + clearBody(); try { - if(_exception != null) - { - final MessageFormatException messageFormatException = new MessageFormatException("Cannot decode original message"); - messageFormatException.setLinkedException(_exception); - throw messageFormatException; - } - else if(_decodedValue == null) - { - return EMPTY_BYTE_BUFFER; - } - else + if (text != null) { - return _encoder.encode(CharBuffer.wrap(_decodedValue)); + final String encoding = getEncoding(); + if (encoding == null || encoding.equalsIgnoreCase("UTF-8")) + { + _data = ByteBuffer.wrap(Strings.toUTF8(text)); + setEncoding("UTF-8"); + } + else + { + _data = ByteBuffer.wrap(text.getBytes(encoding)); + } + _data.position(_data.limit()); + _changedData=true; } + _decodedValue = text; } - catch (CharacterCodingException e) + catch (UnsupportedEncodingException e) { - final JMSException jmsException = new JMSException("Cannot encode string in UFT-8: " + _decodedValue); - jmsException.setLinkedException(e); - throw jmsException; + // should never occur + JMSException jmse = new JMSException("Unable to decode text data"); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; } } - @Override - public void clearBody() throws JMSException - { - super.clearBody(); - _decodedValue = null; - _exception = null; - } - - public void setText(String text) throws JMSException - { - checkWritable(); - - clearBody(); - _decodedValue = text; - - } - public String getText() throws JMSException { - return _decodedValue; + if (_data == null && _decodedValue == null) + { + return null; + } + else if (_decodedValue != null) + { + return _decodedValue; + } + else + { + _data.rewind(); + + if (propertyExists(PAYLOAD_NULL_PROPERTY) && getBooleanProperty(PAYLOAD_NULL_PROPERTY)) + { + return null; + } + if (getEncoding() != null) + { + try + { + _decodedValue = _data.getString(Charset.forName(getEncoding()).newDecoder()); + } + catch (CharacterCodingException e) + { + JMSException jmse = new JMSException("Could not decode string data: " + e); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; + } + } + else + { + try + { + _decodedValue = _data.getString(DEFAULT_CHARSET.newDecoder()); + } + catch (CharacterCodingException e) + { + JMSException jmse = new JMSException("Could not decode string data: " + e); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; + } + } + return _decodedValue; + } } @Override public void prepareForSending() throws JMSException { super.prepareForSending(); - if (_decodedValue == null) + if (_data == null) { setBooleanProperty(PAYLOAD_NULL_PROPERTY, true); } diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessageFactory.java index d1af32c10a..1f4d64c78f 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessageFactory.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessageFactory.java @@ -22,7 +22,7 @@ package org.apache.qpid.client.message; import javax.jms.JMSException; -import java.nio.ByteBuffer; +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; 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 cdb75fc9a9..4e4061cf4d 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 @@ -104,7 +104,7 @@ public class MessageFactoryRegistry AMQShortString routingKey, ContentHeaderBody contentHeader, List bodies) throws AMQException, JMSException { - BasicContentHeaderProperties properties = (BasicContentHeaderProperties) contentHeader.getProperties(); + BasicContentHeaderProperties properties = (BasicContentHeaderProperties) contentHeader.properties; // Get the message content type. This may be null for pure AMQP messages, but will always be set for JMS over // AMQP. When the type is null, it can only be assumed that the message is a byte message. diff --git a/java/client/src/main/java/org/apache/qpid/client/message/TypedBytesContentReader.java b/java/client/src/main/java/org/apache/qpid/client/message/TypedBytesContentReader.java deleted file mode 100644 index 1ae25eb1ed..0000000000 --- a/java/client/src/main/java/org/apache/qpid/client/message/TypedBytesContentReader.java +++ /dev/null @@ -1,674 +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.client.message; - -import javax.jms.JMSException; -import javax.jms.MessageEOFException; -import javax.jms.MessageFormatException; -import javax.jms.MessageNotReadableException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; - -class TypedBytesContentReader implements TypedBytesCodes -{ - - private final ByteBuffer _data; - private final int _position; - private final int _limit; - - - private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); - - private final CharsetDecoder _charsetDecoder = UTF8_CHARSET.newDecoder(); - - private int _byteArrayRemaining = -1; - - - public TypedBytesContentReader(final ByteBuffer data) - { - _data = data.duplicate(); - _position = _data.position(); - _limit = _data.limit(); - } - - /** - * Check that there is at least a certain number of bytes available to read - * - * @param len the number of bytes - * @throws javax.jms.MessageEOFException if there are less than len bytes available to read - */ - protected void checkAvailable(int len) throws MessageEOFException - { - if (_data.remaining() < len) - { - throw new MessageEOFException("Unable to read " + len + " bytes"); - } - } - - protected byte readWireType() throws MessageFormatException, MessageEOFException, - MessageNotReadableException - { - checkAvailable(1); - return _data.get(); - } - - protected boolean readBoolean() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - boolean result; - try - { - switch (wireType) - { - case BOOLEAN_TYPE: - checkAvailable(1); - result = readBooleanImpl(); - break; - case STRING_TYPE: - checkAvailable(1); - result = Boolean.parseBoolean(readStringImpl()); - break; - default: - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to a boolean"); - } - return result; - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - } - - boolean readBooleanImpl() - { - return _data.get() != 0; - } - - protected byte readByte() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - byte result; - try - { - switch (wireType) - { - case BYTE_TYPE: - checkAvailable(1); - result = readByteImpl(); - break; - case STRING_TYPE: - checkAvailable(1); - result = Byte.parseByte(readStringImpl()); - break; - default: - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to a byte"); - } - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - return result; - } - - byte readByteImpl() - { - return _data.get(); - } - - protected short readShort() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - short result; - try - { - switch (wireType) - { - case SHORT_TYPE: - checkAvailable(2); - result = readShortImpl(); - break; - case STRING_TYPE: - checkAvailable(1); - result = Short.parseShort(readStringImpl()); - break; - case BYTE_TYPE: - checkAvailable(1); - result = readByteImpl(); - break; - default: - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to a short"); - } - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - return result; - } - - short readShortImpl() - { - return _data.getShort(); - } - - /** - * Note that this method reads a unicode character as two bytes from the stream - * - * @return the character read from the stream - * @throws javax.jms.JMSException - */ - protected char readChar() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - try - { - if (wireType == NULL_STRING_TYPE) - { - throw new NullPointerException(); - } - - if (wireType != CHAR_TYPE) - { - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to a char"); - } - else - { - checkAvailable(2); - return readCharImpl(); - } - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - } - - char readCharImpl() - { - return _data.getChar(); - } - - protected int readInt() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - int result; - try - { - switch (wireType) - { - case INT_TYPE: - checkAvailable(4); - result = readIntImpl(); - break; - case SHORT_TYPE: - checkAvailable(2); - result = readShortImpl(); - break; - case STRING_TYPE: - checkAvailable(1); - result = Integer.parseInt(readStringImpl()); - break; - case BYTE_TYPE: - checkAvailable(1); - result = readByteImpl(); - break; - default: - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to an int"); - } - return result; - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - } - - protected int readIntImpl() - { - return _data.getInt(); - } - - protected long readLong() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - long result; - try - { - switch (wireType) - { - case LONG_TYPE: - checkAvailable(8); - result = readLongImpl(); - break; - case INT_TYPE: - checkAvailable(4); - result = readIntImpl(); - break; - case SHORT_TYPE: - checkAvailable(2); - result = readShortImpl(); - break; - case STRING_TYPE: - checkAvailable(1); - result = Long.parseLong(readStringImpl()); - break; - case BYTE_TYPE: - checkAvailable(1); - result = readByteImpl(); - break; - default: - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to a long"); - } - return result; - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - } - - long readLongImpl() - { - return _data.getLong(); - } - - protected float readFloat() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - float result; - try - { - switch (wireType) - { - case FLOAT_TYPE: - checkAvailable(4); - result = readFloatImpl(); - break; - case STRING_TYPE: - checkAvailable(1); - result = Float.parseFloat(readStringImpl()); - break; - default: - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to a float"); - } - return result; - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - } - - float readFloatImpl() - { - return _data.getFloat(); - } - - protected double readDouble() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - double result; - try - { - switch (wireType) - { - case DOUBLE_TYPE: - checkAvailable(8); - result = readDoubleImpl(); - break; - case FLOAT_TYPE: - checkAvailable(4); - result = readFloatImpl(); - break; - case STRING_TYPE: - checkAvailable(1); - result = Double.parseDouble(readStringImpl()); - break; - default: - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to a double"); - } - return result; - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - } - - double readDoubleImpl() - { - return _data.getDouble(); - } - - protected String readString() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - String result; - try - { - switch (wireType) - { - case STRING_TYPE: - checkAvailable(1); - result = readStringImpl(); - break; - case NULL_STRING_TYPE: - result = null; - throw new NullPointerException("data is null"); - case BOOLEAN_TYPE: - checkAvailable(1); - result = String.valueOf(readBooleanImpl()); - break; - case LONG_TYPE: - checkAvailable(8); - result = String.valueOf(readLongImpl()); - break; - case INT_TYPE: - checkAvailable(4); - result = String.valueOf(readIntImpl()); - break; - case SHORT_TYPE: - checkAvailable(2); - result = String.valueOf(readShortImpl()); - break; - case BYTE_TYPE: - checkAvailable(1); - result = String.valueOf(readByteImpl()); - break; - case FLOAT_TYPE: - checkAvailable(4); - result = String.valueOf(readFloatImpl()); - break; - case DOUBLE_TYPE: - checkAvailable(8); - result = String.valueOf(readDoubleImpl()); - break; - case CHAR_TYPE: - checkAvailable(2); - result = String.valueOf(readCharImpl()); - break; - default: - _data.position(position); - throw new MessageFormatException("Unable to convert " + wireType + " to a String"); - } - return result; - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - } - - protected String readStringImpl() throws JMSException - { - try - { - _charsetDecoder.reset(); - ByteBuffer dup = _data.duplicate(); - int pos = _data.position(); - byte b; - while((b = _data.get()) != 0); - dup.limit(_data.position()-1); - return _charsetDecoder.decode(dup).toString(); - - } - catch (CharacterCodingException e) - { - JMSException jmse = new JMSException("Error decoding byte stream as a UTF8 string: " + e); - jmse.setLinkedException(e); - jmse.initCause(e); - throw jmse; - } - } - - protected int readBytes(byte[] bytes) throws JMSException - { - if (bytes == null) - { - throw new IllegalArgumentException("byte array must not be null"); - } - // first call - if (_byteArrayRemaining == -1) - { - // type discriminator checked separately so you get a MessageFormatException rather than - // an EOF even in the case where both would be applicable - checkAvailable(1); - byte wireType = readWireType(); - if (wireType != BYTEARRAY_TYPE) - { - throw new MessageFormatException("Unable to convert " + wireType + " to a byte array"); - } - checkAvailable(4); - int size = _data.getInt(); - // length of -1 indicates null - if (size == -1) - { - return -1; - } - else - { - if (size > _data.remaining()) - { - throw new MessageEOFException("Byte array has stated length " - + size - + " but message only contains " - + - _data.remaining() - + " bytes"); - } - else - { - _byteArrayRemaining = size; - } - } - } - else if (_byteArrayRemaining == 0) - { - _byteArrayRemaining = -1; - return -1; - } - - int returnedSize = readBytesImpl(bytes); - if (returnedSize < bytes.length) - { - _byteArrayRemaining = -1; - } - return returnedSize; - } - - private int readBytesImpl(byte[] bytes) - { - int count = (_byteArrayRemaining >= bytes.length ? bytes.length : _byteArrayRemaining); - _byteArrayRemaining -= count; - - if (count == 0) - { - return 0; - } - else - { - _data.get(bytes, 0, count); - return count; - } - } - - protected Object readObject() throws JMSException - { - int position = _data.position(); - byte wireType = readWireType(); - Object result = null; - try - { - switch (wireType) - { - case BOOLEAN_TYPE: - checkAvailable(1); - result = readBooleanImpl(); - break; - case BYTE_TYPE: - checkAvailable(1); - result = readByteImpl(); - break; - case BYTEARRAY_TYPE: - checkAvailable(4); - int size = _data.getInt(); - if (size == -1) - { - result = null; - } - else - { - _byteArrayRemaining = size; - byte[] bytesResult = new byte[size]; - readBytesImpl(bytesResult); - result = bytesResult; - } - break; - case SHORT_TYPE: - checkAvailable(2); - result = readShortImpl(); - break; - case CHAR_TYPE: - checkAvailable(2); - result = readCharImpl(); - break; - case INT_TYPE: - checkAvailable(4); - result = readIntImpl(); - break; - case LONG_TYPE: - checkAvailable(8); - result = readLongImpl(); - break; - case FLOAT_TYPE: - checkAvailable(4); - result = readFloatImpl(); - break; - case DOUBLE_TYPE: - checkAvailable(8); - result = readDoubleImpl(); - break; - case NULL_STRING_TYPE: - result = null; - break; - case STRING_TYPE: - checkAvailable(1); - result = readStringImpl(); - break; - } - return result; - } - catch (RuntimeException e) - { - _data.position(position); - throw e; - } - } - - public void reset() - { - _byteArrayRemaining = -1; - _data.position(_position); - _data.limit(_limit); - } - - public ByteBuffer getData() - { - ByteBuffer buf = _data.duplicate(); - buf.position(_position); - buf.limit(_limit); - return buf; - } - - public long size() - { - return _limit - _position; - } - - public int remaining() - { - return _data.remaining(); - } - - public void readRawBytes(final byte[] bytes, final int offset, final int count) - { - _data.get(bytes, offset, count); - } - - public String readLengthPrefixedUTF() throws JMSException - { - try - { - short length = readShortImpl(); - if(length == 0) - { - return ""; - } - else - { - _charsetDecoder.reset(); - ByteBuffer encodedString = _data.slice(); - encodedString.limit(length); - _data.position(_data.position()+length); - CharBuffer string = _charsetDecoder.decode(encodedString); - - return string.toString(); - } - } - catch(CharacterCodingException e) - { - JMSException jmse = new JMSException("Error decoding byte stream as a UTF8 string: " + e); - jmse.setLinkedException(e); - jmse.initCause(e); - throw jmse; - } - } -} diff --git a/java/client/src/main/java/org/apache/qpid/client/message/TypedBytesContentWriter.java b/java/client/src/main/java/org/apache/qpid/client/message/TypedBytesContentWriter.java deleted file mode 100644 index 7c91db3a32..0000000000 --- a/java/client/src/main/java/org/apache/qpid/client/message/TypedBytesContentWriter.java +++ /dev/null @@ -1,370 +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.client.message; - -import javax.jms.JMSException; -import javax.jms.MessageFormatException; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; - -class TypedBytesContentWriter implements TypedBytesCodes -{ - private final ByteArrayOutputStream _baos = new ByteArrayOutputStream(); - private final DataOutputStream _data = new DataOutputStream(_baos); - private static final Charset UTF8 = Charset.forName("UTF-8"); - - protected void writeTypeDiscriminator(byte type) throws JMSException - { - try - { - _data.writeByte(type); - } - catch (IOException e) - { - throw handle(e); - } - } - - private JMSException handle(final IOException e) - { - JMSException jmsEx = new JMSException("Unable to write value: " + e.getMessage()); - jmsEx.setLinkedException(e); - return jmsEx; - } - - - protected void writeBoolean(boolean b) throws JMSException - { - writeTypeDiscriminator(BOOLEAN_TYPE); - writeBooleanImpl(b); - } - - public void writeBooleanImpl(final boolean b) throws JMSException - { - try - { - _data.writeByte(b ? (byte) 1 : (byte) 0); - } - catch (IOException e) - { - throw handle(e); - } - } - - protected void writeByte(byte b) throws JMSException - { - writeTypeDiscriminator(BYTE_TYPE); - writeByteImpl(b); - } - - public void writeByteImpl(final byte b) throws JMSException - { - try - { - _data.writeByte(b); - } - catch (IOException e) - { - throw handle(e); - } - } - - protected void writeShort(short i) throws JMSException - { - writeTypeDiscriminator(SHORT_TYPE); - writeShortImpl(i); - } - - public void writeShortImpl(final short i) throws JMSException - { - try - { - _data.writeShort(i); - } - catch (IOException e) - { - throw handle(e); - } - } - - protected void writeChar(char c) throws JMSException - { - writeTypeDiscriminator(CHAR_TYPE); - writeCharImpl(c); - } - - public void writeCharImpl(final char c) throws JMSException - { - try - { - _data.writeChar(c); - } - catch (IOException e) - { - throw handle(e); - } - } - - protected void writeInt(int i) throws JMSException - { - writeTypeDiscriminator(INT_TYPE); - writeIntImpl(i); - } - - protected void writeIntImpl(int i) throws JMSException - { - try - { - _data.writeInt(i); - } - catch (IOException e) - { - throw handle(e); - } - } - - protected void writeLong(long l) throws JMSException - { - writeTypeDiscriminator(LONG_TYPE); - writeLongImpl(l); - } - - public void writeLongImpl(final long l) throws JMSException - { - try - { - _data.writeLong(l); - } - catch (IOException e) - { - throw handle(e); - } - } - - protected void writeFloat(float v) throws JMSException - { - writeTypeDiscriminator(FLOAT_TYPE); - writeFloatImpl(v); - } - - public void writeFloatImpl(final float v) throws JMSException - { - try - { - _data.writeFloat(v); - } - catch (IOException e) - { - throw handle(e); - } - } - - protected void writeDouble(double v) throws JMSException - { - writeTypeDiscriminator(DOUBLE_TYPE); - writeDoubleImpl(v); - } - - public void writeDoubleImpl(final double v) throws JMSException - { - try - { - _data.writeDouble(v); - } - catch (IOException e) - { - throw handle(e); - } - } - - protected void writeString(String string) throws JMSException - { - if (string == null) - { - writeTypeDiscriminator(NULL_STRING_TYPE); - } - else - { - writeTypeDiscriminator(STRING_TYPE); - writeNullTerminatedStringImpl(string); - } - } - - protected void writeNullTerminatedStringImpl(String string) - throws JMSException - { - try - { - _data.write(string.getBytes(UTF8)); - _data.writeByte((byte) 0); - } - catch (IOException e) - { - throw handle(e); - } - - } - - protected void writeBytes(byte[] bytes) throws JMSException - { - writeBytes(bytes, 0, bytes == null ? 0 : bytes.length); - } - - protected void writeBytes(byte[] bytes, int offset, int length) throws JMSException - { - writeTypeDiscriminator(BYTEARRAY_TYPE); - writeBytesImpl(bytes, offset, length); - } - - public void writeBytesImpl(final byte[] bytes, final int offset, final int length) throws JMSException - { - try - { - if (bytes == null) - { - _data.writeInt(-1); - } - else - { - _data.writeInt(length); - _data.write(bytes, offset, length); - } - } - catch (IOException e) - { - throw handle(e); - } - } - - public void writeBytesRaw(final byte[] bytes, final int offset, final int length) throws JMSException - { - try - { - if (bytes != null) - { - _data.write(bytes, offset, length); - } - } - catch (IOException e) - { - throw handle(e); - } - } - - - protected void writeObject(Object object) throws JMSException - { - Class clazz; - - if (object == null) - { - // string handles the output of null values - clazz = String.class; - } - else - { - clazz = object.getClass(); - } - - if (clazz == Byte.class) - { - writeByte((Byte) object); - } - else if (clazz == Boolean.class) - { - writeBoolean((Boolean) object); - } - else if (clazz == byte[].class) - { - writeBytes((byte[]) object); - } - else if (clazz == Short.class) - { - writeShort((Short) object); - } - else if (clazz == Character.class) - { - writeChar((Character) object); - } - else if (clazz == Integer.class) - { - writeInt((Integer) object); - } - else if (clazz == Long.class) - { - writeLong((Long) object); - } - else if (clazz == Float.class) - { - writeFloat((Float) object); - } - else if (clazz == Double.class) - { - writeDouble((Double) object); - } - else if (clazz == String.class) - { - writeString((String) object); - } - else - { - throw new MessageFormatException("Only primitives plus byte arrays and String are valid types"); - } - } - - public ByteBuffer getData() - { - return ByteBuffer.wrap(_baos.toByteArray()); - } - - public void writeLengthPrefixedUTF(final String string) throws JMSException - { - try - { - CharsetEncoder encoder = UTF8.newEncoder(); - java.nio.ByteBuffer encodedString = encoder.encode(CharBuffer.wrap(string)); - - writeShortImpl((short) encodedString.limit()); - while(encodedString.hasRemaining()) - { - _data.writeByte(encodedString.get()); - } - } - catch (CharacterCodingException e) - { - JMSException jmse = new JMSException("Unable to encode string: " + e); - jmse.setLinkedException(e); - jmse.initCause(e); - throw jmse; - } - catch (IOException e) - { - throw handle(e); - } - - } -} diff --git a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_8.java b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_8.java index ce87a112c9..685e646d85 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_8.java +++ b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_8.java @@ -87,9 +87,9 @@ public class UnprocessedMessage_0_8 extends UnprocessedMessage public void receiveBody(ContentBody body) { - if (body._payload != null) + if (body.payload != null) { - final long payloadSize = body._payload.length; + final long payloadSize = body.payload.remaining(); if (_bodies == null) { diff --git a/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java b/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java index 368ec60525..00503cc650 100644 --- a/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java +++ b/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java @@ -27,7 +27,6 @@ import java.util.Map; import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQDestination.Binding; -import org.apache.qpid.client.messaging.address.Link.Reliability; import org.apache.qpid.client.messaging.address.Link.Subscription; import org.apache.qpid.client.messaging.address.Node.ExchangeNode; import org.apache.qpid.client.messaging.address.Node.QueueNode; @@ -55,7 +54,7 @@ public class AddressHelper public static final String EXCLUSIVE = "exclusive"; public static final String AUTO_DELETE = "auto-delete"; public static final String TYPE = "type"; - public static final String ALT_EXCHANGE = "alternate-exchange"; + public static final String ALT_EXCHANGE = "alt-exchange"; public static final String BINDINGS = "bindings"; public static final String BROWSE = "browse"; public static final String MODE = "mode"; @@ -232,9 +231,14 @@ public class AddressHelper private boolean getDurability(Map map) { - Accessor access = new MapAccessor(map); - Boolean result = access.getBoolean(DURABLE); - return (result == null) ? false : result.booleanValue(); + if (map != null && map.get(DURABLE) != null) + { + return Boolean.parseBoolean((String)map.get(DURABLE)); + } + else + { + return false; + } } /** @@ -258,7 +262,7 @@ public class AddressHelper } } - public Link getLink() throws Exception + public Link getLink() { Link link = new Link(); link.setSubscription(new Subscription()); @@ -268,25 +272,6 @@ public class AddressHelper : linkProps.getBoolean(DURABLE)); link.setName(linkProps.getString(NAME)); - String reliability = linkProps.getString(RELIABILITY); - if ( reliability != null) - { - if (reliability.equalsIgnoreCase("unreliable")) - { - link.setReliability(Reliability.UNRELIABLE); - } - else if (reliability.equalsIgnoreCase("at-least-once")) - { - link.setReliability(Reliability.AT_LEAST_ONCE); - } - else - { - throw new Exception("The reliability mode '" + - reliability + "' is not yet supported"); - } - - } - if (((Map) address.getOptions().get(LINK)).get(CAPACITY) instanceof Map) { MapAccessor capacityProps = new MapAccessor( diff --git a/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java b/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java index 5f97d625b4..a7d19d1bd5 100644 --- a/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java +++ b/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java @@ -20,8 +20,6 @@ */ package org.apache.qpid.client.messaging.address; -import static org.apache.qpid.client.messaging.address.Link.Reliability.UNSPECIFIED; - import java.util.HashMap; import java.util.Map; @@ -31,8 +29,6 @@ public class Link { public enum FilterType { SQL92, XQUERY, SUBJECT } - public enum Reliability { UNRELIABLE, AT_MOST_ONCE, AT_LEAST_ONCE, EXACTLY_ONCE, UNSPECIFIED } - protected String name; protected String _filter; protected FilterType _filterType = FilterType.SUBJECT; @@ -42,18 +38,7 @@ public class Link protected int _producerCapacity = 0; protected Node node; protected Subscription subscription; - protected Reliability reliability = UNSPECIFIED; - public Reliability getReliability() - { - return reliability; - } - - public void setReliability(Reliability reliability) - { - this.reliability = reliability; - } - public Node getNode() { return node; 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 284954edba..eb5af119b2 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,9 +20,7 @@ */ package org.apache.qpid.client.protocol; -import java.io.DataOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -30,8 +28,10 @@ import java.util.Iterator; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import org.apache.mina.filter.codec.ProtocolCodecException; import org.apache.qpid.AMQConnectionClosedException; import org.apache.qpid.AMQDisconnectedException; import org.apache.qpid.AMQException; @@ -46,7 +46,6 @@ 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.configuration.ClientProperties; import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; @@ -58,13 +57,16 @@ 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.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.protocol.ProtocolEngine; import org.apache.qpid.thread.Threading; -import org.apache.qpid.transport.Sender; -import org.apache.qpid.transport.network.NetworkConnection; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.network.io.IoTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -162,22 +164,20 @@ public class AMQProtocolHandler implements ProtocolEngine private FailoverException _lastFailoverException; /** Defines the default timeout to use for synchronous protocol commands. */ - private final long DEFAULT_SYNC_TIMEOUT = Long.getLong(ClientProperties.QPID_SYNC_OP_TIMEOUT, - Long.getLong(ClientProperties.AMQJ_DEFAULT_SYNCWRITE_TIMEOUT, - ClientProperties.DEFAULT_SYNC_OPERATION_TIMEOUT)); + 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; - private NetworkConnection _network; - private Sender<ByteBuffer> _sender; - /** * Creates a new protocol handler, associated with the specified client connection instance. * @@ -189,10 +189,43 @@ public class AMQProtocolHandler implements ProtocolEngine _protocolSession = new AMQProtocolSession(this, _connection); _stateManager = new AMQStateManager(_protocolSession); _codecFactory = new AMQCodecFactory(false, _protocolSession); + _poolReference.setThreadFactory(new ThreadFactory() + { + + public Thread newThread(final Runnable runnable) + { + try + { + return Threading.getThreadFactory().createThread(runnable); + } + catch (Exception e) + { + throw new RuntimeException("Failed to create thread", e); + } + } + }); + _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 + */ + public void createIoTransportSession(BrokerDetails brokerDetail) + { + _protocolSession = new AMQProtocolSession(this, _connection); + _stateManager.setProtocolSession(_protocolSession); + IoTransport.connect_0_9(getProtocolSession(), + brokerDetail.getHost(), + brokerDetail.getPort(), + brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SSL)); + _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 * where the connection died, an attempt to failover automatically to a new connection may be started. The failover @@ -282,7 +315,7 @@ public class AMQProtocolHandler implements ProtocolEngine // failover: HeartbeatDiagnostics.timeout(); _logger.warn("Timed out while waiting for heartbeat from peer."); - _network.close(); + _networkDriver.close(); } public void writerIdle() @@ -304,12 +337,22 @@ public class AMQProtocolHandler implements ProtocolEngine { _logger.info("Exception caught therefore going to attempt failover: " + cause, cause); // this will attempt failover - _network.close(); + _networkDriver.close(); closed(); } else { + + if (cause instanceof ProtocolCodecException) + { + _logger.info("Protocol Exception caught NOT going to attempt failover as " + + "cause isn't AMQConnectionClosedException: " + cause, cause); + + AMQException amqe = new AMQException("Protocol handler error: " + cause, cause); + propagateExceptionToAllWaiters(amqe); + } _connection.exceptionReceived(cause); + } // FIXME Need to correctly handle other exceptions. Things like ... @@ -403,63 +446,76 @@ public class AMQProtocolHandler implements ProtocolEngine public void received(ByteBuffer msg) { - _readBytes += msg.remaining(); try { + _readBytes += msg.remaining(); final ArrayList<AMQDataBlock> dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg); - // Decode buffer - - for (AMQDataBlock message : dataBlocks) + Job.fireAsynchEvent(_poolReference.getPool(), _readJob, new Runnable() { - if (PROTOCOL_DEBUG) - { - _protocolLogger.info(String.format("RECV: [%s] %s", this, message)); - } + public void run() + { + // Decode buffer - if(message instanceof AMQFrame) + for (AMQDataBlock message : dataBlocks) { - final boolean debug = _logger.isDebugEnabled(); - final long msgNumber = ++_messageReceivedCount; - if (debug && ((msgNumber % 1000) == 0)) + try { - _logger.debug("Received " + _messageReceivedCount + " protocol messages"); + 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(); + _logger.info("Broker suggested using protocol version:" + _suggestedProtocolVersion); + + // 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); } - - 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(); - _logger.info("Broker suggested using protocol version:" + _suggestedProtocolVersion); - - // 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); } - - } public void methodBodyReceived(final int channelId, final AMQBody bodyFrame) @@ -514,13 +570,28 @@ public class AMQProtocolHandler implements ProtocolEngine return getStateManager().createWaiter(states); } - public synchronized void writeFrame(AMQDataBlock frame) + /** + * Convenience method that writes a frame to the protocol session. Equivalent to calling + * getProtocolSession().write(). + * + * @param frame the frame to write + */ + public void writeFrame(AMQDataBlock frame) { - final ByteBuffer buf = asByteBuffer(frame); - _writtenBytes += buf.remaining(); - _sender.send(buf); - _sender.flush(); + writeFrame(frame, false); + } + public void writeFrame(AMQDataBlock frame, boolean 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)); @@ -537,41 +608,12 @@ public class AMQProtocolHandler implements ProtocolEngine _connection.bytesSent(_writtenBytes); - } - - private ByteBuffer asByteBuffer(AMQDataBlock block) - { - final ByteBuffer buf = ByteBuffer.allocate((int) block.getSize()); - - try + if (wait) { - block.writePayload(new DataOutputStream(new OutputStream() - { - - - @Override - public void write(int b) throws IOException - { - buf.put((byte) b); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException - { - buf.put(b, off, len); - } - })); - } - catch (IOException e) - { - throw new RuntimeException(e); + _networkDriver.flush(); } - - buf.flip(); - return buf; } - /** * Convenience method that writes a frame to the protocol session and waits for a particular response. Equivalent to * calling getProtocolSession().write() then waiting for the response. @@ -665,23 +707,24 @@ public class AMQProtocolHandler implements ProtocolEngine * <p/>If a failover exception occurs whilst closing the connection it is ignored, as the connection is closed * anyway. * - * @param timeout The timeout to wait for an acknowledgment to the close request. + * @param timeout The timeout to wait for an acknowledgement to the close request. * * @throws AMQException If the close fails for any reason. */ public void closeConnection(long timeout) throws AMQException { + 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); + + //If the connection is already closed then don't do a syncWrite if (!getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSED)) { - // Connection is already closed then don't do a syncWrite try { - final 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); - syncWrite(frame, ConnectionCloseOkBody.class, timeout); - _network.close(); + _networkDriver.close(); closed(); } catch (AMQTimeoutException e) @@ -690,9 +733,10 @@ public class AMQProtocolHandler implements ProtocolEngine } catch (FailoverException e) { - _logger.debug("FailoverException interrupted connection close, ignoring as connection closed anyway."); + _logger.debug("FailoverException interrupted connection close, ignoring as connection close anyway."); } } + _poolReference.releaseExecutorService(); } /** @return the number of bytes read from this protocol session */ @@ -800,23 +844,17 @@ public class AMQProtocolHandler implements ProtocolEngine public SocketAddress getRemoteAddress() { - return _network.getRemoteAddress(); + return _networkDriver.getRemoteAddress(); } public SocketAddress getLocalAddress() { - return _network.getLocalAddress(); - } - - public void setNetworkConnection(NetworkConnection network) - { - setNetworkConnection(network, network.getSender()); + return _networkDriver.getLocalAddress(); } - public void setNetworkConnection(NetworkConnection network, Sender<ByteBuffer> sender) + public void setNetworkDriver(NetworkDriver driver) { - _network = network; - _sender = sender; + _networkDriver = driver; } /** @param delay delay in seconds (not ms) */ @@ -824,15 +862,15 @@ public class AMQProtocolHandler implements ProtocolEngine { if (delay > 0) { - _network.setMaxWriteIdle(delay); - _network.setMaxReadIdle(HeartbeatConfig.CONFIG.getTimeout(delay)); + getNetworkDriver().setMaxWriteIdle(delay); + getNetworkDriver().setMaxReadIdle(HeartbeatConfig.CONFIG.getTimeout(delay)); HeartbeatDiagnostics.init(delay, HeartbeatConfig.CONFIG.getTimeout(delay)); } } - public NetworkConnection getNetworkConnection() + public NetworkDriver getNetworkDriver() { - return _network; + return _networkDriver; } public ProtocolVersion getSuggestedProtocolVersion() 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 b7253e6e9c..7976760696 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,36 +20,27 @@ */ package org.apache.qpid.client.protocol; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.jms.JMSException; import javax.security.sasl.SaslClient; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.apache.qpid.AMQException; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.ConnectionTuneParameters; -import org.apache.qpid.client.handler.ClientMethodDispatcherImpl; import org.apache.qpid.client.message.UnprocessedMessage; import org.apache.qpid.client.message.UnprocessedMessage_0_8; import org.apache.qpid.client.state.AMQStateManager; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.MethodDispatcher; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.client.state.AMQState; +import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.transport.Sender; -import org.apache.qpid.transport.TransportException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.qpid.client.handler.ClientMethodDispatcherImpl; /** * Wrapper for protocol session that provides type-safe access to session attributes. <p/> The underlying protocol @@ -157,6 +148,16 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession return getAMQConnection().getVirtualHost(); } + public String getUsername() + { + return getAMQConnection().getUsername(); + } + + public String getPassword() + { + return getAMQConnection().getPassword(); + } + public SaslClient getSaslClient() { return _saslClient; @@ -298,11 +299,22 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession return _connection.getSession(channelId); } + /** + * Convenience method that writes a frame to the protocol session. Equivalent to calling + * getProtocolSession().write(). + * + * @param frame the frame to write + */ public void writeFrame(AMQDataBlock frame) { _protocolHandler.writeFrame(frame); } + public void writeFrame(AMQDataBlock frame, boolean wait) + { + _protocolHandler.writeFrame(frame, wait); + } + /** * Starts the process of closing a session * @@ -363,15 +375,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession public void closeProtocolSession() throws AMQException { - try - { - _protocolHandler.getNetworkConnection().close(); - } - catch(TransportException e) - { - //ignore such exceptions, they were already logged - //and this is a forcible close. - } + _protocolHandler.closeConnection(0); } public void failover(String host, int port) diff --git a/java/client/src/main/java/org/apache/qpid/client/protocol/ProtocolBufferMonitorFilter.java b/java/client/src/main/java/org/apache/qpid/client/protocol/ProtocolBufferMonitorFilter.java new file mode 100644 index 0000000000..bbd0a7b144 --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/protocol/ProtocolBufferMonitorFilter.java @@ -0,0 +1,115 @@ +/* + * + * 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.IoFilterAdapter; +import org.apache.mina.common.IoSession; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A MINA filter that monitors the numbers of messages pending to be sent by MINA. It outputs a message + * when a threshold has been exceeded, and has a frequency configuration so that messages are not output + * too often. + * + */ +public class ProtocolBufferMonitorFilter extends IoFilterAdapter +{ + private static final Logger _logger = LoggerFactory.getLogger(ProtocolBufferMonitorFilter.class); + + public static final long DEFAULT_FREQUENCY = 5000; + + public static final int DEFAULT_THRESHOLD = 3000; + + private int _bufferedMessages = 0; + + private int _threshold; + + private long _lastMessageOutputTime; + + private long _outputFrequencyInMillis; + + public ProtocolBufferMonitorFilter() + { + _threshold = DEFAULT_THRESHOLD; + _outputFrequencyInMillis = DEFAULT_FREQUENCY; + } + + public ProtocolBufferMonitorFilter(int threshold, long frequency) + { + _threshold = threshold; + _outputFrequencyInMillis = frequency; + } + + public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception + { + _bufferedMessages++; + if (_bufferedMessages > _threshold) + { + long now = System.currentTimeMillis(); + if ((now - _lastMessageOutputTime) > _outputFrequencyInMillis) + { + _logger.warn("Protocol message buffer exceeded threshold of " + _threshold + ". Current backlog: " + + _bufferedMessages); + _lastMessageOutputTime = now; + } + } + + nextFilter.messageReceived(session, message); + } + + public void messageSent(NextFilter nextFilter, IoSession session, Object message) throws Exception + { + _bufferedMessages--; + nextFilter.messageSent(session, message); + } + + public int getBufferedMessages() + { + return _bufferedMessages; + } + + public int getThreshold() + { + return _threshold; + } + + public void setThreshold(int threshold) + { + _threshold = threshold; + } + + public long getOutputFrequencyInMillis() + { + return _outputFrequencyInMillis; + } + + public void setOutputFrequencyInMillis(long outputFrequencyInMillis) + { + _outputFrequencyInMillis = outputFrequencyInMillis; + } + + public long getLastMessageOutputTime() + { + return _lastMessageOutputTime; + } +} diff --git a/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java b/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java index 67dd1a58b6..fbca444208 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java @@ -22,9 +22,9 @@ package org.apache.qpid.client.security; import javax.security.auth.callback.CallbackHandler; -import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.client.protocol.AMQProtocolSession; public interface AMQCallbackHandler extends CallbackHandler { - void initialise(ConnectionURL connectionURL); + void initialise(AMQProtocolSession protocolSession); } diff --git a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java index 14bae68561..140cbdeb75 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java @@ -20,22 +20,17 @@ */ package org.apache.qpid.client.security; +import org.apache.qpid.util.FileUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.io.InputStream; -import java.util.Collection; -import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.TreeMap; - -import org.apache.qpid.util.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * CallbackHandlerRegistry is a registry for call back handlers for user authentication and interaction during user @@ -47,7 +42,7 @@ import org.slf4j.LoggerFactory; * "amp.callbackhandler.properties". The format of the properties file is: * * <p/><pre> - * CallbackHanlder.n.mechanism=fully.qualified.class.name where n is an ordinal + * CallbackHanlder.mechanism=fully.qualified.class.name * </pre> * * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a @@ -71,15 +66,51 @@ public class CallbackHandlerRegistry public static final String DEFAULT_RESOURCE_NAME = "org/apache/qpid/client/security/CallbackHandlerRegistry.properties"; /** A static reference to the singleton instance of this registry. */ - private static final CallbackHandlerRegistry _instance; + private static CallbackHandlerRegistry _instance = new CallbackHandlerRegistry(); /** Holds a map from SASL mechanism names to call back handlers. */ - private Map<String, Class<AMQCallbackHandler>> _mechanismToHandlerClassMap = new HashMap<String, Class<AMQCallbackHandler>>(); + private Map<String, Class> _mechanismToHandlerClassMap = new HashMap<String, Class>(); + + /** Holds a space delimited list of mechanisms that callback handlers exist for. */ + private String _mechanisms; + + /** + * Gets the singleton instance of this registry. + * + * @return The singleton instance of this registry. + */ + public static CallbackHandlerRegistry getInstance() + { + return _instance; + } - /** Ordered collection of mechanisms for which callback handlers exist. */ - private Collection<String> _mechanisms; + /** + * Gets the callback handler class for a given SASL mechanism name. + * + * @param mechanism The SASL mechanism name. + * + * @return The callback handler class for the mechanism, or null if none is configured for that mechanism. + */ + public Class getCallbackHandlerClass(String mechanism) + { + return (Class) _mechanismToHandlerClassMap.get(mechanism); + } - static + /** + * Gets a space delimited list of supported SASL mechanisms. + * + * @return A space delimited list of supported SASL mechanisms. + */ + public String getMechanisms() + { + return _mechanisms; + } + + /** + * Creates the call back handler registry from its configuration resource or file. This also has the side effect + * of configuring and registering the SASL client factory implementations using {@link DynamicSaslRegistrar}. + */ + private CallbackHandlerRegistry() { // Register any configured SASL client factories. DynamicSaslRegistrar.registerSaslProviders(); @@ -89,12 +120,12 @@ public class CallbackHandlerRegistry FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME, CallbackHandlerRegistry.class.getClassLoader()); - final Properties props = new Properties(); - try { - + Properties props = new Properties(); props.load(is); + parseProperties(props); + _logger.info("Callback handlers available for SASL mechanisms: " + _mechanisms); } catch (IOException e) { @@ -115,68 +146,32 @@ public class CallbackHandlerRegistry } } } - - _instance = new CallbackHandlerRegistry(props); - _logger.info("Callback handlers available for SASL mechanisms: " + _instance._mechanisms); - } - /** - * Gets the singleton instance of this registry. - * - * @return The singleton instance of this registry. - */ - public static CallbackHandlerRegistry getInstance() - { - return _instance; - } - - public AMQCallbackHandler createCallbackHandler(final String mechanism) + /*private InputStream openPropertiesInputStream(String filename) { - final Class<AMQCallbackHandler> mechanismClass = _mechanismToHandlerClassMap.get(mechanism); - - if (mechanismClass == null) + boolean useDefault = true; + InputStream is = null; + if (filename != null) { - throw new IllegalArgumentException("Mechanism " + mechanism + " not known"); + try + { + is = new BufferedInputStream(new FileInputStream(new File(filename))); + useDefault = false; + } + catch (FileNotFoundException e) + { + _logger.error("Unable to read from file " + filename + ": " + e, e); + } } - try - { - return mechanismClass.newInstance(); - } - catch (InstantiationException e) - { - throw new IllegalArgumentException("Unable to create an instance of mechanism " + mechanism, e); - } - catch (IllegalAccessException e) + if (useDefault) { - throw new IllegalArgumentException("Unable to create an instance of mechanism " + mechanism, e); + is = CallbackHandlerRegistry.class.getResourceAsStream(DEFAULT_RESOURCE_NAME); } - } - /** - * Gets collections of supported SASL mechanism names, ordered by preference - * - * @return collection of SASL mechanism names. - */ - public Collection<String> getMechanisms() - { - return Collections.unmodifiableCollection(_mechanisms); - } - - /** - * Creates the call back handler registry from its configuration resource or file. - * - * This also has the side effect of configuring and registering the SASL client factory - * implementations using {@link DynamicSaslRegistrar}. - * - * This constructor is default protection to allow for effective unit testing. Clients must use - * {@link #getInstance()} to obtain the singleton instance. - */ - CallbackHandlerRegistry(final Properties props) - { - parseProperties(props); - } + return is; + }*/ /** * Scans the specified properties as a mapping from IANA registered SASL mechanism to call back handler @@ -188,20 +183,20 @@ public class CallbackHandlerRegistry */ private void parseProperties(Properties props) { - - final Map<Integer, String> mechanisms = new TreeMap<Integer, String>(); - Enumeration e = props.propertyNames(); while (e.hasMoreElements()) { - final String propertyName = (String) e.nextElement(); - final String[] parts = propertyName.split("\\.", 2); + String propertyName = (String) e.nextElement(); + int period = propertyName.indexOf("."); + if (period < 0) + { + _logger.warn("Unable to parse property " + propertyName + " when configuring SASL providers"); - checkPropertyNameFormat(propertyName, parts); + continue; + } - final String mechanism = parts[0]; - final int ordinal = getPropertyOrdinal(propertyName, parts); - final String className = props.getProperty(propertyName); + String mechanism = propertyName.substring(period + 1); + String className = props.getProperty(propertyName); Class clazz = null; try { @@ -210,11 +205,20 @@ public class CallbackHandlerRegistry { _logger.warn("SASL provider " + clazz + " does not implement " + AMQCallbackHandler.class + ". Skipping"); + continue; } - _mechanismToHandlerClassMap.put(mechanism, clazz); - mechanisms.put(ordinal, mechanism); + _mechanismToHandlerClassMap.put(mechanism, clazz); + if (_mechanisms == null) + { + _mechanisms = mechanism; + } + else + { + // one time cost + _mechanisms = _mechanisms + " " + mechanism; + } } catch (ClassNotFoundException ex) { @@ -223,91 +227,5 @@ public class CallbackHandlerRegistry continue; } } - - _mechanisms = mechanisms.values(); // order guaranteed by keys of treemap (i.e. our ordinals) - - - } - - private void checkPropertyNameFormat(final String propertyName, final String[] parts) - { - if (parts.length != 2) - { - throw new IllegalArgumentException("Unable to parse property " + propertyName + " when configuring SASL providers"); - } - } - - private int getPropertyOrdinal(final String propertyName, final String[] parts) - { - try - { - return Integer.parseInt(parts[1]); - } - catch(NumberFormatException nfe) - { - throw new IllegalArgumentException("Unable to parse property " + propertyName + " when configuring SASL providers", nfe); - } - } - - /** - * Selects a SASL mechanism that is mutually available to both parties. If more than one - * mechanism is mutually available the one appearing first (by ordinal) will be returned. - * - * @param peerMechanismList space separated list of mechanisms - * @return selected mechanism, or null if none available - */ - public String selectMechanism(final String peerMechanismList) - { - final Set<String> peerList = mechListToSet(peerMechanismList); - - return selectMechInternal(peerList, Collections.<String>emptySet()); - } - - /** - * Selects a SASL mechanism that is mutually available to both parties. - * - * @param peerMechanismList space separated list of mechanisms - * @param restrictionList space separated list of mechanisms - * @return selected mechanism, or null if none available - */ - public String selectMechanism(final String peerMechanismList, final String restrictionList) - { - final Set<String> peerList = mechListToSet(peerMechanismList); - final Set<String> restrictionSet = mechListToSet(restrictionList); - - return selectMechInternal(peerList, restrictionSet); - } - - private String selectMechInternal(final Set<String> peerSet, final Set<String> restrictionSet) - { - for (final String mech : _mechanisms) - { - if (peerSet.contains(mech)) - { - if (restrictionSet.isEmpty() || restrictionSet.contains(mech)) - { - return mech; - } - } - } - - return null; - } - - private Set<String> mechListToSet(final String mechanismList) - { - if (mechanismList == null) - { - return Collections.emptySet(); - } - - final StringTokenizer tokenizer = new StringTokenizer(mechanismList, " "); - final Set<String> mechanismSet = new HashSet<String>(tokenizer.countTokens()); - while (tokenizer.hasMoreTokens()) - { - mechanismSet.add(tokenizer.nextToken()); - } - return Collections.unmodifiableSet(mechanismSet); } - } 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 b04a756e80..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 @@ -16,17 +16,7 @@ # specific language governing permissions and limitations # under the License. # - -# -# Format: -# <mechanism name>.ordinal=<implementation> -# -# @see CallbackHandlerRegistry -# - -EXTERNAL.1=org.apache.qpid.client.security.UsernamePasswordCallbackHandler -GSSAPI.2=org.apache.qpid.client.security.UsernamePasswordCallbackHandler -CRAM-MD5-HASHED.3=org.apache.qpid.client.security.UsernameHashedPasswordCallbackHandler -CRAM-MD5.4=org.apache.qpid.client.security.UsernamePasswordCallbackHandler -AMQPLAIN.5=org.apache.qpid.client.security.UsernamePasswordCallbackHandler -PLAIN.6=org.apache.qpid.client.security.UsernamePasswordCallbackHandler +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.properties b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties index b903208927..1bff43142b 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties +++ b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties @@ -18,4 +18,3 @@ # AMQPLAIN=org.apache.qpid.client.security.amqplain.AmqPlainSaslClientFactory CRAM-MD5-HASHED=org.apache.qpid.client.security.crammd5hashed.CRAMMD5HashedSaslClientFactory -ANONYMOUS=org.apache.qpid.client.security.anonymous.AnonymousSaslClientFactory diff --git a/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java b/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java index 6ec83f0a23..66176dac3c 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java @@ -20,29 +20,30 @@ */ package org.apache.qpid.client.security; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; +import org.apache.qpid.client.protocol.AMQProtocolSession; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.security.auth.callback.Callback; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; -import org.apache.qpid.jms.ConnectionURL; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; public class UsernameHashedPasswordCallbackHandler implements AMQCallbackHandler { - private ConnectionURL _connectionURL; + private static final Logger _logger = LoggerFactory.getLogger(UsernameHashedPasswordCallbackHandler.class); - /** - * @see org.apache.qpid.client.security.AMQCallbackHandler#initialise(org.apache.qpid.jms.ConnectionURL) - */ - @Override - public void initialise(ConnectionURL connectionURL) + private AMQProtocolSession _protocolSession; + + public void initialise(AMQProtocolSession protocolSession) { - _connectionURL = connectionURL; + _protocolSession = protocolSession; } public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException @@ -52,13 +53,13 @@ public class UsernameHashedPasswordCallbackHandler implements AMQCallbackHandler Callback cb = callbacks[i]; if (cb instanceof NameCallback) { - ((NameCallback) cb).setName(_connectionURL.getUsername()); + ((NameCallback) cb).setName(_protocolSession.getUsername()); } else if (cb instanceof PasswordCallback) { try { - ((PasswordCallback) cb).setPassword(getHash(_connectionURL.getPassword())); + ((PasswordCallback) cb).setPassword(getHash(_protocolSession.getPassword())); } catch (NoSuchAlgorithmException e) { @@ -98,5 +99,4 @@ public class UsernameHashedPasswordCallbackHandler implements AMQCallbackHandler return hash; } - } diff --git a/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java b/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java index ad088722c8..c50c62710f 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java @@ -27,19 +27,15 @@ import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; -import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.client.protocol.AMQProtocolSession; public class UsernamePasswordCallbackHandler implements AMQCallbackHandler { - private ConnectionURL _connectionURL; + private AMQProtocolSession _protocolSession; - /** - * @see org.apache.qpid.client.security.AMQCallbackHandler#initialise(org.apache.qpid.jms.ConnectionURL) - */ - @Override - public void initialise(final ConnectionURL connectionURL) + public void initialise(AMQProtocolSession protocolSession) { - _connectionURL = connectionURL; + _protocolSession = protocolSession; } public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException @@ -49,11 +45,11 @@ public class UsernamePasswordCallbackHandler implements AMQCallbackHandler Callback cb = callbacks[i]; if (cb instanceof NameCallback) { - ((NameCallback)cb).setName(_connectionURL.getUsername()); + ((NameCallback)cb).setName(_protocolSession.getUsername()); } else if (cb instanceof PasswordCallback) { - ((PasswordCallback)cb).setPassword(_connectionURL.getPassword().toCharArray()); + ((PasswordCallback)cb).setPassword(_protocolSession.getPassword().toCharArray()); } else { @@ -61,5 +57,4 @@ public class UsernamePasswordCallbackHandler implements AMQCallbackHandler } } } - } diff --git a/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClient.java b/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClient.java deleted file mode 100644 index 0f56b2ef6c..0000000000 --- a/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClient.java +++ /dev/null @@ -1,52 +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.client.security.anonymous; - -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; - -public class AnonymousSaslClient implements SaslClient -{ - public String getMechanismName() { - return "ANONYMOUS"; - } - public boolean hasInitialResponse() { - return true; - } - public byte[] evaluateChallenge(byte[] challenge) throws SaslException { - return new byte[0]; - } - public boolean isComplete() { - return true; - } - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - throw new IllegalStateException("No security layer supported"); - } - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - throw new IllegalStateException("No security layer supported"); - } - public Object getNegotiatedProperty(String propName) { - return null; - } - public void dispose() throws SaslException {} -} diff --git a/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClientFactory.java b/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClientFactory.java deleted file mode 100644 index de698f87c6..0000000000 --- a/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClientFactory.java +++ /dev/null @@ -1,52 +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.client.security.anonymous; - -import java.util.Arrays; -import java.util.Map; - -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslClientFactory; -import javax.security.sasl.SaslException; -import javax.security.auth.callback.CallbackHandler; - -public class AnonymousSaslClientFactory implements SaslClientFactory -{ - public SaslClient createSaslClient(String[] mechanisms, String authId, - String protocol, String server, - Map props, CallbackHandler cbh) throws SaslException - { - if (Arrays.asList(mechanisms).contains("ANONYMOUS")) { - return new AnonymousSaslClient(); - } else { - return null; - } - } - public String[] getMechanismNames(Map props) - { - if (props == null || props.isEmpty()) { - return new String[]{"ANONYMOUS"}; - } else { - return new String[0]; - } - } -} 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 0d6fc727c1..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/> @@ -47,7 +48,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * * The two step process is required as there is an inherit race condition between starting a process that will cause * the state to change and then attempting to wait for that change. The interest in the change must be first set up so - * that any asynchronous errors that occur can be delivered to the correct waiters. + * that any asynchrous errors that occur can be delivered to the correct waiters. */ public class AMQStateManager implements AMQMethodListener { @@ -83,10 +84,7 @@ public class AMQStateManager implements AMQMethodListener public AMQState getCurrentState() { - synchronized (_stateLock) - { - return _currentState; - } + return _currentState; } public void changeState(AMQState newState) @@ -116,7 +114,7 @@ public class AMQStateManager implements AMQMethodListener } /** - * Setting of the ProtocolSession will be required when Failover has been successfully completed. + * Setting of the ProtocolSession will be required when Failover has been successfuly compeleted. * * The new {@link AMQProtocolSession} that has been re-established needs to be provided as that is now the * connection to the network. @@ -133,9 +131,9 @@ public class AMQStateManager implements AMQMethodListener } /** - * Propagate error to waiters + * Propogate error to waiters * - * @param error The error to propagate. + * @param error The error to propogate. */ public void error(Exception error) { @@ -179,7 +177,7 @@ public class AMQStateManager implements AMQMethodListener } /** - * Create and add a new waiter to the notification list. + * Create and add a new waiter to the notifcation list. * * @param states The waiter will attempt to wait for one of these desired set states to be achived. * 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 732480e1c9..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 @@ -34,7 +34,7 @@ import java.util.Set; * * On construction the current state and a set of States to await for is provided. * - * When await() is called the state at construction is compared against the awaitStates. If the state at construction is + * When await() is called the state at constuction is compared against the awaitStates. If the state at construction is * a desired state then await() returns immediately. * * Otherwise it will block for the set timeout for a desired state to be achieved. @@ -48,9 +48,9 @@ public class StateWaiter extends BlockingWaiter<AMQState> { private static final Logger _logger = LoggerFactory.getLogger(StateWaiter.class); - private final Set<AMQState> _awaitStates; - private final AMQState _startState; - private final AMQStateManager _stateManager; + Set<AMQState> _awaitStates; + private AMQState _startState; + private AMQStateManager _stateManager; /** * @@ -78,9 +78,9 @@ public class StateWaiter extends BlockingWaiter<AMQState> } /** - * Await for the required State to be achieved within the default timeout. + * Await for the requried State to be achieved within the default timeout. * @return The achieved state that was requested. - * @throws AMQException The exception that prevented the required state from being achieved. + * @throws AMQException The exception that prevented the required state from being achived. */ public AMQState await() throws AMQException { @@ -88,13 +88,13 @@ public class StateWaiter extends BlockingWaiter<AMQState> } /** - * Await for the required State to be achieved. + * Await for the requried State to be achieved. * * <b>It is the responsibility of this class to remove the waiter from the StateManager * - * @param timeout The time in milliseconds to wait for any of the states to be achieved. + * @param timeout The time in milliseconds to wait for any of the states to be achived. * @return The achieved state that was requested. - * @throws AMQException The exception that prevented the required state from being achieved. + * @throws AMQException The exception that prevented the required state from being achived. */ public AMQState await(long timeout) throws AMQException { diff --git a/java/client/src/main/java/org/apache/qpid/client/transport/ClientConnectionDelegate.java b/java/client/src/main/java/org/apache/qpid/client/transport/ClientConnectionDelegate.java deleted file mode 100644 index 1b483f6948..0000000000 --- a/java/client/src/main/java/org/apache/qpid/client/transport/ClientConnectionDelegate.java +++ /dev/null @@ -1,168 +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.client.transport; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; - -import org.apache.qpid.client.security.AMQCallbackHandler; -import org.apache.qpid.client.security.CallbackHandlerRegistry; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.transport.ClientDelegate; -import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.ConnectionException; -import org.apache.qpid.transport.ConnectionOpenOk; -import org.apache.qpid.transport.ConnectionSettings; -import org.apache.qpid.transport.util.Logger; -import org.apache.qpid.util.Strings; -import org.ietf.jgss.GSSContext; -import org.ietf.jgss.GSSException; -import org.ietf.jgss.GSSManager; -import org.ietf.jgss.GSSName; -import org.ietf.jgss.Oid; - -/** - * - */ -public class ClientConnectionDelegate extends ClientDelegate -{ - private static final Logger LOGGER = Logger.get(ClientDelegate.class); - - private static final String KRB5_OID_STR = "1.2.840.113554.1.2.2"; - protected static final Oid KRB5_OID; - - static - { - Oid oid; - try - { - oid = new Oid(KRB5_OID_STR); - } - catch (GSSException ignore) - { - oid = null; - } - - KRB5_OID = oid; - } - - private final ConnectionURL _connectionURL; - - /** - * @param settings - * @param connectionURL - */ - public ClientConnectionDelegate(ConnectionSettings settings, ConnectionURL connectionURL) - { - super(settings); - this._connectionURL = connectionURL; - } - - @Override - protected SaslClient createSaslClient(List<Object> brokerMechs) throws ConnectionException, SaslException - { - final String brokerMechanisms = Strings.join(" ", brokerMechs); - final String restrictionList = _conSettings.getSaslMechs(); - final String selectedMech = CallbackHandlerRegistry.getInstance().selectMechanism(brokerMechanisms, restrictionList); - if (selectedMech == null) - { - throw new ConnectionException("Client and broker have no SASL mechanisms in common." + - " Broker allows : " + brokerMechanisms + - " Client has : " + CallbackHandlerRegistry.getInstance().getMechanisms() + - " Client restricted itself to : " + (restrictionList != null ? restrictionList : "no restriction")); - } - - Map<String,Object> saslProps = new HashMap<String,Object>(); - if (_conSettings.isUseSASLEncryption()) - { - saslProps.put(Sasl.QOP, "auth-conf"); - } - - final AMQCallbackHandler handler = CallbackHandlerRegistry.getInstance().createCallbackHandler(selectedMech); - handler.initialise(_connectionURL); - final SaslClient sc = Sasl.createSaslClient(new String[] {selectedMech}, null, _conSettings.getSaslProtocol(), _conSettings.getSaslServerName(), saslProps, handler); - - return sc; - } - - @Override - public void connectionOpenOk(Connection conn, ConnectionOpenOk ok) - { - SaslClient sc = conn.getSaslClient(); - if (sc != null) - { - if (sc.getMechanismName().equals("GSSAPI")) - { - String id = getKerberosUser(); - if (id != null) - { - conn.setUserID(id); - } - } - else if (sc.getMechanismName().equals("EXTERNAL")) - { - if (conn.getSecurityLayer() != null) - { - conn.setUserID(conn.getSecurityLayer().getUserID()); - } - } - } - - super.connectionOpenOk(conn, ok); - } - - private String getKerberosUser() - { - LOGGER.debug("Obtaining userID from kerberos"); - String service = _conSettings.getSaslProtocol() + "@" + _conSettings.getSaslServerName(); - GSSManager manager = GSSManager.getInstance(); - - try - { - GSSName acceptorName = manager.createName(service, - GSSName.NT_HOSTBASED_SERVICE, KRB5_OID); - - GSSContext secCtx = manager.createContext(acceptorName, - KRB5_OID, - null, - GSSContext.INDEFINITE_LIFETIME); - - secCtx.initSecContext(new byte[0], 0, 1); - - if (secCtx.getSrcName() != null) - { - return secCtx.getSrcName().toString(); - } - - } - catch (GSSException e) - { - LOGGER.warn("Unable to retrieve userID from Kerberos due to error",e); - } - - 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 new file mode 100644 index 0000000000..1ac8f62e32 --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java @@ -0,0 +1,90 @@ +/* + * + * 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.transport; + +import java.io.IOException; +import java.net.InetSocketAddress; + +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoConnector; +import org.apache.mina.common.SimpleByteBufferAllocator; +import org.apache.qpid.client.SSLConfiguration; +import org.apache.qpid.client.protocol.AMQProtocolHandler; +import org.apache.qpid.jms.BrokerDetails; +import org.apache.qpid.ssl.SSLContextFactory; +import org.apache.qpid.transport.network.mina.MINANetworkDriver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SocketTransportConnection implements ITransportConnection +{ + private static final Logger _logger = LoggerFactory.getLogger(SocketTransportConnection.class); + private static final int DEFAULT_BUFFER_SIZE = 32 * 1024; + + private SocketConnectorFactory _socketConnectorFactory; + + static interface SocketConnectorFactory + { + IoConnector newSocketConnector(); + } + + public SocketTransportConnection(SocketConnectorFactory socketConnectorFactory) + { + _socketConnectorFactory = socketConnectorFactory; + } + + public void connect(AMQProtocolHandler protocolHandler, BrokerDetails brokerDetail) throws IOException + { + ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers")); + + // the MINA default is currently to use the pooled allocator although this may change in future + // once more testing of the performance of the simple allocator has been done + if (!Boolean.getBoolean("amqj.enablePooledAllocator")) + { + _logger.info("Using SimpleByteBufferAllocator"); + ByteBuffer.setAllocator(new SimpleByteBufferAllocator()); + } + + final IoConnector ioConnector = _socketConnectorFactory.newSocketConnector(); + final InetSocketAddress address; + + if (brokerDetail.getTransport().equals(BrokerDetails.SOCKET)) + { + address = null; + } + else + { + address = new InetSocketAddress(brokerDetail.getHost(), brokerDetail.getPort()); + _logger.info("Attempting connection to " + address); + } + + SSLConfiguration sslConfig = protocolHandler.getConnection().getSSLConfiguration(); + SSLContextFactory sslFactory = null; + if (sslConfig != null) + { + 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 new file mode 100644 index 0000000000..aef3a563af --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java @@ -0,0 +1,351 @@ +/* + * + * 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.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; +import org.apache.mina.transport.socket.nio.ExistingSocketConnector; +import org.apache.mina.transport.socket.nio.MultiThreadSocketConnector; +import org.apache.mina.transport.socket.nio.SocketConnector; +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.protocol.ProtocolEngineFactory; +import org.apache.qpid.thread.QpidThreadExecutor; +import org.apache.qpid.transport.network.mina.MINANetworkDriver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 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 + * protocol events. <p/> Could be extended in future to support different transport types by turning this into concrete + * class/interface combo. + */ +public class TransportConnection +{ + private static ITransportConnection _instance; + + private static final Map _inVmPipeAddress = new HashMap(); + private static VmPipeAcceptor _acceptor; + private static int _currentInstance = -1; + private static int _currentVMPort = -1; + + private static final int TCP = 0; + private static final int VM = 1; + private static final int SOCKET = 2; + + private static Logger _logger = LoggerFactory.getLogger(TransportConnection.class); + + private static final String DEFAULT_QPID_SERVER = "org.apache.qpid.server.protocol.AMQProtocolEngineFactory"; + + private static Map<String, Socket> _openSocketRegister = new ConcurrentHashMap<String, Socket>(); + + public static void registerOpenSocket(String socketID, Socket openSocket) + { + _openSocketRegister.put(socketID, openSocket); + } + + public static Socket removeOpenSocket(String socketID) + { + return _openSocketRegister.remove(socketID); + } + + public static synchronized ITransportConnection getInstance(final BrokerDetails details) throws AMQTransportConnectionException + { + int transport = getTransport(details.getTransport()); + + if (transport == -1) + { + throw new AMQNoTransportForProtocolException(details, null, null); + } + + switch (transport) + { + case SOCKET: + return new SocketTransportConnection(new SocketTransportConnection.SocketConnectorFactory() + { + public IoConnector newSocketConnector() + { + 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: + return new SocketTransportConnection(new SocketTransportConnection.SocketConnectorFactory() + { + public IoConnector newSocketConnector() + { + SocketConnector result; + // FIXME - this needs to be sorted to use the new Mina MultiThread SA. + if (Boolean.getBoolean("qpidnio")) + { + _logger.warn("Using Qpid MultiThreaded NIO - " + (System.getProperties().containsKey("qpidnio") + ? "Qpid NIO is new default" + : "Sysproperty 'qpidnio' is set")); + result = new MultiThreadSocketConnector(1, new QpidThreadExecutor()); + } + else + { + _logger.info("Using Mina NIO"); + 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 + // clients (like unit tests) to complete quickly. + result.setWorkerTimeout(0); + return result; + } + }); + case VM: + { + return getVMTransport(details, Boolean.getBoolean("amqj.AutoCreateVMBroker")); + } + default: + throw new AMQNoTransportForProtocolException(details, "Transport not recognised:" + transport, null); + } + } + + private static int getTransport(String transport) + { + if (transport.equals(BrokerDetails.SOCKET)) + { + return SOCKET; + } + + if (transport.equals(BrokerDetails.TCP)) + { + return TCP; + } + + if (transport.equals(BrokerDetails.VM)) + { + return VM; + } + + return -1; + } + + private static ITransportConnection getVMTransport(BrokerDetails details, boolean AutoCreate) + throws AMQVMBrokerCreationException + { + int port = details.getPort(); + + synchronized (_inVmPipeAddress) + { + if (!_inVmPipeAddress.containsKey(port)) + { + if (AutoCreate) + { + _logger.warn("Auto Creating InVM Broker on port:" + port); + createVMBroker(port); + } + else + { + throw new AMQVMBrokerCreationException(null, port, "VM Broker on port " + port + + " does not exist. Auto create disabled.", null); + } + } + } + + return new VmPipeTransportConnection(port); + } + + public static void createVMBroker(int port) throws AMQVMBrokerCreationException + { + synchronized(TransportConnection.class) + { + if (_acceptor == null) + { + _acceptor = new VmPipeAcceptor(); + + IoServiceConfig config = _acceptor.getDefaultConfig(); + } + } + synchronized (_inVmPipeAddress) + { + + if (!_inVmPipeAddress.containsKey(port)) + { + _logger.info("Creating InVM Qpid.AMQP listening on port " + port); + IoHandlerAdapter provider = null; + try + { + VmPipeAddress pipe = new VmPipeAddress(port); + + provider = createBrokerInstance(port); + + _acceptor.bind(pipe, provider); + + _inVmPipeAddress.put(port, pipe); + _logger.info("Created InVM Qpid.AMQP listening on port " + port); + } + catch (IOException e) + { + _logger.error("Got IOException.", e); + + // Try and unbind provider + try + { + VmPipeAddress pipe = new VmPipeAddress(port); + + try + { + _acceptor.unbind(pipe); + } + catch (Exception ignore) + { + // ignore + } + + if (provider == null) + { + provider = createBrokerInstance(port); + } + + _acceptor.bind(pipe, provider); + _inVmPipeAddress.put(port, pipe); + _logger.info("Created InVM Qpid.AMQP listening on port " + port); + } + catch (IOException justUseFirstException) + { + String because; + if (e.getCause() == null) + { + because = e.toString(); + } + else + { + because = e.getCause().toString(); + } + + throw new AMQVMBrokerCreationException(null, port, because + " Stopped binding of InVM Qpid.AMQP", e); + } + } + + } + else + { + _logger.info("InVM Qpid.AMQP on port " + port + " already exits."); + } + } + } + + private static IoHandlerAdapter createBrokerInstance(int port) throws AMQVMBrokerCreationException + { + String protocolProviderClass = System.getProperty("amqj.protocolprovider.class", DEFAULT_QPID_SERVER); + _logger.info("Creating Qpid protocol provider: " + protocolProviderClass); + + // can't use introspection to get Provider as it is a server class. + // need to go straight to IoHandlerAdapter but that requries the queues and exchange from the ApplicationRegistry which we can't access. + + // get right constructor and pass in instancec ID - "port" + IoHandlerAdapter provider; + try + { + Class[] cnstr = {Integer.class}; + Object[] params = {port}; + + 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); + } + catch (Exception e) + { + _logger.info("Unable to create InVM Qpid.AMQP on port " + port + ". Because: " + e.getCause()); + String because; + if (e.getCause() == null) + { + because = e.toString(); + } + else + { + because = e.getCause().toString(); + } + + AMQVMBrokerCreationException amqbce = + new AMQVMBrokerCreationException(null, port, because + " Stopped InVM Qpid.AMQP creation", e); + throw amqbce; + } + + return provider; + } + + public static void killAllVMBrokers() + { + _logger.info("Killing all VM Brokers"); + synchronized(TransportConnection.class) + { + if (_acceptor != null) + { + _acceptor.unbindAll(); + } + synchronized (_inVmPipeAddress) + { + _inVmPipeAddress.clear(); + } + _acceptor = null; + } + _currentInstance = -1; + _currentVMPort = -1; + } + + public static void killVMBroker(int port) + { + synchronized (_inVmPipeAddress) + { + VmPipeAddress pipe = (VmPipeAddress) _inVmPipeAddress.get(port); + if (pipe != null) + { + _logger.info("Killing VM Broker:" + port); + _inVmPipeAddress.remove(port); + // This does need to be sychronized as otherwise mina can hang + // if a new connection is made + _acceptor.unbind(pipe); + } + } + } + +} 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 new file mode 100644 index 0000000000..87cc2e7a5a --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.client.transport; + +import java.io.IOException; + +import org.apache.mina.common.ConnectFuture; +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.transport.network.mina.MINANetworkDriver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VmPipeTransportConnection implements ITransportConnection +{ + private static final Logger _logger = LoggerFactory.getLogger(VmPipeTransportConnection.class); + + private int _port; + + private MINANetworkDriver _networkDriver; + + public VmPipeTransportConnection(int port) + { + _port = port; + } + + public void connect(AMQProtocolHandler protocolHandler, BrokerDetails brokerDetail) throws IOException + { + final VmPipeConnector ioConnector = new QpidVmPipeConnector(); + + final VmPipeAddress address = new VmPipeAddress(_port); + _logger.info("Attempting connection to " + address); + _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 03167561ef..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 @@ -45,7 +45,7 @@ public class URLParser private void parseURL(String fullURL) throws URLSyntaxException { // Connection URL format - // amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\',option=\'value\';tcp://host:port?option=\'value\'',failover='method?option=\'value\',option='value''" + // amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\',option=\'value\';vm://:3/virtualpath?option=\'value\'',failover='method?option=\'value\',option='value''" // Options are of course optional except for requiring a single broker in the broker list. try { @@ -195,7 +195,7 @@ public class URLParser { String brokerlist = _url.getOptions().get(AMQConnectionURL.OPTIONS_BROKERLIST); - // brokerlist tcp://host:port?option='value',option='value';tcp://host:port/virtualpath?option='value' + // brokerlist tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value' StringTokenizer st = new StringTokenizer(brokerlist, "" + URLHelper.BROKER_SEPARATOR); while (st.hasMoreTokens()) 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 bec41644fc..208658a5ff 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 @@ -28,8 +28,9 @@ import java.util.concurrent.locks.ReentrantLock; import org.apache.qpid.AMQException; import org.apache.qpid.AMQTimeoutException; import org.apache.qpid.client.failover.FailoverException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodListener; /** * BlockingWaiter is a 'rendezvous' which delegates handling of @@ -63,8 +64,6 @@ import org.slf4j.LoggerFactory; */ public abstract class BlockingWaiter<T> { - private static final Logger _logger = LoggerFactory.getLogger(BlockingWaiter.class); - /** This flag is used to indicate that the blocked for method has been received. */ private volatile boolean _ready = false; @@ -181,7 +180,7 @@ public abstract class BlockingWaiter<T> } catch (InterruptedException e) { - _logger.error(e.getMessage(), e); + System.err.println(e.getMessage()); // IGNORE -- //fixme this isn't ideal as being interrupted isn't equivellant to sucess // if (!_ready && timeout != -1) // { @@ -229,12 +228,12 @@ public abstract class BlockingWaiter<T> } /** - * This is a callback, called when an error has occurred that should interrupt any waiter. + * This is a callback, called when an error has occured that should interupt any waiter. * It is also called from within this class to avoid code repetition but it should only be called by the MINA threads. * * Once closed any notification of an exception will be ignored. * - * @param e The exception being propagated. + * @param e The exception being propogated. */ public void error(Exception e) { @@ -256,7 +255,7 @@ public abstract class BlockingWaiter<T> } else { - _logger.error("WARNING: new error '" + e == null ? "null" : e.getMessage() + "' arrived while old one not yet processed:" + _error.getMessage()); + System.err.println("WARNING: new error '" + e == null ? "null" : e.getMessage() + "' arrived while old one not yet processed:" + _error.getMessage()); } if (_waiting.get()) @@ -273,7 +272,7 @@ public abstract class BlockingWaiter<T> } catch (InterruptedException e1) { - _logger.error(e1.getMessage(), e1); + System.err.println(e.getMessage()); } } _errorAck = false; diff --git a/java/client/src/main/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStream.java b/java/client/src/main/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStream.java deleted file mode 100644 index 669a0f1abf..0000000000 --- a/java/client/src/main/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStream.java +++ /dev/null @@ -1,134 +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.client.util; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectStreamClass; -import java.lang.reflect.Proxy; -import java.util.HashMap; - - -/** - * <code>ClassLoadingAwareObjectInputStream</code> is an Extention of Object input stream to be used - * to de-serialize JMS Object Messages. - * - * <p>This was introduced to resolve the class loading issues which can happen when we use the client - * libraries in a complex class loading Environment.</p> - */ -public class ClassLoadingAwareObjectInputStream extends ObjectInputStream -{ - /** <p>Class loader instance which loaded this class. - * It will be used to load classes when we failed to load classes from dynamic class loading</p> */ - private static final ClassLoader _ON_FAULT_CLASS_LOADER = - ClassLoadingAwareObjectInputStream.class.getClassLoader(); - - /** <p>Maps primitive type names to corresponding class objects.</p> */ - private static final HashMap<String, Class> _primitives = new HashMap<String, Class>(8, 1.0F); - - - public ClassLoadingAwareObjectInputStream(InputStream in) throws IOException - { - super(in); - } - - @Override - protected Class resolveClass(ObjectStreamClass classDesc) - throws IOException, ClassNotFoundException - { - - // Here we use TTCL as our primary class loader to load the classes - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - - return load(classDesc.getName(), cl); - } - - @Override - protected Class resolveProxyClass(String[] interfaces) - throws IOException, ClassNotFoundException - { - // Here we use TTCL as our primary class loader to load the classes - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - - Class[] cinterfaces = new Class[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) - { - cinterfaces[i] = load(interfaces[i], cl); - } - - try - { - return Proxy.getProxyClass(cinterfaces[0].getClassLoader(), cinterfaces); - } - catch (IllegalArgumentException e) - { - throw new ClassNotFoundException(null, e); - } - } - - /** - * <p> - * Method we used to load class that are needed to de-serialize the objects. </p> - * <p> - * Here we first look up for the objects from the given class loader and if its not there - * we will be using the class loader of this class. - * </p> - * @param className Class name to lookup - * @param cl primary class loader which we 1st use to lookup - * @return Class instance we are looking for - * @throws ClassNotFoundException if both primary and secondary lockup's failed. - */ - private Class load(String className, ClassLoader cl) - throws ClassNotFoundException - { - try - { - return Class.forName(className, false, cl); - } - catch (ClassNotFoundException e) - { - final Class clazz = _primitives.get(className); - - if (clazz != null) - { - return clazz; - } - else - { - return Class.forName(className, false, _ON_FAULT_CLASS_LOADER); - } - } - } - - static - { - _primitives.put("boolean", boolean.class); - _primitives.put("byte", byte.class); - _primitives.put("char", char.class); - _primitives.put("short", short.class); - _primitives.put("int", int.class); - _primitives.put("long", long.class); - _primitives.put("float", float.class); - _primitives.put("double", double.class); - _primitives.put("void", void.class); - } -} diff --git a/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java b/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java new file mode 100644 index 0000000000..dc0d9b8c78 --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java @@ -0,0 +1,60 @@ +/* + * + * 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.vmbroker; + +import org.apache.qpid.client.transport.AMQTransportConnectionException; +import org.apache.qpid.protocol.AMQConstant; + +/** + * AMQVMBrokerCreationException represents failure to create an in VM broker on the vm transport medium. + * + * <p/><table id="crc"><caption>CRC Card</caption> + * <tr><th> Responsibilities <th> Collaborations + * <tr><td> Represent failure to create an in VM broker. + * </table> + * + * @todo Error code never used. This is not an AMQException. + */ +public class AMQVMBrokerCreationException extends AMQTransportConnectionException +{ + private int _port; + + /** + * @param port + * + * @deprecated + */ + public AMQVMBrokerCreationException(int port) + { + this(null, port, "Unable to create vm broker", null); + } + + public AMQVMBrokerCreationException(AMQConstant errorCode, int port, String message, Throwable cause) + { + super(errorCode, message, cause); + _port = port; + } + + public String toString() + { + return super.toString() + " on port " + _port; + } +} diff --git a/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java b/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java index 40718c6435..4159986090 100644 --- a/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java +++ b/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java @@ -37,9 +37,9 @@ public class JMSSelectorFilter implements MessageFilter public JMSSelectorFilter(String selector) throws AMQInternalException { _selector = selector; - if (_logger.isDebugEnabled()) + if (JMSSelectorFilter._logger.isDebugEnabled()) { - _logger.debug("Created JMSSelectorFilter with selector:" + _selector); + JMSSelectorFilter._logger.debug("Created JMSSelectorFilter with selector:" + _selector); } _matcher = new SelectorParser().parse(selector); } @@ -49,16 +49,16 @@ public class JMSSelectorFilter implements MessageFilter try { boolean match = _matcher.matches(message); - if (_logger.isDebugEnabled()) + if (JMSSelectorFilter._logger.isDebugEnabled()) { - _logger.debug(message + " match(" + match + ") selector(" + System + JMSSelectorFilter._logger.debug(message + " match(" + match + ") selector(" + System .identityHashCode(_selector) + "):" + _selector); } return match; } catch (AMQInternalException e) { - _logger.warn("Caught exception when evaluating message selector for message " + message, e); + JMSSelectorFilter._logger.warn("Caght exception when evaluating message selector for message " + message, e); } return false; } 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 574a1b3888..b7b6bd57bc 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 @@ -19,7 +19,6 @@ package org.apache.qpid.filter; import java.util.HashMap; -import javax.jms.DeliveryMode; import javax.jms.JMSException; import org.apache.qpid.AMQInternalException; @@ -33,7 +32,7 @@ import org.slf4j.LoggerFactory; public class PropertyExpression implements Expression { // Constants - defined the same as JMS - private static enum JMSDeliveryMode { NON_PERSISTENT, PERSISTENT } + private static final int NON_PERSISTENT = 1; private static final int DEFAULT_PRIORITY = 4; private static final Logger _logger = LoggerFactory.getLogger(PropertyExpression.class); @@ -80,24 +79,22 @@ public class PropertyExpression implements Expression { public Object evaluate(AbstractJMSMessage message) { - - JMSDeliveryMode mode = JMSDeliveryMode.NON_PERSISTENT; try { - mode = message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT ? - JMSDeliveryMode.PERSISTENT : JMSDeliveryMode.NON_PERSISTENT; - + int mode = message.getJMSDeliveryMode(); if (_logger.isDebugEnabled()) { _logger.debug("JMSDeliveryMode is :" + mode); } + + return mode; } catch (JMSException e) { _logger.warn("Error evaluating property",e); } - return mode.toString(); + return NON_PERSISTENT; } }); 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 0c2f4ce57d..6d81f728c9 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 @@ -22,7 +22,7 @@ package org.apache.qpid.jms; import java.util.Map; -import org.apache.qpid.transport.ConnectionSettings; +import org.apache.qpid.client.SSLConfiguration; public interface BrokerDetails { @@ -52,7 +52,9 @@ public interface BrokerDetails public static final int DEFAULT_PORT = 5672; + public static final String SOCKET = "socket"; public static final String TCP = "tcp"; + public static final String VM = "vm"; public static final String DEFAULT_TRANSPORT = TCP; @@ -104,12 +106,14 @@ public interface BrokerDetails long getTimeout(); void setTimeout(long timeout); + + SSLConfiguration getSSLConfiguration(); + + void setSSLConfiguration(SSLConfiguration sslConfiguration); boolean getBooleanProperty(String propName); String toString(); boolean equals(Object o); - - ConnectionSettings buildConnectionSettings(); } 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 26641982d7..0e8ca60686 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 @@ -27,7 +27,7 @@ import java.util.List; /** Connection URL format - amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\'&option=\'value\';tcp://host:port/virtualpath?option=\'value\''&failover='method?option=\'value\'&option='value''" + amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\'&option=\'value\';vm://:3/virtualpath?option=\'value\''&failover='method?option=\'value\'&option='value''" Options are of course optional except for requiring a single broker in the broker list. The option seperator is defined to be either '&' or ',' */ 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 56abf03c81..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,6 +20,7 @@ */ 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; @@ -50,7 +51,7 @@ public class FailoverPolicy private long _lastMethodTime; private long _lastFailTime; - public FailoverPolicy(ConnectionURL connectionDetails, Connection conn) + public FailoverPolicy(ConnectionURL connectionDetails, AMQConnection conn) { FailoverMethod method; @@ -82,7 +83,7 @@ public class FailoverPolicy */ if (failoverMethod.equals(FailoverMethod.SINGLE_BROKER)) { - method = new FailoverSingleServer(connectionDetails); + method = new FailoverRoundRobinServers(connectionDetails); } else { diff --git a/java/client/src/main/java/org/apache/qpid/jms/MessageProducer.java b/java/client/src/main/java/org/apache/qpid/jms/MessageProducer.java index 4ad917fa83..b830c377b8 100644 --- a/java/client/src/main/java/org/apache/qpid/jms/MessageProducer.java +++ b/java/client/src/main/java/org/apache/qpid/jms/MessageProducer.java @@ -51,4 +51,7 @@ public interface MessageProducer extends javax.jms.MessageProducer int priority, long timeToLive, boolean mandatory, boolean immediate) throws JMSException; + void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, + boolean mandatory, boolean immediate, boolean waitUntilSent) throws JMSException; + } 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 index cb3ab718e9..9e6000c472 100644 --- 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 @@ -32,9 +32,9 @@ 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.Connection; import org.apache.qpid.jms.ConnectionURL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,7 +58,7 @@ 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 Connection _conn; + private AMQConnection _conn; /** Protects the broker list when modifications happens */ private Object _brokerListLock = new Object(); @@ -80,7 +80,7 @@ public class FailoverExchangeMethod implements FailoverMethod, MessageListener /** Denotes the number of failed attempts **/ private int _failedAttemps = 0; - public FailoverExchangeMethod(ConnectionURL connectionDetails, Connection conn) + public FailoverExchangeMethod(ConnectionURL connectionDetails, AMQConnection conn) { _connectionDetails = connectionDetails; _originalBrokerDetail = _connectionDetails.getBrokerDetails(0); @@ -140,6 +140,7 @@ public class FailoverExchangeMethod implements FailoverMethod, MessageListener 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()) && 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 b480f56c07..fec5af55c1 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 @@ -36,7 +36,6 @@ import javax.jms.Queue; import javax.jms.Topic; import javax.naming.Context; import javax.naming.NamingException; -import javax.naming.ConfigurationException; import javax.naming.spi.InitialContextFactory; import org.apache.qpid.client.AMQConnectionFactory; @@ -140,7 +139,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor return new ReadOnlyContext(environment, data); } - protected void createConnectionFactories(Map data, Hashtable environment) throws ConfigurationException + protected void createConnectionFactories(Map data, Hashtable environment) { for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();) { @@ -158,7 +157,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor } } - protected void createDestinations(Map data, Hashtable environment) throws ConfigurationException + protected void createDestinations(Map data, Hashtable environment) { for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();) { @@ -226,7 +225,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor /** * Factory method to create new Connection Factory instances */ - protected ConnectionFactory createFactory(String url) throws ConfigurationException + protected ConnectionFactory createFactory(String url) { try { @@ -234,18 +233,16 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor } catch (URLSyntaxException urlse) { - _logger.warn("Unable to create factory:" + urlse); - - ConfigurationException ex = new ConfigurationException("Failed to parse entry: " + urlse + " due to : " + urlse.getMessage()); - ex.initCause(urlse); - throw ex; + _logger.warn("Unable to createFactories:" + urlse); } + + return null; } /** * Factory method to create new Destination instances from an AMQP BindingURL */ - protected Destination createDestination(String str) throws ConfigurationException + protected Destination createDestination(String str) { try { @@ -255,9 +252,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor { _logger.warn("Unable to create destination:" + e, e); - ConfigurationException ex = new ConfigurationException("Failed to parse entry: " + str + " due to : " + e.getMessage()); - ex.initCause(e); - throw ex; + return null; } } diff --git a/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindConnectionFactory.java b/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindConnectionFactory.java new file mode 100644 index 0000000000..2c08f1e34a --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindConnectionFactory.java @@ -0,0 +1,185 @@ +/* + * + * 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.IBMPerfTest; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.url.URLSyntaxException; + +import javax.jms.ConnectionFactory; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import java.io.File; +import java.util.Hashtable; + +public class JNDIBindConnectionFactory +{ + + public static final String CONNECTION_FACTORY_BINDING = "amq.ConnectionFactory"; + public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + File.separator + "IBMPerfTestsJNDI"; + public static final String PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH; + public static final String FSCONTEXT_FACTORY = "com.sun.jndi.fscontext.RefFSContextFactory"; + public static final String DEFAULT_CONNECTION_URL = "amqp://guest:guest@clientid/testpath?brokerlist='tcp://localhost:5672'"; + + private static void printUsage() + { + System.out.println("Using default values: Usage:java JNDIBindConnectionFactory <connection url> [<Connection Factory Binding>] [<Provider URL>] [<JNDI Context Factory>]"); + + } + + public static void main(String[] args) + { + Logger.getRootLogger().setLevel(Level.OFF); + + String connectionFactoryBinding = CONNECTION_FACTORY_BINDING; + String provider = PROVIDER_URL; + String contextFactory = FSCONTEXT_FACTORY; + if (args.length == 0) + { + printUsage(); + System.exit(1); + } + + String connectionURL = args[0]; + + System.out.println("Using Connection:" + connectionURL + "\n"); + + + if (args.length > 1) + { + connectionFactoryBinding = args[1]; + + if (args.length > 2) + { + provider = args[2]; + + if (args.length > 3) + { + contextFactory = args[3]; + } + } + else + { + System.out.println("Using default File System Context Factory"); + System.out.println("Using default Connection Factory Binding:" + connectionFactoryBinding); + } + } + else + { + printUsage(); + } + + + System.out.println("File System Context Factory\n" + + "Connection:" + connectionURL + "\n" + + "Connection Factory Binding:" + connectionFactoryBinding + "\n" + + "JNDI Provider URL:" + provider); + + if (provider.startsWith("file")) + { + File file = new File(provider.substring(provider.indexOf("://") + 3)); + + if (file.exists() && !file.isDirectory()) + { + System.out.println("Couldn't make directory file already exists"); + System.exit(1); + } + else + { + if (!file.exists()) + { + if (!file.mkdirs()) + { + System.out.println("Couldn't make directory"); + System.exit(1); + } + } + } + } + + new JNDIBindConnectionFactory(provider, connectionFactoryBinding, contextFactory, connectionURL); + + } + + public JNDIBindConnectionFactory(String provider, String binding, String contextFactory, String CONNECTION_URL) + { + // Set up the environment for creating the initial context + Hashtable env = new Hashtable(11); + env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory); + + env.put(Context.PROVIDER_URL, provider); + + try + { + // Create the initial context + Context ctx = new InitialContext(env); + + // Create the object to be bound + ConnectionFactory factory = null; + + try + { + factory = new AMQConnectionFactory(CONNECTION_URL); + + + try + { + Object obj = ctx.lookup(binding); + + if (obj != null) + { + System.out.println("Un-binding previous Connection Factory"); + ctx.unbind(binding); + } + } + catch (NamingException e) + { + System.out.println("Operation failed: " + e); + } + + // Perform the bind + ctx.bind(binding, factory); + System.out.println("Bound Connection Factory:" + binding); + + // Check that it is bound + Object obj = ctx.lookup(binding); + System.out.println("Connection URL:" + ((AMQConnectionFactory) obj).getConnectionURL()); + + System.out.println("JNDI FS Context:" + provider); + } + catch (NamingException amqe) + { + System.out.println("Operation failed: " + amqe); + } + catch (URLSyntaxException e) + { + System.out.println("Operation failed: " + e); + } + + } + catch (NamingException e) + { + System.out.println("Operation failed: " + e); + } + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindQueue.java b/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindQueue.java new file mode 100644 index 0000000000..10e8b94311 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindQueue.java @@ -0,0 +1,213 @@ +/* + * + * 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.IBMPerfTest; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.Session; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import java.io.File; +import java.util.Hashtable; + +public class JNDIBindQueue +{ + public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + File.separator + "IBMPerfTestsJNDI"; + public static final String PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH; + public static final String FSCONTEXT_FACTORY = "com.sun.jndi.fscontext.RefFSContextFactory"; + + Connection _connection = null; + Context _ctx = null; + + + public JNDIBindQueue(String queueBinding, String queueName, String provider, String contextFactory) + { + // Set up the environment for creating the initial context + Hashtable env = new Hashtable(11); + env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory); + + env.put(Context.PROVIDER_URL, provider); + + try + { + // Create the initial context + _ctx = new InitialContext(env); + + // Create the object to be bound + + try + { + _connection = new AMQConnection("amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'"); + System.out.println("Connected"); + } + catch (Exception amqe) + { + System.out.println("Unable to create AMQConnectionFactory:" + amqe); + } + + if (_connection != null) + { + bindQueue(queueName, queueBinding); + } + + // Check that it is bound + Object obj = _ctx.lookup(queueBinding); + + System.out.println("Bound Queue:" + ((AMQQueue) obj).toURL()); + + System.out.println("JNDI FS Context:" + provider); + + } + catch (NamingException e) + { + System.out.println("Operation failed: " + e); + } + finally + { + try + { + if (_connection != null) + { + _connection.close(); + } + } + catch (JMSException closeE) + { + System.out.println("Connection closing failed: " + closeE); + } + } + + + } + + + private void bindQueue(String queueName, String queueBinding) throws NamingException + { + + try + { + Object obj = _ctx.lookup(queueBinding); + + if (obj != null) + { + System.out.println("Un-binding exisiting object"); + _ctx.unbind(queueBinding); + } + } + catch (NamingException e) + { + + } + + Queue queue = null; + try + { + + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + if (session != null) + { + queue = ((AMQSession) session).createQueue(queueName); + } + } + catch (JMSException jmse) + { + System.out.println("Unable to create Queue:" + jmse); + } + + // Perform the bind + _ctx.bind(queueBinding, queue); + } + + + public static void main(String[] args) + { + Logger.getRootLogger().setLevel(Level.OFF); + + String provider = JNDIBindQueue.PROVIDER_URL; + String contextFactory = JNDIBindQueue.FSCONTEXT_FACTORY; + + if (args.length > 1) + { + String binding = args[0]; + String queueName = args[1]; + + if (args.length > 2) + { + provider = args[2]; + + if (args.length > 3) + { + contextFactory = args[3]; + } + } + else + { + System.out.println("Using default File System Context Factory"); + } + + System.out.println("File System Context Factory\n" + + "Binding Queue:'" + queueName + "' to '" + binding + "'\n" + + "JNDI Provider URL:" + provider); + + if (provider.startsWith("file")) + { + File file = new File(provider.substring(provider.indexOf("://") + 3)); + + if (file.exists() && !file.isDirectory()) + { + System.out.println("Couldn't make directory file already exists"); + System.exit(1); + } + else + { + if (!file.exists()) + { + if (!file.mkdirs()) + { + System.out.println("Couldn't make directory"); + System.exit(1); + } + } + } + } + + + new JNDIBindQueue(binding, queueName, provider, contextFactory); + + } + else + { + System.out.println("Using Defaults: Usage:java JNDIBindQueue <Binding> <queue name> [<Provider URL> [<JNDI Context Factory>]]"); + } + + } + + +} diff --git a/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindTopic.java b/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindTopic.java new file mode 100644 index 0000000000..ca071c1187 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindTopic.java @@ -0,0 +1,212 @@ +/* + * + * 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.IBMPerfTest; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Session; +import javax.jms.Topic; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import java.io.File; +import java.util.Hashtable; + +public class JNDIBindTopic +{ + public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + File.separator + "IBMPerfTestsJNDI"; + public static final String PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH; + + public static final String FSCONTEXT_FACTORY = "com.sun.jndi.fscontext.RefFSContextFactory"; + + Connection _connection = null; + Context _ctx = null; + + + public JNDIBindTopic(String topicBinding, String topicName, String provider, String contextFactory) + { + // Set up the environment for creating the initial context + Hashtable env = new Hashtable(11); + env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory); + + env.put(Context.PROVIDER_URL, provider); + + try + { + // Create the initial context + _ctx = new InitialContext(env); + + // Create the object to be bound + + try + { + _connection = new AMQConnection("amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'"); + System.out.println("Connected"); + } + catch (Exception amqe) + { + System.out.println("Unable to create AMQConnectionFactory:" + amqe); + } + + if (_connection != null) + { + bindTopic(topicName, topicBinding); + } + + // Check that it is bound + Object obj = _ctx.lookup(topicBinding); + + System.out.println("Bound Queue:" + ((AMQTopic) obj).toURL()); + + System.out.println("JNDI FS Context:" + provider); + + } + catch (NamingException e) + { + System.out.println("Operation failed: " + e); + } + finally + { + try + { + if (_connection != null) + { + _connection.close(); + } + } + catch (JMSException closeE) + { + System.out.println("Operation failed: " + closeE); + } + } + } + + + private void bindTopic(String topicName, String topicBinding) throws NamingException + { + + try + { + Object obj = _ctx.lookup(topicBinding); + + if (obj != null) + { + System.out.println("Un-binding exisiting object"); + _ctx.unbind(topicBinding); + } + } + catch (NamingException e) + { + + } + + Topic topic = null; + try + { + + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + if (session != null) + { + topic = ((AMQSession) session).createTopic(topicName); + } + } + catch (JMSException jmse) + { + System.out.println("Unable to create Topic:" + jmse); + } + + // Perform the bind + _ctx.bind(topicBinding, topic); + } + + + public static void main(String[] args) + { + Logger.getRootLogger().setLevel(Level.OFF); + + String provider = JNDIBindTopic.PROVIDER_URL; + String contextFactory = JNDIBindTopic.FSCONTEXT_FACTORY; + + if (args.length > 1) + { + String binding = args[0]; + String queueName = args[1]; + + if (args.length > 2) + { + provider = args[2]; + + if (args.length > 3) + { + contextFactory = args[3]; + } + } + else + { + System.out.println("Using default File System Context Factory"); + } + + System.out.println("File System Context Factory\n" + + "Binding Topic:'" + queueName + "' to '" + binding + "'\n" + + "JNDI Provider URL:" + provider); + + + if (provider.startsWith("file")) + { + File file = new File(provider.substring(provider.indexOf("://") + 3)); + + if (file.exists() && !file.isDirectory()) + { + System.out.println("Couldn't make directory file already exists"); + System.exit(1); + } + else + { + if (!file.exists()) + { + if (!file.mkdirs()) + { + System.out.println("Couldn't make directory"); + System.exit(1); + } + } + } + } + + new JNDIBindTopic(binding, queueName, provider, contextFactory); + + } + else + { + System.out.println("Usage:java JNDIBindTopic <Binding> <topic name> [<Provider URL> [<JNDI Context Factory>]]"); + } + + } + + +} diff --git a/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/README.txt b/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/README.txt new file mode 100644 index 0000000000..95ee9f9c77 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/README.txt @@ -0,0 +1,11 @@ +These JNDI setup tools are mainly for use in conjunction with the IBM JMS Performance Harness available here: +The jar should be placed in the client/test/lib/ directory. + +http://www.alphaworks.ibm.com/tech/perfharness + + +These JNDI classes use the the SUN FileSystem context. +There are two jar files that should be placed in your client/test/lib directory. + +http://javashoplm.sun.com/ECom/docs/Welcome.jsp?StoreId=22&PartDetailId=7110-jndi-1.2.1-oth-JPR&SiteId=JSC&TransactionId=noreg + diff --git a/java/client/src/old_test/java/org/apache/qpid/cluster/Client.java b/java/client/src/old_test/java/org/apache/qpid/cluster/Client.java new file mode 100644 index 0000000000..cf8059a143 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/cluster/Client.java @@ -0,0 +1,129 @@ +/* + * + * 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.cluster; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.url.URLSyntaxException; + +import javax.jms.MessageListener; +import javax.jms.Message; +import javax.jms.Session; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; +import java.util.Random; + +public class Client +{ + private final Random random = new Random(); + private final String name; + private final Session session; + private final MessageProducer topicProducer; + private final MessageProducer queueProducer; + + Client(AMQConnection connection, String name) throws JMSException, InterruptedException + { + this.name = name; + session = connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + + AMQTopic topic = new AMQTopic(((AMQSession)session).getDefaultTopicExchangeName(), new AMQShortString("cluster_test_topic")); + AMQQueue queue = new AMQQueue(((AMQSession)session).getDefaultQueueExchangeName(), new AMQShortString("cluster_test_queue")); + + topicProducer = session.createProducer(topic); + queueProducer = session.createProducer(queue); + + //subscribe to a known topic + session.createConsumer(topic).setMessageListener(new TopicHandler()); + //subscribe to a known queue + session.createConsumer(queue).setMessageListener(new QueueHandler()); + + connection.start(); + + while(true) + { + Thread.sleep(random.nextInt(60000)); + sendToQueue(name + ":" + randomString(5)); + } + } + + private synchronized void sendToTopic(String message) throws JMSException + { + topicProducer.send(session.createTextMessage(message)); + } + + private synchronized void sendToQueue(String message) throws JMSException + { + queueProducer.send(session.createTextMessage(message)); + } + + private String randomString(int length){ + char[] c = new char[length]; + for(int i = 0; i < length; i++) + { + c[i] = (char) ('A' + random.nextInt(26)); + } + return new String(c); + } + + private class QueueHandler implements MessageListener + { + public void onMessage(Message message) + { + try + { + sendToTopic(((TextMessage) message).getText()); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + } + + private class TopicHandler implements MessageListener + { + public void onMessage(Message message) + { + try + { + System.out.println(((TextMessage) message).getText()); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + } + + public static void main(String[] argv) throws AMQException, JMSException, InterruptedException, URLSyntaxException + { + //assume args describe the set of brokers to try + + String clientName = argv.length > 1 ? argv[1] : "testClient"; + new Client(new AMQConnection(argv.length > 0 ? argv[0] : "vm://:1", "guest", "guest", clientName, "/test"), clientName); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/codec/BasicDeliverTest.java b/java/client/src/old_test/java/org/apache/qpid/codec/BasicDeliverTest.java new file mode 100644 index 0000000000..1db7e200bd --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/codec/BasicDeliverTest.java @@ -0,0 +1,277 @@ +/* + * + * 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.codec; + +import org.apache.qpid.framing.*; +import org.apache.mina.common.*; +import org.apache.mina.common.support.BaseIoSession; +import org.apache.mina.filter.codec.ProtocolDecoderOutput; +import org.apache.mina.filter.codec.ProtocolEncoderOutput; + +import java.net.SocketAddress; + +/** + */ +public class BasicDeliverTest +{ + public static void main(String[] argv) throws Exception + { + BasicDeliverTest test = new BasicDeliverTest(); + + //warm up: + test.encode(512, 100000); + + //real tests: + test.encode(16, 10000, 15); + test.encode(32, 10000, 15); + test.encode(64, 10000, 15); + test.encode(128, 10000, 15); + test.encode(256, 10000, 15); + test.encode(512, 10000, 15); + test.encode(1024, 10000, 15); + test.encode(2048, 10000, 15); + + test.decode(16, 10000, 15); + test.decode(32, 10000, 15); + test.decode(64, 10000, 15); + test.decode(128, 10000, 15); + test.decode(256, 10000, 15); + test.decode(512, 10000, 15); + test.decode(1024, 10000, 15); + test.decode(2048, 10000, 15); + } + + void decode(int size, int count, int iterations) throws Exception + { + long min = Long.MAX_VALUE; + long max = 0; + long total = 0; + for (int i = 0; i < iterations; i++) + { + long time = decode(size, count); + total += time; + if (time < min) + { + min = time; + } + if (time > max) + { + max = time; + } + } + System.out.println("Decoded " + count + " messages of " + size + + " bytes: avg=" + (total / iterations) + ", min=" + min + ", max=" + max); + } + + + long decode(int size, int count) throws Exception + { + AMQDataBlock block = getDataBlock(size); + ByteBuffer data = ByteBuffer.allocate((int) block.getSize()); // XXX: Is cast a problem? + block.writePayload(data); + data.flip(); + AMQDecoder decoder = new AMQDecoder(false); + long start = System.currentTimeMillis(); + for (int i = 0; i < count; i++) + { + decoder.decode(session, data, decoderOutput); + data.rewind(); + } + return System.currentTimeMillis() - start; + } + + void encode(int size, int count, int iterations) throws Exception + { + long min = Long.MAX_VALUE; + long max = 0; + long total = 0; + for (int i = 0; i < iterations; i++) + { + long time = encode(size, count); + total += time; + if (time < min) + { + min = time; + } + if (time > max) + { + max = time; + } + } + System.out.println("Encoded " + count + " messages of " + size + + " bytes: avg=" + (total / iterations) + ", min=" + min + ", max=" + max); + } + + long encode(int size, int count) throws Exception + { + IoSession session = null; + AMQDataBlock block = getDataBlock(size); + AMQEncoder encoder = new AMQEncoder(); + long start = System.currentTimeMillis(); + for (int i = 0; i < count; i++) + { + encoder.encode(session, block, encoderOutput); + } + return System.currentTimeMillis() - start; + } + + private final ProtocolEncoderOutput encoderOutput = new ProtocolEncoderOutput() + { + + public void write(ByteBuffer byteBuffer) + { + } + + public void mergeAll() + { + } + + public WriteFuture flush() + { + return null; + } + }; + + private final ProtocolDecoderOutput decoderOutput = new ProtocolDecoderOutput() + { + public void write(Object object) + { + } + + public void flush() + { + } + }; + + private final IoSession session = new BaseIoSession() + { + + protected void updateTrafficMask() + { + //To change body of implemented methods use File | Settings | File Templates. + } + + 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 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 SocketAddress getRemoteAddress() + { + return null; //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 getScheduledWriteRequests() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public int getScheduledWriteBytes() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + }; + + private static final char[] DATA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); + + static CompositeAMQDataBlock getDataBlock(int size) + { + //create a frame representing message delivery + AMQFrame[] frames = new AMQFrame[3]; + frames[0] = wrapBody(createBasicDeliverBody()); + frames[1] = wrapBody(createContentHeaderBody()); + frames[2] = wrapBody(createContentBody(size)); + + return new CompositeAMQDataBlock(frames); + } + + static AMQFrame wrapBody(AMQBody body) + { + AMQFrame frame = new AMQFrame(1, body); + return frame; + } + + static ContentBody createContentBody(int size) + { + ContentBody body = new ContentBody(); + body.payload = ByteBuffer.allocate(size); + for (int i = 0; i < size; i++) + { + body.payload.put((byte) DATA[i % DATA.length]); + } + return body; + } + + static ContentHeaderBody createContentHeaderBody() + { + ContentHeaderBody body = new ContentHeaderBody(); + body.properties = new BasicContentHeaderProperties(); + body.weight = 1; + body.classId = 6; + return body; + } + + static BasicDeliverBody createBasicDeliverBody() + { + BasicDeliverBody body = new BasicDeliverBody((byte) 8, (byte) 0, + BasicDeliverBody.getClazz((byte) 8, (byte) 0), + BasicDeliverBody.getMethod((byte) 8, (byte) 0), + new AMQShortString("myConsumerTag"), 1, + new AMQShortString("myExchange"), false, + new AMQShortString("myRoutingKey")); + return body; + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/codec/Client.java b/java/client/src/old_test/java/org/apache/qpid/codec/Client.java new file mode 100644 index 0000000000..3886021277 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/codec/Client.java @@ -0,0 +1,133 @@ +/* + * + * 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.codec; + +import org.apache.mina.transport.socket.nio.SocketConnector; +import org.apache.mina.common.ConnectFuture; +import org.apache.mina.common.IoHandlerAdapter; +import org.apache.mina.common.IoSession; +import org.apache.mina.filter.codec.ProtocolCodecFilter; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicDeliverBody; +import org.apache.qpid.framing.ContentBody; + +import java.net.InetSocketAddress; + +public class Client extends IoHandlerAdapter +{ + //private static final int[] DEFAULT_SIZES = new int[]{1024, 512, 256, 128, 56}; + //private static final int[] DEFAULT_SIZES = new int[]{256, 256, 256, 256, 256, 512, 512, 512, 512, 512}; + private static final int[] DEFAULT_SIZES = new int[]{256, 512, 256, 512, 256, 512, 256, 512, 256, 512}; + //private static final int[] DEFAULT_SIZES = new int[]{1024, 1024, 1024, 1024, 1024}; + + private final IoSession _session; + private final long _start; + private final int _size; + private final int _count; + private int _received; + private boolean _closed; + + Client(String host, int port, int size, int count) throws Exception + { + _count = count; + _size = size; + AMQDataBlock block = BasicDeliverTest.getDataBlock(size); + + InetSocketAddress address = new InetSocketAddress(host, port); + ConnectFuture future = new SocketConnector().connect(address, this); + future.join(); + _session = future.getSession(); + + _start = System.currentTimeMillis(); + for(int i = 0; i < count; i++) + { + _session.write(block); + } + } + + void close() + { + long time = System.currentTimeMillis() - _start; + System.out.println("Received " + _received + " messages of " + _size + + " bytes in " + time + "ms."); + _session.close(); + synchronized(this) + { + _closed = true; + notify(); + } + } + + void waitForClose() throws InterruptedException + { + synchronized(this) + { + while(!_closed) + { + wait(); + } + } + } + + public void sessionCreated(IoSession session) throws Exception + { + session.getFilterChain().addLast("protocolFilter", new ProtocolCodecFilter(new AMQCodecFactory(false))); + } + + public void messageReceived(IoSession session, Object object) throws Exception + { + if(isContent(object) && ++_received == _count) close(); + } + + public void exceptionCaught(IoSession session, Throwable throwable) throws Exception + { + throwable.printStackTrace(); + close(); + } + + private static boolean isDeliver(Object o) + { + return o instanceof AMQFrame && ((AMQFrame) o).getBodyFrame() instanceof BasicDeliverBody; + } + + private static boolean isContent(Object o) + { + return o instanceof AMQFrame && ((AMQFrame) o).getBodyFrame() instanceof ContentBody; + } + + public static void main(String[] argv) throws Exception + { + String host = argv.length > 0 ? argv[0] : "localhost"; + int port = argv.length > 1 ? Integer.parseInt(argv[1]) : 8888; + int count = argv.length > 2 ? Integer.parseInt(argv[2]) : 10000; + int[] sizes = argv.length > 3 ? new int[]{Integer.parseInt(argv[3])} : DEFAULT_SIZES; + + System.out.println("Connecting to " + host + ":" + port); + + for(int i = 0; i < sizes.length; i++) + { + new Client(host, port, sizes[i], count).waitForClose(); + Thread.sleep(1000); + } + } + +} diff --git a/java/client/src/old_test/java/org/apache/qpid/codec/Server.java b/java/client/src/old_test/java/org/apache/qpid/codec/Server.java new file mode 100644 index 0000000000..fa4295e0b2 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/codec/Server.java @@ -0,0 +1,103 @@ +/* + * + * 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.codec; + +import org.apache.mina.common.IoHandlerAdapter; +import org.apache.mina.common.IoSession; +import org.apache.mina.transport.socket.nio.SocketAcceptor; +import org.apache.mina.util.SessionUtil; +import org.apache.mina.filter.codec.ProtocolCodecFilter; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.CompositeAMQDataBlock; + +import java.net.InetSocketAddress; + +public class Server extends IoHandlerAdapter +{ + Server(int port) throws Exception + { + new SocketAcceptor().bind(new InetSocketAddress(port), this); + System.out.println("Listening on " + port); + } + + public void sessionCreated(IoSession session) throws Exception + { + SessionUtil.initialize(session); + session.getFilterChain().addLast("protocolFilter", new ProtocolCodecFilter(new AMQCodecFactory(false))); + } + + public void messageReceived(IoSession session, Object object) throws Exception + { + getAccumulator(session).received(session, (AMQFrame) object); + } + + public void sessionOpened(IoSession session) throws Exception + { + System.out.println("sessionOpened()"); + } + + public void sessionClosed(IoSession session) throws Exception + { + System.out.println("sessionClosed()"); + } + + public void exceptionCaught(IoSession session, Throwable t) throws Exception + { + System.out.println("exceptionCaught()"); + t.printStackTrace(); + session.close(); + } + + private Accumulator getAccumulator(IoSession session) + { + Accumulator a = (Accumulator) session.getAttribute(ACCUMULATOR); + if(a == null) + { + a = new Accumulator(); + session.setAttribute(ACCUMULATOR, a); + } + return a; + } + + private static final String ACCUMULATOR = Accumulator.class.getName(); + + private static class Accumulator + { + private final AMQFrame[] frames = new AMQFrame[3]; + private int i; + + void received(IoSession session, AMQFrame frame) + { + frames[i++] = frame; + if(i >= frames.length) + { + i = 0; + session.write(new CompositeAMQDataBlock(frames)); + } + } + } + + public static void main(String[] argv) throws Exception + { + int port = argv.length > 0 ? Integer.parseInt(argv[0]) : 8888; + new Server(port); + } +} diff --git a/java/client/src/main/java/org/apache/qpid/client/message/TypedBytesCodes.java b/java/client/src/old_test/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java index 26a0b41cdc..cac0064785 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/TypedBytesCodes.java +++ b/java/client/src/old_test/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,29 +18,18 @@ * under the License. * */ -package org.apache.qpid.client.message; - -public interface TypedBytesCodes -{ - static final byte BOOLEAN_TYPE = (byte) 1; - - static final byte BYTE_TYPE = (byte) 2; - - static final byte BYTEARRAY_TYPE = (byte) 3; +package org.apache.qpid.config; - static final byte SHORT_TYPE = (byte) 4; +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.ConnectorConfig; - static final byte CHAR_TYPE = (byte) 5; +import javax.jms.ConnectionFactory; - static final byte INT_TYPE = (byte) 6; - - static final byte LONG_TYPE = (byte) 7; - - static final byte FLOAT_TYPE = (byte) 8; - - static final byte DOUBLE_TYPE = (byte) 9; - - static final byte STRING_TYPE = (byte) 10; - - static final byte NULL_STRING_TYPE = (byte) 11; +class AMQConnectionFactoryInitialiser implements ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) + { + return new AMQConnectionFactory(config.getHost(), config.getPort(), "/test_path"); + } } diff --git a/java/client/src/old_test/java/org/apache/qpid/config/AbstractConfig.java b/java/client/src/old_test/java/org/apache/qpid/config/AbstractConfig.java new file mode 100644 index 0000000000..04381d66a0 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/config/AbstractConfig.java @@ -0,0 +1,69 @@ +/* + * + * 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.config; + +public abstract class AbstractConfig +{ + public boolean setOptions(String[] argv) + { + try + { + for(int i = 0; i < argv.length - 1; i += 2) + { + String key = argv[i]; + String value = argv[i+1]; + setOption(key, value); + } + return true; + } + catch(Exception e) + { + System.out.println(e.getMessage()); + } + return false; + } + + protected int parseInt(String msg, String i) + { + try + { + return Integer.parseInt(i); + } + catch(NumberFormatException e) + { + throw new RuntimeException(msg + ": " + i); + } + } + + protected long parseLong(String msg, String i) + { + try + { + return Long.parseLong(i); + } + catch(NumberFormatException e) + { + throw new RuntimeException(msg + ": " + i); + } + } + + public abstract void setOption(String key, String value); +} diff --git a/java/client/src/main/java/org/apache/qpid/client/message/QpidMessageProperties.java b/java/client/src/old_test/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java index b30afafa35..a9984eb09a 100644 --- a/java/client/src/main/java/org/apache/qpid/client/message/QpidMessageProperties.java +++ b/java/client/src/old_test/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,17 +18,12 @@ * under the License. * */ -package org.apache.qpid.client.message; +package org.apache.qpid.config; -/** - * Place holder for Qpid specific message properties - */ -public class QpidMessageProperties -{ +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; - public static final String QPID_SUBJECT = "qpid.subject"; - - // AMQP 0-10 related properties - public static final String AMQP_0_10_APP_ID = "x-amqp-0-10.app-id"; - public static final String AMQP_0_10_ROUTING_KEY = "x-amqp-0-10.routing-key"; +public interface ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException; } diff --git a/java/client/src/old_test/java/org/apache/qpid/config/Connector.java b/java/client/src/old_test/java/org/apache/qpid/config/Connector.java new file mode 100644 index 0000000000..ff2377f087 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/config/Connector.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.config; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; + +public class Connector +{ + public Connection createConnection(ConnectorConfig config) throws Exception + { + return getConnectionFactory(config).createConnection(); + } + + ConnectionFactory getConnectionFactory(ConnectorConfig config) throws Exception + { + String factory = config.getFactory(); + if(factory == null) factory = AMQConnectionFactoryInitialiser.class.getName(); + System.out.println("Using " + factory); + return ((ConnectionFactoryInitialiser) Class.forName(factory).newInstance()).getFactory(config); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/config/ConnectorConfig.java b/java/client/src/old_test/java/org/apache/qpid/config/ConnectorConfig.java new file mode 100644 index 0000000000..b120ed3f12 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/config/ConnectorConfig.java @@ -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. + * + */ +package org.apache.qpid.config; + +public interface ConnectorConfig +{ + public String getHost(); + public int getPort(); + public String getFactory(); +} diff --git a/java/client/src/old_test/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java b/java/client/src/old_test/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java new file mode 100644 index 0000000000..1c86aea56c --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java @@ -0,0 +1,117 @@ +/* + * + * 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.config; + +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.ConnectorConfig; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.MBeanException; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.NameNotFoundException; +import java.util.Hashtable; + +public class JBossConnectionFactoryInitialiser implements ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException + { + ConnectionFactory cf = null; + InitialContext ic = null; + Hashtable ht = new Hashtable(); + ht.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); + String jbossHost = System.getProperty("jboss.host", "eqd-lxamq01"); + String jbossPort = System.getProperty("jboss.port", "1099"); + ht.put(InitialContext.PROVIDER_URL, "jnp://" + jbossHost + ":" + jbossPort); + ht.put(InitialContext.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); + + try + { + ic = new InitialContext(ht); + if (!doesDestinationExist("topictest.messages", ic)) + { + deployTopic("topictest.messages", ic); + } + if (!doesDestinationExist("topictest.control", ic)) + { + deployTopic("topictest.control", ic); + } + + cf = (ConnectionFactory) ic.lookup("/ConnectionFactory"); + return cf; + } + catch (NamingException e) + { + JMSException jmse = new JMSException("Unable to lookup object: " + e); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; + } + catch (Exception e) + { + JMSException jmse = new JMSException("Error creating topic: " + e); + jmse.setLinkedException(e); + jmse.initCause(e); + throw jmse; + } + } + + private boolean doesDestinationExist(String name, InitialContext ic) throws Exception + { + try + { + ic.lookup("/" + name); + } + catch (NameNotFoundException e) + { + return false; + } + return true; + } + + private void deployTopic(String name, InitialContext ic) throws Exception + { + MBeanServerConnection mBeanServer = lookupMBeanServerProxy(ic); + + ObjectName serverObjectName = new ObjectName("jboss.messaging:service=ServerPeer"); + + String jndiName = "/" + name; + try + { + mBeanServer.invoke(serverObjectName, "createTopic", + new Object[]{name, jndiName}, + new String[]{"java.lang.String", "java.lang.String"}); + } + catch (MBeanException e) + { + System.err.println("Error: " + e); + System.err.println("Cause: " + e.getCause()); + } + } + + private MBeanServerConnection lookupMBeanServerProxy(InitialContext ic) throws NamingException + { + return (MBeanServerConnection) ic.lookup("jmx/invoker/RMIAdaptor"); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java b/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java new file mode 100644 index 0000000000..cb8adae18c --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java @@ -0,0 +1,112 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.flow; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; + +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; + +public class ChannelFlowTest implements MessageListener +{ + private int sent; + private int received; + + ChannelFlowTest(String broker) throws Exception + { + this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "/test")); + } + + ChannelFlowTest(AMQConnection connection) throws Exception + { + this(connection, new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("ChannelFlowTest")), true)); + } + + ChannelFlowTest(AMQConnection connection, AMQDestination destination) throws Exception + { + AMQSession session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE, 50,25); + + //set up a slow consumer + session.createConsumer(destination).setMessageListener(this); + connection.start(); + + //create a publisher + MessageProducer producer = session.createProducer(destination); + Message msg = session.createTextMessage("Message"); + + //publish in bursts that are fast enough to cause channel flow control + for(int i = 0; i < 10; i++) + { + for(int j = 0; j < 100; j++) + { + producer.send(msg); + sent++; + } + waitUntilReceived(sent - 40); + } + + waitUntilReceived(sent); + + session.close(); + connection.close(); + } + + + private synchronized void waitUntilReceived(int count) throws InterruptedException + { + while(received <count) + { + wait(); + } + } + + public synchronized void onMessage(Message message) + { + try + { + Thread.sleep(50); + + received++; + notify(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + new ChannelFlowTest(argv.length == 0 ? "localhost:5672" : argv[0]); + } + +} diff --git a/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargePublisher.java b/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargePublisher.java new file mode 100644 index 0000000000..2fe01fc126 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargePublisher.java @@ -0,0 +1,196 @@ +/* + * + * 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.fragmentation; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.jms.MessageProducer; +import org.apache.qpid.jms.Session; +import org.apache.log4j.Logger; + +import javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A client that behaves as follows: + * <ul><li>Connects to a queue, whose name is specified as a cmd-line argument</li> + * <li>Creates a temporary queue</li> + * <li>Creates messages containing a property that is the name of the temporary queue</li> + * <li>Fires off a message on the original queue and waits for a response on the temporary queue</li> + * </ul> + */ +public class TestLargePublisher +{ + private static final Logger _log = Logger.getLogger(TestLargePublisher.class); + + private AMQConnection _connection; + + private AMQSession _session; + + private class CallbackHandler implements MessageListener + { + private int _expectedMessageCount; + + private int _actualMessageCount; + + private long _startTime; + + public CallbackHandler(int expectedMessageCount, long startTime) + { + _expectedMessageCount = expectedMessageCount; + _startTime = startTime; + } + + public void onMessage(Message m) + { + if (_log.isDebugEnabled()) + { + _log.debug("Message received: " + m); + } + _actualMessageCount++; + if (_actualMessageCount%1000 == 0) + { + _log.info("Received message count: " + _actualMessageCount); + } + /*if (!"henson".equals(m.toString())) + { + _log.error("AbstractJMSMessage response not correct: expected 'henson' but got " + m.toString()); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug("AbstractJMSMessage " + m + " received"); + } + else + { + _log.info("AbstractJMSMessage received"); + } + } */ + + if (_actualMessageCount == _expectedMessageCount) + { + long timeTaken = System.currentTimeMillis() - _startTime; + System.out.println("Total time taken to receive " + _expectedMessageCount+ " messages was " + + timeTaken + "ms, equivalent to " + + (_expectedMessageCount/(timeTaken/1000.0)) + " messages per second"); + } + } + } + + public TestLargePublisher(String host, int port, String clientID, + final int messageCount) throws AMQException,URLSyntaxException + { + try + { + createConnection(host, port, clientID); + + _session = (AMQSession) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic destination = new AMQTopic(_session.getDefaultTopicExchangeName(), new AMQShortString("large")); + MessageProducer producer = (MessageProducer) _session.createProducer(destination); + + _connection.start(); + //TextMessage msg = _session.createTextMessage(tempDestination.getQueueName() + "/Presented to in conjunction with Mahnah Mahnah and the Snowths"); + final long startTime = System.currentTimeMillis(); + + for (int i = 0; i < messageCount; i++) + { + BytesMessage msg = _session.createBytesMessage(); + populateMessage(msg); + producer.send(msg); + } + _log.info("Finished sending " + messageCount + " messages"); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + private void createConnection(String host, int port, String clientID) throws AMQException , URLSyntaxException + { + _connection = new AMQConnection(host, port, "guest", "guest", + clientID, "/test"); + } + + private void populateMessage(BytesMessage msg) throws JMSException + { + int size = 1024 * 187; // 187k + byte[] data = new byte[size]; + for (int i = 0; i < data.length; i++) + { + data[i] = (byte)(i%25); + } + msg.writeBytes(data); + } + + /** + * + * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank + * means the server will allocate a name. + */ + public static void main(String[] args) throws URLSyntaxException + { + final String host; + final int port; + final int numMessages; + if (args.length == 0) + { + host = "localhost"; + port = 5672; + numMessages = 100; +// System.err.println("Usage: TestLargePublisher <host> <port> <number of messages>"); + } + else + { + host = args[0]; + port = Integer.parseInt(args[1]); + numMessages = Integer.parseInt(args[2]); + } + + try + { + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + TestLargePublisher client = new TestLargePublisher(host, port, clientID, numMessages); + } + catch (UnknownHostException e) + { + e.printStackTrace(); + } + catch (AMQException e) + { + System.err.println("Error in client: " + e); + e.printStackTrace(); + } + + //System.exit(0); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargeSubscriber.java b/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargeSubscriber.java new file mode 100644 index 0000000000..b0cde22349 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargeSubscriber.java @@ -0,0 +1,167 @@ +/* + * + * 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.fragmentation; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.jms.Session; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.log4j.Logger; + +import javax.jms.*; +import java.net.InetAddress; + +public class TestLargeSubscriber +{ + private static final Logger _logger = Logger.getLogger(TestLargeSubscriber.class); + + private static MessageProducer _destinationProducer; + + private static String _destinationName; + + public static void main(String[] args) + { + _logger.info("Starting..."); + + final String host; + final int port; + final String username; + final String password; + final String virtualPath; + final int numExpectedMessages; + if (args.length == 0) + { + host = "localhost"; + port = 5672; + username = "guest"; + password = "guest"; + virtualPath = "/test"; + numExpectedMessages = 100; + } + else if (args.length == 6) + { + host = args[0]; + port = Integer.parseInt(args[1]); + username = args[2]; + password = args[3]; + virtualPath = args[4]; + numExpectedMessages = Integer.parseInt(args[5]); + } + else + { + System.out.println("Usage: host port username password virtual-path expectedMessageCount"); + System.exit(1); + throw new RuntimeException("cannot be reached"); + } + + try + { + InetAddress address = InetAddress.getLocalHost(); + AMQConnection con = new AMQConnection(host, port, username, password, + address.getHostName(), virtualPath); + final AMQSession session = (AMQSession) con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + final int expectedMessageCount = numExpectedMessages; + + MessageConsumer consumer = session.createConsumer(new AMQTopic(session.getDefaultTopicExchangeName(), + new AMQShortString("large")), + 100, true, false, null); + + consumer.setMessageListener(new MessageListener() + { + private int _messageCount; + + private long _startTime = 0; + + public void onMessage(Message message) + { + validateMessage(message); + if (_messageCount++ == 0) + { + _startTime = System.currentTimeMillis(); + } + if (_logger.isInfoEnabled()) + { + _logger.info("Got message '" + message + "'"); + } + if (_messageCount == expectedMessageCount) + { + long totalTime = System.currentTimeMillis() - _startTime; + _logger.error("Total time to receive " + _messageCount + " messages was " + + totalTime + "ms. Rate is " + (_messageCount/(totalTime/1000.0))); + } + } + + private void validateMessage(Message message) + { + if (!(message instanceof BytesMessage)) + { + _logger.error("Message is not of correct type - should be BytesMessage and is " + + message.getClass()); + } + BytesMessage bm = (BytesMessage) message; + final int expectedSize = 1024 * 187; // 187k + try + { + if (bm.getBodyLength() != expectedSize) + { + _logger.error("Message is not correct length - should be " + expectedSize + " and is " + + bm.getBodyLength()); + } + } + catch (JMSException e) + { + _logger.error("Failed to validate message: " + e, e); + } + try + { + byte[] data = new byte[(int)bm.getBodyLength()]; + bm.readBytes(data); + for (int i = 0; i < data.length; i++) + { + if (data[i] != (byte)(i%25)) + { + _logger.error("byte " + i + " of message is wrong - should be " + i%25 + " but is " + + data[i]); + } + } + _logger.info("***** Validated message successfully"); + } + catch (JMSException e) + { + _logger.error("Failed to validate message: " + e, e); + } + } + }); + con.start(); + } + catch (Throwable t) + { + System.err.println("Fatal error: " + t); + t.printStackTrace(); + } + + System.out.println("Waiting..."); + } +} + diff --git a/java/client/src/old_test/java/org/apache/qpid/headers/Listener.java b/java/client/src/old_test/java/org/apache/qpid/headers/Listener.java new file mode 100644 index 0000000000..cb5caefc1e --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/headers/Listener.java @@ -0,0 +1,117 @@ +/* + * + * 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.headers; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.jms.Session; +//import org.apache.qpid.testutil.Config; + +import javax.jms.MessageListener; +import javax.jms.Message; +import javax.jms.Destination; +import javax.jms.MessageProducer; +import javax.jms.JMSException; + +public class Listener //implements MessageListener +{ +/* private final AMQConnection _connection; + private final MessageProducer _controller; + private final AMQSession _session; + private final MessageFactory _factory; + private int count; + private long start; + + Listener(AMQConnection connection, Destination exchange) throws Exception + { + _connection = connection; + _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _factory = new MessageFactory(_session, 0, 19); + + //register for events + _factory.createConsumer(exchange).setMessageListener(this); + _connection.start(); + + _controller = _session.createProducer(exchange); + } + + private void shutdown() + { + try + { + _session.close(); + _connection.stop(); + _connection.close(); + } + catch(Exception e) + { + e.printStackTrace(System.out); + } + } + + private void report() + { + try + { + String msg = getReport(); + _controller.send(_factory.createReportResponseMessage(msg)); + System.out.println("Sent report: " + msg); + } + catch(Exception e) + { + e.printStackTrace(System.out); + } + } + + private String getReport() throws JMSException + { + long time = (System.currentTimeMillis() - start); + return "Received " + count + " in " + time + "ms"; + } + + public void onMessage(Message message) + { + if(count == 0) start = System.currentTimeMillis(); + + if(_factory.isShutdown(message)) + { + shutdown(); + } + else if(_factory.isReport(message)) + { + //send a report: + report(); + } + else if (++count % 100 == 0) + { + System.out.println("Received " + count + " messages."); + } + } + + public static void main(String[] argv) throws Exception + { + Config config = new Config(); + config.setType(Config.HEADERS); + config.setName("test_headers_exchange"); + config.setOptions(argv); + new Listener((AMQConnection) config.getConnection(), config.getDestination()); + }*/ +} diff --git a/java/client/src/old_test/java/org/apache/qpid/headers/MessageFactory.java b/java/client/src/old_test/java/org/apache/qpid/headers/MessageFactory.java new file mode 100644 index 0000000000..a2d575fdd4 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/headers/MessageFactory.java @@ -0,0 +1,175 @@ +/* + * + * 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.headers; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; + +import javax.jms.BytesMessage; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.TextMessage; + +/** + */ +class MessageFactory +{ + private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray(); + + private final AMQSession _session; + private final byte[] _payload; + + private String[] _headerNames; + + MessageFactory(AMQSession session) + { + this(session, Integer.getInteger("amqj.test.message_size", 256).intValue(), 5); + } + + MessageFactory(AMQSession session, int payloadSize, int headerCount) + { + if (headerCount < 1) + { + throw new IllegalArgumentException("Header count must be positive"); + } + _session = session; + _payload = new byte[payloadSize]; + for (int i = 0; i < _payload.length; i++) + { + _payload[i] = (byte) DATA[i % DATA.length]; + } + _headerNames = new String[headerCount]; + // note that with the standard encoding the headers get prefixed with an S to indicate their type + for (int i = 0; i < _headerNames.length; i++) + { + if (i < 10) + { + _headerNames[i] = "F000" + i; + } + else if (i >= 10 && i < 100) + { + _headerNames[i] = "F00" + i; + } + else + { + _headerNames[i] = "F0" + i; + } + } + } + + Message createEventMessage() throws JMSException + { + BytesMessage msg = _session.createBytesMessage(); + if (_payload.length != 0) + { + msg.writeBytes(_payload); + } + return setHeaders(msg, _headerNames); + } + + Message createShutdownMessage() throws JMSException + { + return setHeaders(_session.createMessage(), new String[]{"F0000", "SHUTDOWN"}); + } + + Message createReportRequestMessage() throws JMSException + { + return setHeaders(_session.createMessage(), new String[]{"F0000", "REPORT"}); + } + + Message createReportResponseMessage(String msg) throws JMSException + { + return setHeaders(_session.createTextMessage(msg), new String[]{"CONTROL", "REPORT"}); + } + + boolean isShutdown(Message m) + { + return checkPresent(m, "SHUTDOWN"); + } + + boolean isReport(Message m) + { + return checkPresent(m, "REPORT"); + } + + Object getReport(Message m) + { + try + { + return ((TextMessage) m).getText(); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + return e.toString(); + } + } + + FieldTable getConsumerBinding() + { + FieldTable binding = FieldTableFactory.newFieldTable(); + binding.setString("SF0000", "value"); + return binding; + } + + FieldTable getControllerBinding() + { + FieldTable binding = FieldTableFactory.newFieldTable(); + binding.setString("SCONTROL", "value"); + return binding; + } + + MessageConsumer createConsumer(Destination source) throws Exception + { + return _session.createConsumer(source, 0, false, true, null, getConsumerBinding()); + } + + MessageConsumer createController(Destination source) throws Exception + { + return _session.createConsumer(source, 0, false, true, null, getControllerBinding()); + } + + private static boolean checkPresent(Message m, String s) + { + try + { + return m.getStringProperty(s) != null; + } + catch (JMSException e) + { + e.printStackTrace(System.out); + return false; + } + } + + private static Message setHeaders(Message m, String[] headers) throws JMSException + { + for (int i = 0; i < headers.length; i++) + { + // the value in GRM is 5 bytes + m.setStringProperty(headers[i], "value"); + } + return m; + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/headers/Publisher.java b/java/client/src/old_test/java/org/apache/qpid/headers/Publisher.java new file mode 100644 index 0000000000..d9ef702c48 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/headers/Publisher.java @@ -0,0 +1,133 @@ +/* + * + * 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.headers; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +//import org.apache.qpid.testutil.Config; + +import javax.jms.*; + +public class Publisher // implements MessageListener +{ +/* private final Object _lock = new Object(); + private final AMQConnection _connection; + private final AMQSession _session; + private final Destination _exchange; + private final MessageFactory _factory; + private final MessageProducer _publisher; + private int _count; + + Publisher(AMQConnection connection, Destination exchange) throws Exception + { + _connection = connection; + _exchange = exchange; + _session = (AMQSession) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _factory = new MessageFactory(_session, 0, 19); + _publisher = _session.createProducer(_exchange); + } + + Publisher(Config config) throws Exception + { + this((AMQConnection) config.getConnection(), config.getDestination()); + } + + private void test(int msgCount, int consumerCount) throws Exception + { + _count = consumerCount; + _factory.createController(_exchange).setMessageListener(this); + _connection.start(); + long start = System.currentTimeMillis(); + publish(msgCount); + waitForCompletion(consumerCount); + long end = System.currentTimeMillis(); + + System.out.println("Completed in " + (end - start) + " ms."); + + //request shutdown + _publisher.send(_factory.createShutdownMessage()); + + _connection.stop(); + _connection.close(); + } + + private void publish(int count) throws Exception + { + + //send events + for (int i = 0; i < count; i++) + { + _publisher.send(_factory.createEventMessage()); + if ((i + 1) % 100 == 0) + { + System.out.println("Sent " + (i + 1) + " messages"); + } + } + + //request report + _publisher.send(_factory.createReportRequestMessage()); + } + + private void waitForCompletion(int consumers) throws Exception + { + System.out.println("Waiting for completion..."); + synchronized (_lock) + { + while (_count > 0) + { + _lock.wait(); + } + } + } + + + public void onMessage(Message message) + { + System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining"); + if (_count == 0) + { + synchronized (_lock) + { + _lock.notify(); + } + } + } + + + public static void main(String[] argv) throws Exception + { + if (argv.length >= 2) + { + int msgCount = Integer.parseInt(argv[argv.length - 2]); + int consumerCount = Integer.parseInt(argv[argv.length - 1]); + + Config config = new Config(); + config.setType(Config.HEADERS); + config.setName("test_headers_exchange"); + String[] options = new String[argv.length - 2]; + System.arraycopy(argv, 0, options, 0, options.length); + config.setOptions(options); + + new Publisher(config).test(msgCount, consumerCount); + } + + }*/ +} diff --git a/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Bind.java b/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Bind.java new file mode 100644 index 0000000000..ee6a12c233 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Bind.java @@ -0,0 +1,273 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.jndi.referenceable; + +import org.apache.qpid.client.*; +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; + +import javax.jms.*; +import javax.naming.*; + +import java.util.Properties; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.IOException; + +/** + * Binds a reference from a JNDI source. + * Given a properties file with the JNDI information and a binding string. + */ +public class Bind +{ + private static final String USAGE="USAGE: java bind <JNDI Properties file> -cf <url> <binding> | -c <url> <binding> [-t <topic Name> <binding>] [-q <queue Name> <binding>]"; + public Bind(String propertiesFile, String bindingURL, Referenceable reference) throws NameAlreadyBoundException, NoInitialContextException + { + // Set up the environment for creating the initial context + String qpid_home = System.getProperty("QPID_HOME"); + + if (qpid_home == null || qpid_home.equals("")) + { + System.out.println("QPID_HOME is not set"); + System.exit(1); + } + + if (qpid_home.charAt(qpid_home.length() - 1) != '/') + { + qpid_home += "/"; + } + + try + { + InputStream inputStream = new FileInputStream(qpid_home + propertiesFile); + Properties properties = new Properties(); + properties.load(inputStream); + + // Create the initial context + Context ctx = new InitialContext(properties); + + // Perform the binds + ctx.bind(bindingURL, reference); + + // Close the context when we're done + ctx.close(); + } + catch (IOException ioe) + { + System.out.println("Unable to access properties file:" + propertiesFile + " Due to:" + ioe); + } + catch (NamingException e) + { + System.out.println("Operation failed: " + e); + if (e instanceof NameAlreadyBoundException) + { + throw (NameAlreadyBoundException) e; + } + + if (e instanceof NoInitialContextException) + { + throw (NoInitialContextException) e; + } + } + + } + + private static String parse(String[] args, int index, String what, String type) + { + try + { + return args[index]; + } + catch (IndexOutOfBoundsException ioobe) + { + System.out.println("ERROR: No " + what + " specified for " + type + "."); + System.out.println(USAGE); + System.exit(1); + } + + // The path is either return normally or exception.. which calls system exit so keep the compiler happy + return "Never going to happen"; + } + + + public static void main(String[] args) throws NameAlreadyBoundException, NoInitialContextException, URLSyntaxException, AMQException, JMSException + { + + + org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.OFF); + +// org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(AMQConnection.class); +// _logger.setLevel(org.apache.log4j.Level.OFF); + + boolean exit = false; + + String qpid_home = System.getProperty("QPID_HOME"); + + if (qpid_home == null || qpid_home.equals("")) + { + System.out.println("QPID_HOME is not set"); + exit = true; + } + + if (args.length <= 2) + { + System.out.println("At least a connection or connection factory must be requested to be bound."); + exit = true; + } + else + { + if ((args.length - 1) % 3 != 0) + { + System.out.println("Not all values have full details"); + exit = true; + } + } + if (exit) + { + System.out.println(USAGE); + System.exit(1); + } + + if (qpid_home.charAt(qpid_home.length() - 1) != '/') + + { + qpid_home += "/"; + } + + AMQConnectionFactory cf = null; + AMQConnection c = null; + AMQSession session = null; + Referenceable reference = null; + + for (int index = 1; index < args.length; index ++) + { + String obj = args[index]; + + String what = "Invalid"; + String binding; + + if (obj.startsWith("-c")) + { + boolean isFactory = obj.contains("f"); + + + if (isFactory) + { + what = "ConnectionFactory"; + } + else + { + what = "Factory"; + } + + String url = parse(args, ++index, "url", what); + + if (isFactory) + { + + cf = new AMQConnectionFactory(url); + reference = cf; + } + else + { + c = new AMQConnection(url); + reference = c; + } + + } + + if (obj.equals("-t") || obj.equals("-q")) + { + if (c == null) + { + c = (AMQConnection) cf.createConnection(); + } + + if (session == null) + { + session = (AMQSession) c.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + } + + if (obj.equals("-t")) + { + + String topicName = parse(args, ++index, "Topic Name", "Topic"); + reference = (AMQTopic) session.createTopic(topicName); + what = "Topic"; + } + else + { + if (obj.equals("-q")) + { + String topicName = parse(args, ++index, "Queue Name", "Queue"); + reference = (AMQQueue) session.createQueue(topicName); + what = "Queue"; + } + } + + binding = parse(args, ++index, "binding", what); + if (binding == null) + { + System.out.println(obj + " is not a known Object to bind."); + System.exit(1); + } + else + { + System.out.print("Binding:" + reference + " to " + binding); + try + { + new Bind(args[0], binding, reference); + System.out.println(" ..Successful"); + + } + catch (NameAlreadyBoundException nabe) + { + System.out.println(""); + if (!obj.startsWith("-c") || index == args.length - 1) + { + throw nabe; + } + else + { + System.out.println("Continuing with other bindings using the same connection details"); + } + } + finally + { + if (!obj.startsWith("-c") || index == args.length - 1) + { + if (c != null) + { + c.close(); + } + } + } + } + } + + if (c != null) + { + c.close(); + } + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Lookup.java b/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Lookup.java new file mode 100644 index 0000000000..1c9d8b0fd5 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Lookup.java @@ -0,0 +1,196 @@ +/* + * + * 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.jndi.referenceable; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * Looksup a reference from a JNDI source. + * Given a properties file with the JNDI information and a binding string. + */ +public class Lookup +{ + private static final String USAGE = "USAGE: java lookup <JNDI Properties file> -b <binding>"; + private Properties _properties; + private Object _object; + + public Lookup(String propertiesFile, String bindingValue) throws NamingException + { + // Set up the environment for creating the initial context + String qpid_home = System.getProperty("QPID_HOME"); + + if (qpid_home == null || qpid_home.equals("")) + { + System.out.println("QPID_HOME is not set"); + System.exit(1); + } + + if (qpid_home.charAt(qpid_home.length() - 1) != '/') + { + qpid_home += "/"; + } + + try + { + InputStream inputStream = new FileInputStream(qpid_home + propertiesFile); + Properties properties = new Properties(); + properties.load(inputStream); + + _properties = properties; + lookup(bindingValue); + } + catch (IOException ioe) + { + System.out.println("Unable to access properties file:" + propertiesFile + " Due to:" + ioe); + } + } + + public Object lookup(String bindingValue) throws NamingException + { + + // Create the initial context + Context ctx = new InitialContext(_properties); + + // Perform the binds + _object = ctx.lookup(bindingValue); + + // Close the context when we're done + ctx.close(); + + return getObject(); + } + + public Object getObject() + { + return _object; + } + + private static String parse(String[] args, int index, String what) + { + try + { + return args[index]; + } + catch (IndexOutOfBoundsException ioobe) + { + System.out.println("ERROR: No " + what + " specified."); + System.out.println(USAGE); + System.exit(1); + } + + // The path is either return normally or exception.. which calls system exit so keep the compiler happy + return "Never going to happen"; + } + + + public static void main(String[] args) throws NamingException + { + boolean exit = false; + + String qpid_home = System.getProperty("QPID_HOME"); + + if (qpid_home == null || qpid_home.equals("")) + { + System.out.println("QPID_HOME is not set"); + exit = true; + } + + if (args.length <= 2) + { + System.out.println("At least a connection or connection factory must be requested to be bound."); + exit = true; + } + else + { + if ((args.length - 1) % 2 != 0) + { + System.out.println("Not all values have full details"); + exit = true; + } + } + if (exit) + { + System.out.println(USAGE); + System.exit(1); + } + + if (qpid_home.charAt(qpid_home.length() - 1) != '/') + + { + qpid_home += "/"; + } + + for (int index = 1; index < args.length; index ++) + { + String obj = args[index]; + + + if (obj.equals("-b")) + { + String binding = parse(args, ++index, "binding"); + + if (binding == null) + { + System.out.println("Binding not specified."); + System.exit(1); + } + else + { + System.out.print("Looking up:" + binding); + try + { + Lookup l = new Lookup(args[0], binding); + + Object object = l.getObject(); + + if (object instanceof Connection) + { + try + { + ((Connection) object).close(); + } + catch (JMSException jmse) + { + ; + } + } + } + catch (NamingException nabe) + { + System.out.println("Problem unbinding " + binding + " continuing with other values."); + } + } + }// if -b + else + { + System.out.println("Continuing with other bindings option not known:" + obj); + } + }//for + }//main +}//class diff --git a/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Unbind.java b/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Unbind.java new file mode 100644 index 0000000000..1acead674c --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Unbind.java @@ -0,0 +1,166 @@ +/* + * + * 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.jndi.referenceable; + +import javax.naming.*; + +import java.util.Properties; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.IOException; + +/** + * Unbinds a reference from a JNDI source. + * Given a properties file with the JNDI information and a binding string. + */ +public class Unbind +{ + private static final String USAGE = "USAGE: java unbind <JNDI Properties file> -b <binding>"; + + public Unbind(String propertiesFile, String bindingValue) throws NamingException + { + // Set up the environment for creating the initial context + String qpid_home = System.getProperty("QPID_HOME"); + + if (qpid_home == null || qpid_home.equals("")) + { + System.out.println("QPID_HOME is not set"); + System.exit(1); + } + + if (qpid_home.charAt(qpid_home.length() - 1) != '/') + { + qpid_home += "/"; + } + + try + { + InputStream inputStream = new FileInputStream(qpid_home + propertiesFile); + Properties properties = new Properties(); + properties.load(inputStream); + + // Create the initial context + Context ctx = new InitialContext(properties); + + // Perform the binds + ctx.unbind(bindingValue); + + // Close the context when we're done + ctx.close(); + } + catch (IOException ioe) + { + System.out.println("Unable to access properties file:" + propertiesFile + " Due to:" + ioe); + } + } + + private static String parse(String[] args, int index, String what) + { + try + { + return args[index]; + } + catch (IndexOutOfBoundsException ioobe) + { + System.out.println("ERROR: No " + what + " specified."); + System.out.println(USAGE); + System.exit(1); + } + + // The path is either return normally or exception.. which calls system exit so keep the compiler happy + return "Never going to happen"; + } + + + public static void main(String[] args) throws NamingException + { + boolean exit = false; + + String qpid_home = System.getProperty("QPID_HOME"); + + if (qpid_home == null || qpid_home.equals("")) + { + System.out.println("QPID_HOME is not set"); + exit = true; + } + + if (args.length <= 2) + { + System.out.println("At least a connection or connection factory must be requested to be bound."); + exit = true; + } + else + { + if ((args.length - 1) % 2 != 0) + { + System.out.println("Not all values have full details"); + exit = true; + } + } + if (exit) + { + System.out.println(USAGE); + System.exit(1); + } + + if (qpid_home.charAt(qpid_home.length() - 1) != '/') + + { + qpid_home += "/"; + } + + for (int index = 1; index < args.length; index ++) + { + String obj = args[index]; + + + if (obj.equals("-b")) + { + String binding = parse(args, ++index, "binding"); + + if (binding == null) + { + System.out.println("Binding not specified."); + System.exit(1); + } + else + { + System.out.print("UnBinding:" + binding); + try + { + new Unbind(args[0], binding); + System.out.println(" ..Successful"); + } + catch (NamingException nabe) + { + System.out.println(""); + + System.out.println("Problem unbinding " + binding + " continuing with other values."); + } + } + }// if -b + else + { + System.out.println("Continuing with other bindings option not known:" + obj); + } + }//for + }//main +}//class diff --git a/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java b/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java new file mode 100644 index 0000000000..4865a68dc4 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java @@ -0,0 +1,153 @@ +/* + * + * 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.latency; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; + +import javax.jms.MessageProducer; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.JMSException; +import javax.jms.TextMessage; +import javax.jms.BytesMessage; + +public class LatencyTest implements MessageListener +{ + private volatile boolean waiting; + private int sent; + private int received; + + private final byte[] data; + + private long min = Long.MAX_VALUE; + private long max = 0; + private long total = 0; + + LatencyTest(String broker, int count, int delay, int length) throws Exception + { + this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "/test"), count, delay, length); + } + + LatencyTest(AMQConnection connection, int count, int delay, int length) throws Exception + { + this(connection, new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("LatencyTest")), true), count, delay, length); + } + + LatencyTest(AMQConnection connection, AMQDestination destination, int count, int delay, int length) throws Exception + { + AMQSession session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + + data = new byte[length]; + for(int i = 0; i < data.length; i++) + { + data[i] = (byte) (i % 100); + } + + //set up a consumer + session.createConsumer(destination).setMessageListener(this); + connection.start(); + + //create a publisher + MessageProducer producer = session.createProducer(destination, false, false, true); + + //publish at a low volume + for(int i = 0; i < count; i++) + { + BytesMessage msg = session.createBytesMessage(); + msg.writeBytes(data); + msg.setStringProperty("sent-at", Long.toString(System.nanoTime())); + producer.send(msg); + Thread.sleep(delay); + if(++sent % 100 == 0) + { + System.out.println("Sent " + sent + " of " + count); + } + } + + waitUntilReceived(sent); + + session.close(); + connection.close(); + + System.out.println("Latency (in nanoseconds): avg=" + (total/sent) + ", min=" + min + ", max=" + max + + ", avg(discarding min and max)=" + ((total - min - max) / (sent - 2))); + } + + + private synchronized void waitUntilReceived(int count) throws InterruptedException + { + waiting = true; + while(received < count) + { + wait(); + } + waiting = false; + } + + public void onMessage(Message message) + { + received++; + try + { + long sent = Long.parseLong(message.getStringProperty("sent-at")); + long time = System.nanoTime() - sent; + total += time; + min = Math.min(min, time); + max = Math.max(max, time); + } + catch (JMSException e) + { + e.printStackTrace(); + } + + if(waiting){ + synchronized(this) + { + notify(); + } + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + String host = argv.length > 0 ? argv[0] : "localhost:5672"; + if("-help".equals(host)) + { + System.out.println("Usage: <broker> <message count> <delay between messages> <message size>"); + } + int count = argv.length > 1 ? Integer.parseInt(argv[1]) : 1000; + int delay = argv.length > 2 ? Integer.parseInt(argv[2]) : 1000; + int size = argv.length > 3 ? Integer.parseInt(argv[3]) : 512; + new LatencyTest(host, count, delay, size); + } + + +} diff --git a/java/client/src/old_test/java/org/apache/qpid/mina/AcceptorTest.java b/java/client/src/old_test/java/org/apache/qpid/mina/AcceptorTest.java new file mode 100644 index 0000000000..f0ac0e6902 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/mina/AcceptorTest.java @@ -0,0 +1,102 @@ +/* + * + * 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.mina; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoAcceptor; +import org.apache.mina.common.IoHandlerAdapter; +import org.apache.mina.common.IoSession; +import org.apache.mina.transport.socket.nio.SocketAcceptor; +import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; +import org.apache.mina.transport.socket.nio.SocketSessionConfig; +import org.apache.qpid.pool.ReadWriteThreadModel; + +import java.io.IOException; +import java.net.InetSocketAddress; + +import junit.framework.TestCase; + +/** + * Tests MINA socket performance. This acceptor simply reads data from the network and writes it back again. + * + */ +public class AcceptorTest extends TestCase +{ + private static final Logger _logger = Logger.getLogger(AcceptorTest.class); + + public static int PORT = 9999; + + private static class TestHandler extends IoHandlerAdapter + { + private int _sentCount; + + private int _bytesSent; + + public void messageReceived(IoSession session, Object message) throws Exception + { + ((ByteBuffer) message).acquire(); + session.write(message); + _logger.debug("Sent response " + ++_sentCount); + _bytesSent += ((ByteBuffer)message).remaining(); + _logger.debug("Bytes sent: " + _bytesSent); + } + + public void messageSent(IoSession session, Object message) throws Exception + { + //((ByteBuffer) message).release(); + } + + public void exceptionCaught(IoSession session, Throwable cause) throws Exception + { + _logger.error("Error: " + cause, cause); + } + } + + public void testStartAcceptor() throws IOException + { + IoAcceptor acceptor = null; + acceptor = new SocketAcceptor(); + + SocketAcceptorConfig config = (SocketAcceptorConfig) acceptor.getDefaultConfig(); + SocketSessionConfig sc = (SocketSessionConfig) config.getSessionConfig(); + sc.setTcpNoDelay(true); + sc.setSendBufferSize(32768); + sc.setReceiveBufferSize(32768); + + config.setThreadModel(ReadWriteThreadModel.getInstance()); + + acceptor.bind(new InetSocketAddress(PORT), + new TestHandler()); + _logger.info("Bound on port " + PORT); + } + + public static void main(String[] args) throws IOException + { + AcceptorTest a = new AcceptorTest(); + a.testStartAcceptor(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(AcceptorTest.class); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/mina/BlockingAcceptorTest.java b/java/client/src/old_test/java/org/apache/qpid/mina/BlockingAcceptorTest.java new file mode 100644 index 0000000000..bfe29c47e6 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/mina/BlockingAcceptorTest.java @@ -0,0 +1,93 @@ +/* + * + * 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.mina; + +import org.apache.log4j.Logger; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; + +import junit.framework.TestCase; + +public class BlockingAcceptorTest extends TestCase +{ + private static final Logger _logger = Logger.getLogger(BlockingAcceptorTest.class); + + public static int PORT = 9999; + + public void testStartAcceptor() throws IOException + { + + ServerSocket sock = new ServerSocket(PORT); + + sock.setReuseAddress(true); + sock.setReceiveBufferSize(32768); + _logger.info("Bound on port " + PORT); + + while (true) + { + final Socket s = sock.accept(); + _logger.info("Received connection from " + s.getRemoteSocketAddress()); + s.setReceiveBufferSize(32768); + s.setSendBufferSize(32768); + s.setTcpNoDelay(true); + new Thread(new Runnable() + { + public void run() + { + byte[] chunk = new byte[32768]; + try + { + InputStream is = s.getInputStream(); + OutputStream os = s.getOutputStream(); + + while (true) + { + int count = is.read(chunk, 0, chunk.length); + if (count > 0) + { + os.write(chunk, 0, count); + } + } + } + catch (IOException e) + { + _logger.error("Error - closing connection: " + e, e); + } + } + }, "SocketReaderWriter").start(); + } + } + + public static void main(String[] args) throws IOException + { + BlockingAcceptorTest a = new BlockingAcceptorTest(); + a.testStartAcceptor(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(AcceptorTest.class); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/mina/WriterTest.java b/java/client/src/old_test/java/org/apache/qpid/mina/WriterTest.java new file mode 100644 index 0000000000..910345624f --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/mina/WriterTest.java @@ -0,0 +1,271 @@ +/* + * + * 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.mina; + +import org.apache.log4j.Logger; +import org.apache.mina.common.*; +import org.apache.mina.transport.socket.nio.SocketConnector; +import org.apache.mina.transport.socket.nio.SocketConnectorConfig; +import org.apache.mina.transport.socket.nio.SocketSessionConfig; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.concurrent.CountDownLatch; + +import junit.framework.TestCase; + +public class WriterTest extends TestCase +{ + private static final Logger _logger = Logger.getLogger(WriterTest.class); + + private static class RunnableWriterTest implements Runnable + { + private Logger _logger; + + private IoSession _session; + + private long _startTime; + + private long[] _chunkTimes; + + private int _chunkCount = 500000; + + private int _chunkSize = 1024; + + private CountDownLatch _notifier; + + public RunnableWriterTest(Logger logger) + { + _logger = logger; + } + + public void run() + { + _startTime = System.currentTimeMillis(); + _notifier = new CountDownLatch(1); + for (int i = 0; i < _chunkCount; i++) + { + ByteBuffer buf = ByteBuffer.allocate(_chunkSize, false); + byte check = (byte) (i % 128); + buf.put(check); + buf.fill((byte)88, buf.remaining()); + buf.flip(); + _session.write(buf); + } + + try + { + _logger.info("All buffers sent; waiting for receipt from server"); + _notifier.await(); + } + catch (InterruptedException e) + { + } + _logger.info("Completed"); + long totalTime = System.currentTimeMillis() - _startTime; + _logger.info("Total time: " + totalTime); + _logger.info("MB per second: " + (_chunkSize * _chunkCount)/totalTime); + long lastChunkTime = _startTime; + double average = 0; + for (int i = 0; i < _chunkTimes.length; i++) + { + if (i == 0) + { + average = _chunkTimes[i] - _startTime; + } + else + { + long delta = _chunkTimes[i] - lastChunkTime; + if (delta != 0) + { + average = (average + delta)/2; + } + } + lastChunkTime = _chunkTimes[i]; + } + _logger.info("Average chunk time: " + average + "ms"); + CloseFuture cf = _session.close(); + cf.join(); + } + + private class WriterHandler extends IoHandlerAdapter + { + private int _chunksReceived = 0; + + private int _partialBytesRead = 0; + + private byte _partialCheckNumber; + + private int _totalBytesReceived = 0; + + public void messageReceived(IoSession session, Object message) throws Exception + { + ByteBuffer result = (ByteBuffer) message; + _totalBytesReceived += result.remaining(); + int size = result.remaining(); + long now = System.currentTimeMillis(); + if (_partialBytesRead > 0) + { + int offset = _chunkSize - _partialBytesRead; + if (size >= offset) + { + _chunkTimes[_chunksReceived++] = now; + result.position(offset); + } + else + { + // have not read even one chunk, including the previous partial bytes + _partialBytesRead += size; + return; + } + } + + int chunkCount = result.remaining()/_chunkSize; + + for (int i = 0; i < chunkCount; i++) + { + _chunkTimes[_chunksReceived++] = now; + byte check = result.get(); + _logger.debug("Check number " + check + " read"); + if (check != (byte)((_chunksReceived - 1)%128)) + { + _logger.error("Check number " + check + " read when expected " + (_chunksReceived%128)); + } + _logger.debug("Chunk times recorded"); + + try + { + result.skip(_chunkSize - 1); + } + catch (IllegalArgumentException e) + { + _logger.error("Position was: " + result.position()); + _logger.error("Tried to skip to: " + (_chunkSize * i)); + _logger.error("limit was; " + result.limit()); + } + } + _logger.debug("Chunks received now " + _chunksReceived); + _logger.debug("Bytes received: " + _totalBytesReceived); + _partialBytesRead = result.remaining(); + + if (_partialBytesRead > 0) + { + _partialCheckNumber = result.get(); + } + + if (_chunksReceived >= _chunkCount) + { + _notifier.countDown(); + } + + } + + public void exceptionCaught(IoSession session, Throwable cause) throws Exception + { + _logger.error("Error: " + cause, cause); + } + } + + public void startWriter(int chunkSize) throws IOException, InterruptedException + { + _chunkSize = chunkSize; + + IoConnector ioConnector = null; + + ioConnector = new SocketConnector(); + + SocketConnectorConfig cfg = (SocketConnectorConfig) ioConnector.getDefaultConfig(); + cfg.setThreadModel(ThreadModel.MANUAL); + SocketSessionConfig scfg = (SocketSessionConfig) cfg.getSessionConfig(); + scfg.setTcpNoDelay(true); + scfg.setSendBufferSize(32768); + scfg.setReceiveBufferSize(32768); + + final InetSocketAddress address = new InetSocketAddress("localhost", AcceptorTest.PORT); + _logger.info("Attempting connection to " + address); + ConnectFuture future = ioConnector.connect(address, new WriterHandler()); + // wait for connection to complete + future.join(); + _logger.info("Connection completed"); + // we call getSession which throws an IOException if there has been an error connecting + _session = future.getSession(); + _chunkTimes = new long[_chunkCount]; + Thread t = new Thread(this); + t.start(); + t.join(); + _logger.info("Test completed"); + } + } + + private RunnableWriterTest _runnableWriterTest = new RunnableWriterTest(_logger); + + public void test1k() throws IOException, InterruptedException + { + _logger.info("Starting 1k test"); + _runnableWriterTest.startWriter(1024); + } + + public void test2k() throws IOException, InterruptedException + { + _logger.info("Starting 2k test"); + _runnableWriterTest.startWriter(2048); + } + + public void test4k() throws IOException, InterruptedException + { + _logger.info("Starting 4k test"); + _runnableWriterTest.startWriter(4096); + } + + public void test8k() throws IOException, InterruptedException + { + _logger.info("Starting 8k test"); + _runnableWriterTest.startWriter(8192); + } + + public void test16k() throws IOException, InterruptedException + { + _logger.info("Starting 16k test"); + _runnableWriterTest.startWriter(16384); + } + + public void test32k() throws IOException, InterruptedException + { + _logger.info("Starting 32k test"); + _runnableWriterTest.startWriter(32768); + } + + public static void main(String[] args) throws IOException, InterruptedException + { + WriterTest w = new WriterTest(); + //w.test1k(); + //w.test2k(); + //w.test4k(); + w.test8k(); + //w.test16k(); + //w.test32k(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(WriterTest.class); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/multiconsumer/AMQTest.java b/java/client/src/old_test/java/org/apache/qpid/multiconsumer/AMQTest.java new file mode 100644 index 0000000000..db02b9954a --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/multiconsumer/AMQTest.java @@ -0,0 +1,269 @@ +/* + * + * 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.multiconsumer; + +import java.io.ByteArrayOutputStream; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import junit.framework.TestCase; + +import org.apache.commons.codec.binary.Base64; +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.Session; + +/** + * Test AMQ. + */ +public class AMQTest extends TestCase implements ExceptionListener +{ + + private final static String COMPRESSION_PROPNAME = "_MSGAPI_COMP"; + private final static String UTF8 = "UTF-8"; + private static final String SUBJECT = "test.amq"; + private static final String DUMMYCONTENT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private static final String HUGECONTENT; + + private AMQConnection connect = null; + private Session pubSession = null; + private Session subSession = null; + private Topic topic = null; + + static + { + StringBuilder sb = new StringBuilder(DUMMYCONTENT.length() * 115); + for (int i = 0; i < 100; i++) + { + sb.append(DUMMYCONTENT); + } + HUGECONTENT = sb.toString(); + } + + private void setup() throws Exception + { + connect = new AMQConnection("localhost", 5672, "guest", "guest", "client1", "/"); + connect.setExceptionListener(this); + pubSession = connect.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + subSession = connect.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + topic = new AMQTopic(pubSession.getDefaultTopicExchangeName(), new AMQShortString(SUBJECT)); + + connect.start(); + } + + public void testMultipleListeners() throws Exception + { + setup(); + try + { + // Create 5 listeners + MsgHandler[] listeners = new MsgHandler[5]; + for (int i = 0; i < listeners.length; i++) + { + listeners[i] = new MsgHandler(); + MessageConsumer subscriber = subSession.createConsumer(topic); + subscriber.setMessageListener(listeners[i]); + } + MessageProducer publisher = pubSession.createProducer(topic); + // Send a single message + TextMessage msg = pubSession.createTextMessage(); + msg.setText(DUMMYCONTENT); + publisher.send(msg); + Thread.sleep(5000); + // Check listeners to ensure they all got it + for (int i = 0; i < listeners.length; i++) + { + if (listeners[i].isGotIt()) + { + System.out.println("Got callback for listener " + i); + } + else + { + TestCase.fail("Listener " + i + " did not get callback"); + } + } + } + catch (Throwable e) + { + System.err.println("Error: " + e); + e.printStackTrace(System.err); + } + finally + { + close(); + } + } + + public void testCompression() throws Exception + { + setup(); + String comp = this.compressString(HUGECONTENT); + try + { + MsgHandler listener = new MsgHandler(); + MessageConsumer subscriber = subSession.createConsumer(topic); + subscriber.setMessageListener(listener); + MessageProducer publisher = pubSession.createProducer(topic); + + // Send a single message + TextMessage msg = pubSession.createTextMessage(); + // Set the compressed text + msg.setText(comp); + msg.setBooleanProperty(COMPRESSION_PROPNAME, true); + publisher.send(msg); + Thread.sleep(1000); + // Check listeners to ensure we got it + if (listener.isGotIt()) + { + System.out.println("Got callback for listener"); + } + else + { + TestCase.fail("Listener did not get callback"); + } + } + finally + { + close(); + } + } + + private void close() throws Exception + { + if (connect != null) + { + connect.close(); + } + } + + private class MsgHandler implements MessageListener + { + private boolean gotIt = false; + + public void onMessage(Message msg) + { + try + { + TextMessage textMessage = (TextMessage) msg; + String string = textMessage.getText(); + if (string != null && string.length() > 0) + { + gotIt = true; + } + if (textMessage.getBooleanProperty(COMPRESSION_PROPNAME)) + { + string = inflateString(string); + } + System.out.println("Got callback of size " + (string==null?0:string.length())); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public boolean isGotIt() + { + return this.gotIt; + } + } + + private String compressString(String string) throws Exception + { + long start = System.currentTimeMillis(); + byte[] input = string.getBytes(); + Deflater compressor = new Deflater(Deflater.BEST_COMPRESSION); + compressor.setInput(input); + compressor.finish(); + + // Get byte array from output of compressor + ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length); + byte[] buf = new byte[1024]; + while (!compressor.finished()) + { + int cnt = compressor.deflate(buf); + baos.write(buf, 0, cnt); + } + baos.close(); + byte[] output = baos.toByteArray(); + + // Convert byte array into String + byte[] base64 = Base64.encodeBase64(output); + String sComp = new String(base64, UTF8); + + long diff = System.currentTimeMillis() - start; + System.out.println("Compressed text from " + input.length + " to " + + sComp.getBytes().length + " in " + diff + " ms"); + System.out.println("Compressed text = '" + sComp + "'"); + + return sComp; + } + + private String inflateString(String string) throws Exception + { + byte[] input = string.getBytes(); + + // First convert Base64 string back to binary array + byte[] bytes = Base64.decodeBase64(input); + + // Set string as input data for decompressor + Inflater decompressor = new Inflater(); + decompressor.setInput(bytes); + + // Decompress the data + ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length); + byte[] buf = new byte[1024]; + while (!decompressor.finished()) + { + int count = decompressor.inflate(buf); + bos.write(buf, 0, count); + } + bos.close(); + byte[] output = bos.toByteArray(); + + // Get the decompressed data + return new String(output, UTF8); + } + + /** + * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) + */ + public void onException(JMSException e) + { + System.err.println(e.getMessage()); + e.printStackTrace(System.err); + } + + +} diff --git a/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestPublisher.java b/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestPublisher.java new file mode 100644 index 0000000000..37b4ff1498 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestPublisher.java @@ -0,0 +1,176 @@ +/* + * + * 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.pubsub1; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.jms.MessageProducer; +import org.apache.qpid.jms.Session; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TextMessage; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A client that behaves as follows: + * <ul><li>Connects to a queue, whose name is specified as a cmd-line argument</li> + * <li>Creates a temporary queue</li> + * <li>Creates messages containing a property that is the name of the temporary queue</li> + * <li>Fires off a message on the original queue and waits for a response on the temporary queue</li> + * </ul> + * + */ +public class TestPublisher +{ + private static final Logger _log = Logger.getLogger(TestPublisher.class); + + private AMQConnection _connection; + + private Session _session; + + private class CallbackHandler implements MessageListener + { + private int _expectedMessageCount; + + private int _actualMessageCount; + + private long _startTime; + + public CallbackHandler(int expectedMessageCount, long startTime) + { + _expectedMessageCount = expectedMessageCount; + _startTime = startTime; + } + + public void onMessage(Message m) + { + if (_log.isDebugEnabled()) + { + _log.debug("Message received: " + m); + } + _actualMessageCount++; + if (_actualMessageCount%1000 == 0) + { + _log.info("Received message count: " + _actualMessageCount); + } + /*if (!"henson".equals(m.toString())) + { + _log.error("AbstractJMSMessage response not correct: expected 'henson' but got " + m.toString()); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug("AbstractJMSMessage " + m + " received"); + } + else + { + _log.info("AbstractJMSMessage received"); + } + } */ + + if (_actualMessageCount == _expectedMessageCount) + { + long timeTaken = System.currentTimeMillis() - _startTime; + System.out.println("Total time taken to receive " + _expectedMessageCount+ " messages was " + + timeTaken + "ms, equivalent to " + + (_expectedMessageCount/(timeTaken/1000.0)) + " messages per second"); + } + } + } + + public TestPublisher(String host, int port, String clientID, String commandQueueName, + final int messageCount) throws AMQException, URLSyntaxException + { + try + { + createConnection(host, port, clientID); + + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic destination = new AMQTopic(_session.getDefaultTopicExchangeName(), new AMQShortString(commandQueueName)); + MessageProducer producer = (MessageProducer) _session.createProducer(destination); + + _connection.start(); + //TextMessage msg = _session.createTextMessage(tempDestination.getQueueName() + "/Presented to in conjunction with Mahnah Mahnah and the Snowths"); + final long startTime = System.currentTimeMillis(); + + for (int i = 0; i < messageCount; i++) + { + TextMessage msg = _session.createTextMessage(destination.getTopicName() + "/Presented to in conjunction with Mahnah Mahnah and the Snowths: " + i); + + //msg.setIntProperty("a",i % 2); + //msg.setIntProperty("b",i % 4); + + producer.send(msg); + } + _log.info("Finished sending " + messageCount + " messages"); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + private void createConnection(String host, int port, String clientID) throws AMQException, URLSyntaxException + { + _connection = new AMQConnection(host, port, "guest", "guest", + clientID, "/test"); + } + + /** + * + * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank + * means the server will allocate a name. + */ + public static void main(String[] args) throws URLSyntaxException + { + if (args.length == 0) + { + System.err.println("Usage: TestPublisher <host> <port> <command queue name> <number of messages>"); + } + try + { + int port = Integer.parseInt(args[1]); + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + TestPublisher client = new TestPublisher(args[0], port, clientID, args[2], Integer.parseInt(args[3])); + } + catch (UnknownHostException e) + { + e.printStackTrace(); + } + catch (AMQException e) + { + System.err.println("Error in client: " + e); + e.printStackTrace(); + } + + //System.exit(0); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestSubscriber.java b/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestSubscriber.java new file mode 100644 index 0000000000..450d9b3914 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestSubscriber.java @@ -0,0 +1,122 @@ +/* + * + * 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.pubsub1; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.jms.Session; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; + +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Topic; +import java.net.InetAddress; + +public class TestSubscriber +{ + private static final Logger _logger = Logger.getLogger(TestSubscriber.class); + + private static class TestMessageListener implements MessageListener + { + private String _name; + + private int _expectedMessageCount; + + private int _messageCount; + + private long _startTime = 0; + + public TestMessageListener(String name, int expectedMessageCount) + { + _name = name; + _expectedMessageCount = expectedMessageCount; + } + + public void onMessage(javax.jms.Message message) + { + if (_messageCount++ == 0) + { + _startTime = System.currentTimeMillis(); + } + if (_logger.isInfoEnabled()) + { + _logger.info(_name + " got message '" + message + "'"); + } + if (_messageCount == _expectedMessageCount) + { + long totalTime = System.currentTimeMillis() - _startTime; + _logger.error(_name + ": Total time to receive " + _messageCount + " messages was " + + totalTime + "ms. Rate is " + (_messageCount/(totalTime/1000.0))); + } + if (_messageCount > _expectedMessageCount) + { + _logger.error("Oops! More messages received than expected (" + _messageCount + ")"); + } + } + } + + public static void main(String[] args) + { + _logger.info("Starting..."); + + if (args.length != 7) + { + System.out.println("Usage: host port username password virtual-path expectedMessageCount selector"); + System.exit(1); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + AMQConnection con1 = new AMQConnection(args[0], Integer.parseInt(args[1]), args[2], args[3], + address.getHostName(), args[4]); + final Session session1 = con1.createSession(false, Session.AUTO_ACKNOWLEDGE); + + AMQConnection con2 = new AMQConnection(args[0], Integer.parseInt(args[1]), args[2], args[3], + address.getHostName(), args[4]); + final Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + String selector = args[6]; + + final int expectedMessageCount = Integer.parseInt(args[5]); + _logger.info("Message selector is <" + selector + ">..."); + + Topic t = new AMQTopic(session1.getDefaultTopicExchangeName(), new AMQShortString("cbr")); + MessageConsumer consumer1 = session1.createConsumer(t, + 100, false, false, selector); + MessageConsumer consumer2 = session2.createConsumer(t, + 100, false, false, selector); + + consumer1.setMessageListener(new TestMessageListener("ML 1", expectedMessageCount)); + consumer2.setMessageListener(new TestMessageListener("ML 2", expectedMessageCount)); + con1.start(); + con2.start(); + } + catch (Throwable t) + { + System.err.println("Fatal error: " + t); + t.printStackTrace(); + } + + System.out.println("Waiting..."); + } +} + diff --git a/java/client/src/old_test/java/org/apache/qpid/test/unit/client/connection/TestManyConnections.java b/java/client/src/old_test/java/org/apache/qpid/test/unit/client/connection/TestManyConnections.java new file mode 100644 index 0000000000..f59b36166a --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/test/unit/client/connection/TestManyConnections.java @@ -0,0 +1,95 @@ +/* + * + * 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.client.connection; + +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.client.AMQConnection; +import org.apache.log4j.Logger; + +import junit.framework.TestCase; + +public class TestManyConnections extends TestCase +{ + private static final Logger _log = Logger.getLogger(TestManyConnections.class); + + private AMQConnection[] _connections; + + private void createConnection(int index, String brokerHosts, String clientID, String username, String password, + String vpath) throws AMQException, URLSyntaxException + { + _connections[index] = new AMQConnection(brokerHosts, username, password, + clientID, vpath); + } + + private void createConnections(int count) throws AMQException, URLSyntaxException + { + _connections = new AMQConnection[count]; + long startTime = System.currentTimeMillis(); + for (int i = 0; i < count; i++) + { + createConnection(i, "vm://:1", "myClient" + i, "guest", "guest", "test"); + } + long endTime = System.currentTimeMillis(); + _log.info("Time to create " + count + " connections: " + (endTime - startTime) + + "ms"); + } + + public void testCreate10Connections() throws AMQException, URLSyntaxException + { + createConnections(10); + } + + public void testCreate50Connections() throws AMQException, URLSyntaxException + { + createConnections(50); + } + + public void testCreate100Connections() throws AMQException, URLSyntaxException + { + createConnections(100); + } + + public void testCreate250Connections() throws AMQException, URLSyntaxException + { + createConnections(250); + } + + public void testCreate500Connections() throws AMQException, URLSyntaxException + { + createConnections(500); + } + + public void testCreate1000Connections() throws AMQException, URLSyntaxException + { + createConnections(1000); + } + + public void testCreate5000Connections() throws AMQException, URLSyntaxException + { + createConnections(5000); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(TestManyConnections.class); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java b/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java new file mode 100644 index 0000000000..5ab5722146 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java @@ -0,0 +1,153 @@ +/* + * + * 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 org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.spi.InitialContextFactory; +import java.util.Properties; +import java.io.InputStream; + + +import junit.framework.TestCase; + +public class PropertiesFileInitialContextFactoryTest extends TestCase +{ + InitialContextFactory contextFactory; + Properties _properties; + Properties _fileProperties; + + protected void setUp() throws Exception + { + super.setUp(); + + //create simple set of hardcoded props + _properties = new Properties(); + _properties.put("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory"); + _properties.put("connectionfactory.local", "amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'"); + _properties.put("queue.MyQueue", "example.MyQueue"); + _properties.put("topic.ibmStocks", "stocks.nyse.ibm"); + _properties.put("destination.direct", "direct://amq.direct//directQueue"); + + //create properties from file as a more realistic test + _fileProperties = new Properties(); + ClassLoader cl = this.getClass().getClassLoader(); + InputStream is = cl.getResourceAsStream("org/apache/qpid/test/unit/jndi/example.properties"); + _fileProperties.load(is); + } + + /** + * Test using hardcoded properties + */ + public void testWithoutFile() + { + Context ctx = null; + + try + { + ctx = new InitialContext(_properties); + } + catch (NamingException ne) + { + fail("Error loading context:" + ne); + } + + checkPropertiesMatch(ctx, "Using hardcoded properties: "); + } + + /** + * Test using properties from example file + */ + public void testWithFile() + { + Context ctx = null; + + try + { + ctx = new InitialContext(_fileProperties); + } + catch (Exception e) + { + fail("Error loading context:" + e); + } + + checkPropertiesMatch(ctx, "Using properties from file: "); + } + + public void tearDown() + { + _properties = null; + _fileProperties = null; + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(PropertiesFileInitialContextFactoryTest.class); + } + + private void checkPropertiesMatch(Context ctx, String errorInfo) + { + try + { + AMQConnectionFactory cf = (AMQConnectionFactory) ctx.lookup("local"); + assertEquals("amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'", cf.getConnectionURL().toString()); + } + catch (NamingException ne) + { + fail(errorInfo + "Unable to create Connection Factory:" + ne); + } + + try + { + AMQQueue queue = (AMQQueue) ctx.lookup("MyQueue"); + assertEquals("example.MyQueue", queue.getRoutingKey().toString()); + } + catch (NamingException ne) + { + fail(errorInfo + "Unable to create queue:" + ne); + } + + try + { + AMQTopic topic = (AMQTopic) ctx.lookup("ibmStocks"); + assertEquals("stocks.nyse.ibm", topic.getTopicName().toString()); + } + catch (Exception ne) + { + fail(errorInfo + "Unable to create topic:" + ne); + } + + try + { + AMQQueue direct = (AMQQueue) ctx.lookup("direct"); + assertEquals("directQueue", direct.getRoutingKey().toString()); + } + catch (NamingException ne) + { + fail(errorInfo + "Unable to create direct destination:" + ne); + } + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/example.properties b/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/example.properties new file mode 100644 index 0000000000..ea9dc5ae0e --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/example.properties @@ -0,0 +1,38 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory + +# use the following property to configure the default connector +#java.naming.provider.url - ignored. + +# register some connection factories +# connectionfactory.[jndiname] = [ConnectionURL] +connectionfactory.local = amqp://guest:guest@clientid/testpath?brokerlist='vm://:1' + +# register some queues in JNDI using the form +# queue.[jndiName] = [physicalName] +queue.MyQueue = example.MyQueue + +# register some topics in JNDI using the form +# topic.[jndiName] = [physicalName] +topic.ibmStocks = stocks.nyse.ibm + +# Register an AMQP destination in JNDI +# NOTE: Qpid currently only supports direct,topics and headers +# destination.[jniName] = [BindingURL] +destination.direct = direct://amq.direct//directQueue diff --git a/java/client/src/old_test/java/org/apache/qpid/topic/Config.java b/java/client/src/old_test/java/org/apache/qpid/topic/Config.java new file mode 100644 index 0000000000..bb740f9094 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/topic/Config.java @@ -0,0 +1,243 @@ +/* + * + * 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.topic; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.config.ConnectorConfig; +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.Connector; +import org.apache.qpid.config.AbstractConfig; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; + +class Config extends AbstractConfig implements ConnectorConfig +{ + + private String host = "localhost"; + private int port = 5672; + private String factory = null; + + private int payload = 256; + private int messages = 1000; + private int clients = 1; + private int batch = 1; + private long delay = 1; + private int warmup; + private int ackMode= AMQSession.NO_ACKNOWLEDGE; + private String clientId; + private String subscriptionId; + private boolean persistent; + + public Config() + { + } + + int getAckMode() + { + return ackMode; + } + + void setPayload(int payload) + { + this.payload = payload; + } + + int getPayload() + { + return payload; + } + + void setClients(int clients) + { + this.clients = clients; + } + + int getClients() + { + return clients; + } + + void setMessages(int messages) + { + this.messages = messages; + } + + int getMessages() + { + return messages; + } + + public String getHost() + { + return host; + } + + public void setHost(String host) + { + this.host = host; + } + + public int getPort() + { + return port; + } + + public String getFactory() + { + return factory; + } + + public void setPort(int port) + { + this.port = port; + } + + int getBatch() + { + return batch; + } + + void setBatch(int batch) + { + this.batch = batch; + } + + int getWarmup() + { + return warmup; + } + + void setWarmup(int warmup) + { + this.warmup = warmup; + } + + public long getDelay() + { + return delay; + } + + public void setDelay(long delay) + { + this.delay = delay; + } + + String getClientId() + { + return clientId; + } + + String getSubscriptionId() + { + return subscriptionId; + } + + boolean usePersistentMessages() + { + return persistent; + } + + public void setOption(String key, String value) + { + if("-host".equalsIgnoreCase(key)) + { + setHost(value); + } + else if("-port".equalsIgnoreCase(key)) + { + try + { + setPort(Integer.parseInt(value)); + } + catch(NumberFormatException e) + { + throw new RuntimeException("Bad port number: " + value); + } + } + else if("-payload".equalsIgnoreCase(key)) + { + setPayload(parseInt("Bad payload size", value)); + } + else if("-messages".equalsIgnoreCase(key)) + { + setMessages(parseInt("Bad message count", value)); + } + else if("-clients".equalsIgnoreCase(key)) + { + setClients(parseInt("Bad client count", value)); + } + else if("-batch".equalsIgnoreCase(key)) + { + setBatch(parseInt("Bad batch count", value)); + } + else if("-delay".equalsIgnoreCase(key)) + { + setDelay(parseLong("Bad batch delay", value)); + } + else if("-warmup".equalsIgnoreCase(key)) + { + setWarmup(parseInt("Bad warmup count", value)); + } + else if("-ack".equalsIgnoreCase(key)) + { + ackMode = parseInt("Bad ack mode", value); + } + else if("-factory".equalsIgnoreCase(key)) + { + factory = value; + } + else if("-clientId".equalsIgnoreCase(key)) + { + clientId = value; + } + else if("-subscriptionId".equalsIgnoreCase(key)) + { + subscriptionId = value; + } + else if("-persistent".equalsIgnoreCase(key)) + { + persistent = "true".equalsIgnoreCase(value); + } + else + { + System.out.println("Ignoring unrecognised option: " + key); + } + } + + static String getAckModeDescription(int ackMode) + { + switch(ackMode) + { + case AMQSession.NO_ACKNOWLEDGE: return "NO_ACKNOWLEDGE"; + case AMQSession.AUTO_ACKNOWLEDGE: return "AUTO_ACKNOWLEDGE"; + case AMQSession.CLIENT_ACKNOWLEDGE: return "CLIENT_ACKNOWLEDGE"; + case AMQSession.DUPS_OK_ACKNOWLEDGE: return "DUPS_OK_ACKNOWELDGE"; + case AMQSession.PRE_ACKNOWLEDGE: return "PRE_ACKNOWLEDGE"; + } + return "AckMode=" + ackMode; + } + + public Connection createConnection() throws Exception + { + return new Connector().createConnection(this); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/topic/Listener.java b/java/client/src/old_test/java/org/apache/qpid/topic/Listener.java new file mode 100644 index 0000000000..47c608cfe4 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/topic/Listener.java @@ -0,0 +1,141 @@ +/* + * + * 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.topic; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +public class Listener implements MessageListener +{ + private final Connection _connection; + private final MessageProducer _controller; + private final javax.jms.Session _session; + private final MessageFactory _factory; + private boolean init; + private int count; + private long start; + + Listener(Connection connection, int ackMode) throws Exception + { + this(connection, ackMode, null); + } + + Listener(Connection connection, int ackMode, String name) throws Exception + { + _connection = connection; + _session = connection.createSession(false, ackMode); + _factory = new MessageFactory(_session); + + //register for events + if(name == null) + { + _factory.createTopicConsumer().setMessageListener(this); + } + else + { + _factory.createDurableTopicConsumer(name).setMessageListener(this); + } + + _connection.start(); + + _controller = _factory.createControlPublisher(); + System.out.println("Waiting for messages " + + Config.getAckModeDescription(ackMode) + + (name == null ? "" : " (subscribed with name " + name + " and client id " + connection.getClientID() + ")") + + "..."); + + } + + private void shutdown() + { + try + { + _session.close(); + _connection.stop(); + _connection.close(); + } + catch(Exception e) + { + e.printStackTrace(System.out); + } + } + + private void report() + { + try + { + String msg = getReport(); + _controller.send(_factory.createReportResponseMessage(msg)); + System.out.println("Sent report: " + msg); + } + catch(Exception e) + { + e.printStackTrace(System.out); + } + } + + private String getReport() + { + long time = (System.currentTimeMillis() - start); + return "Received " + count + " in " + time + "ms"; + } + + public void onMessage(Message message) + { + if(!init) + { + start = System.currentTimeMillis(); + count = 0; + init = true; + } + + if(_factory.isShutdown(message)) + { + shutdown(); + } + else if(_factory.isReport(message)) + { + //send a report: + report(); + init = false; + } + else if (++count % 100 == 0) + { + System.out.println("Received " + count + " messages."); + } + } + + public static void main(String[] argv) throws Exception + { + Config config = new Config(); + config.setOptions(argv); + + Connection con = config.createConnection(); + if(config.getClientId() != null) + { + con.setClientID(config.getClientId()); + } + new Listener(con, config.getAckMode(), config.getSubscriptionId()); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/topic/MessageFactory.java b/java/client/src/old_test/java/org/apache/qpid/topic/MessageFactory.java new file mode 100644 index 0000000000..39d64069d1 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/topic/MessageFactory.java @@ -0,0 +1,155 @@ +/* + * + * 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.topic; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; + +import javax.jms.*; + +/** + */ +class MessageFactory +{ + private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray(); + + private final Session _session; + private final Topic _topic; + private final Topic _control; + private final byte[] _payload; + + + MessageFactory(Session session) throws JMSException + { + this(session, 256); + } + + MessageFactory(Session session, int size) throws JMSException + { + _session = session; + if(session instanceof AMQSession) + { + _topic = new AMQTopic(((AMQSession)session).getDefaultTopicExchangeName(),new AMQShortString("topictest.messages")); + _control = new AMQTopic(((AMQSession)session).getDefaultTopicExchangeName(),new AMQShortString("topictest.control")); + } + else + { + _topic = session.createTopic("topictest.messages"); + _control = session.createTopic("topictest.control"); + } + _payload = new byte[size]; + + for(int i = 0; i < size; i++) + { + _payload[i] = (byte) DATA[i % DATA.length]; + } + } + + Topic getTopic() + { + return _topic; + } + + Message createEventMessage() throws JMSException + { + BytesMessage msg = _session.createBytesMessage(); + msg.writeBytes(_payload); + return msg; + } + + Message createShutdownMessage() throws JMSException + { + return _session.createTextMessage("SHUTDOWN"); + } + + Message createReportRequestMessage() throws JMSException + { + return _session.createTextMessage("REPORT"); + } + + Message createReportResponseMessage(String msg) throws JMSException + { + return _session.createTextMessage(msg); + } + + boolean isShutdown(Message m) + { + return checkText(m, "SHUTDOWN"); + } + + boolean isReport(Message m) + { + return checkText(m, "REPORT"); + } + + Object getReport(Message m) + { + try + { + return ((TextMessage) m).getText(); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + return e.toString(); + } + } + + MessageConsumer createTopicConsumer() throws Exception + { + return _session.createConsumer(_topic); + } + + MessageConsumer createDurableTopicConsumer(String name) throws Exception + { + return _session.createDurableSubscriber(_topic, name); + } + + MessageConsumer createControlConsumer() throws Exception + { + return _session.createConsumer(_control); + } + + MessageProducer createTopicPublisher() throws Exception + { + return _session.createProducer(_topic); + } + + MessageProducer createControlPublisher() throws Exception + { + return _session.createProducer(_control); + } + + private static boolean checkText(Message m, String s) + { + try + { + return m instanceof TextMessage && ((TextMessage) m).getText().equals(s); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + return false; + } + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/topic/Publisher.java b/java/client/src/old_test/java/org/apache/qpid/topic/Publisher.java new file mode 100644 index 0000000000..d788029ee9 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/topic/Publisher.java @@ -0,0 +1,175 @@ +/* + * + * 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.topic; + +import javax.jms.*; + +public class Publisher implements MessageListener +{ + private final Object _lock = new Object(); + private final Connection _connection; + private final Session _session; + private final MessageFactory _factory; + private final MessageProducer _publisher; + private int _count; + + Publisher(Connection connection, int size, int ackMode, boolean persistent) throws Exception + { + _connection = connection; + _session = _connection.createSession(false, ackMode); + _factory = new MessageFactory(_session, size); + _publisher = _factory.createTopicPublisher(); + _publisher.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + System.out.println("Publishing " + (persistent ? "persistent" : "non-persistent") + " messages of " + size + " bytes, " + Config.getAckModeDescription(ackMode) + "."); + } + + private void test(Config config) throws Exception + { + test(config.getBatch(), config.getDelay(), config.getMessages(), config.getClients(), config.getWarmup()); + } + + private void test(int batches, long delay, int msgCount, int consumerCount, int warmup) throws Exception + { + _factory.createControlConsumer().setMessageListener(this); + _connection.start(); + + if(warmup > 0) + { + System.out.println("Runing warmup (" + warmup + " msgs)"); + long time = batch(warmup, consumerCount); + System.out.println("Warmup completed in " + time + "ms"); + } + + long[] times = new long[batches]; + for(int i = 0; i < batches; i++) + { + if(i > 0) Thread.sleep(delay*1000); + times[i] = batch(msgCount, consumerCount); + System.out.println("Batch " + (i+1) + " of " + batches + " completed in " + times[i] + " ms."); + } + + long min = min(times); + long max = max(times); + System.out.println("min: " + min + ", max: " + max + " avg: " + avg(times, min, max)); + + //request shutdown + _publisher.send(_factory.createShutdownMessage()); + + _connection.stop(); + _connection.close(); + } + + private long batch(int msgCount, int consumerCount) throws Exception + { + _count = consumerCount; + long start = System.currentTimeMillis(); + publish(msgCount); + waitForCompletion(consumerCount); + return System.currentTimeMillis() - start; + } + + private void publish(int count) throws Exception + { + + //send events + for (int i = 0; i < count; i++) + { + _publisher.send(_factory.createEventMessage()); + if ((i + 1) % 100 == 0) + { + System.out.println("Sent " + (i + 1) + " messages"); + } + } + + //request report + _publisher.send(_factory.createReportRequestMessage()); + } + + private void waitForCompletion(int consumers) throws Exception + { + System.out.println("Waiting for completion..."); + synchronized (_lock) + { + while (_count > 0) + { + _lock.wait(); + } + } + } + + + public void onMessage(Message message) + { + System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining"); + if (_count == 0) + { + synchronized (_lock) + { + _lock.notify(); + } + } + } + + static long min(long[] times) + { + long min = times.length > 0 ? times[0] : 0; + for(int i = 0; i < times.length; i++) + { + min = Math.min(min, times[i]); + } + return min; + } + + static long max(long[] times) + { + long max = times.length > 0 ? times[0] : 0; + for(int i = 0; i < times.length; i++) + { + max = Math.max(max, times[i]); + } + return max; + } + + static long avg(long[] times, long min, long max) + { + long sum = 0; + for(int i = 0; i < times.length; i++) + { + sum += times[i]; + } + sum -= min; + sum -= max; + + return (sum / (times.length - 2)); + } + + public static void main(String[] argv) throws Exception + { + Config config = new Config(); + config.setOptions(argv); + + Connection con = config.createConnection(); + int size = config.getPayload(); + int ackMode = config.getAckMode(); + boolean persistent = config.usePersistentMessages(); + new Publisher(con, size, ackMode, persistent).test(config); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/transacted/Config.java b/java/client/src/old_test/java/org/apache/qpid/transacted/Config.java new file mode 100644 index 0000000000..bd104e5407 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/transacted/Config.java @@ -0,0 +1,110 @@ +/* + * + * 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.transacted; + +import org.apache.qpid.config.ConnectorConfig; +import org.apache.qpid.config.AbstractConfig; +import org.apache.qpid.config.Connector; + +import javax.jms.Connection; + +class Config extends AbstractConfig implements ConnectorConfig +{ + private String host = "localhost"; + private int port = 5672; + private String factory; + private boolean echo; + private int batch = 100; + private boolean persistent = true; + + Config(String[] argv) + { + setOptions(argv); + } + + Connection createConnection() throws Exception + { + return new Connector().createConnection(this); + } + + public boolean isEchoOn() + { + return echo; + } + + public boolean usePersistentMessages() + { + return persistent; + } + + public int getBatchSize() + { + return batch; + } + + public String getHost() + { + return host; + } + + public int getPort() + { + return port; + } + + public String getFactory() + { + return factory; + } + + public void setOption(String key, String value) + { + if("-host".equalsIgnoreCase(key)) + { + host = value; + } + else if("-port".equalsIgnoreCase(key)) + { + port = parseInt("Bad port number", value); + } + else if("-factory".equalsIgnoreCase(key)) + { + factory = value; + } + else if("-echo".equalsIgnoreCase(key)) + { + echo = "true".equalsIgnoreCase(value); + } + else if("-persistent".equalsIgnoreCase(key)) + { + persistent = "true".equalsIgnoreCase(value); + } + else if("-batch".equalsIgnoreCase(key)) + { + batch = parseInt("Bad batch size", value); + } + else + { + System.out.println("Ignoring nrecognised option " + key); + } + } + +} diff --git a/java/client/src/old_test/java/org/apache/qpid/transacted/Ping.java b/java/client/src/old_test/java/org/apache/qpid/transacted/Ping.java new file mode 100644 index 0000000000..8f15bf089e --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/transacted/Ping.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.transacted; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.client.AMQQueue; + +import javax.jms.Connection; +import javax.jms.JMSException; +import java.util.Arrays; + +public class Ping +{ + public static void main(String[] argv) throws Exception + { + Config config = new Config(argv); + Connection con = config.createConnection(); + con.setClientID("ping"); + new Relay(new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("ping")), new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("pong")), con, + config.isEchoOn(), + config.getBatchSize(), + config.usePersistentMessages()).start(); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/transacted/Pong.java b/java/client/src/old_test/java/org/apache/qpid/transacted/Pong.java new file mode 100644 index 0000000000..f4f4b20d7c --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/transacted/Pong.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.transacted; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.client.AMQQueue; + +import javax.jms.Connection; +import javax.jms.JMSException; + +public class Pong +{ + public static void main(String[] argv) throws Exception + { + Config config = new Config(argv); + Connection con = config.createConnection(); + con.setClientID("pong"); + new Relay(new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("pong")), new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("ping")), con, + config.isEchoOn(), + config.getBatchSize(), + config.usePersistentMessages()).start(); + + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/transacted/Relay.java b/java/client/src/old_test/java/org/apache/qpid/transacted/Relay.java new file mode 100644 index 0000000000..cede95e5f0 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/transacted/Relay.java @@ -0,0 +1,127 @@ +/* + * + * 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.transacted; + +import org.apache.qpid.client.AMQSession; + +import javax.jms.MessageProducer; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Destination; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.TextMessage; +import javax.jms.DeliveryMode; + +class Relay implements Runnable +{ + private final Connection _con; + private final Session _session; + private final MessageConsumer _src; + private final MessageProducer _dest; + private final int _batch; + private final boolean _echo; + private int _counter; + private long start; + private boolean _running; + + Relay(Destination src, Destination dest, Connection con) throws JMSException + { + this(src, dest, con, false, 100, true); + } + + Relay(Destination src, Destination dest, Connection con, boolean echo, int batch, boolean persistent) throws JMSException + { + _echo = echo; + _batch = batch; + _con = con; + _session = con.createSession(true, AMQSession.NO_ACKNOWLEDGE); + _src = _session.createConsumer(src); + _dest = _session.createProducer(dest); + _dest.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + } + + public void run() + { + start = System.currentTimeMillis(); + try{ + while(true) relay(); + } + catch(JMSException e) + { + e.printStackTrace(); + } + try + { + _session.close(); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + void relay() throws JMSException + { + _dest.send(relay(_src.receive())); + _session.commit(); + } + + Message relay(Message in) throws JMSException + { + if(!_running) + { + System.out.println(_con.getClientID() + " started."); + _running = true; + } + if(++_counter % _batch == 0) + { + long time = System.currentTimeMillis() - start; + System.out.println(_batch + " iterations performed in " + time + " ms"); + try + { + Thread.sleep(100); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + start = System.currentTimeMillis(); + } + if(_echo) + { + System.out.println("Received: " + ((TextMessage) in).getText()); + } + return _session.createTextMessage(_con.getClientID() + _counter); + } + + void start() throws InterruptedException, JMSException + { + Thread runner = new Thread(this); + runner.start(); + _con.start(); + System.out.println(_con.getClientID() + " waiting..."); + runner.join(); + _con.close(); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/transacted/Start.java b/java/client/src/old_test/java/org/apache/qpid/transacted/Start.java new file mode 100644 index 0000000000..de718d828a --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/transacted/Start.java @@ -0,0 +1,44 @@ +/* + * + * 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.transacted; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.client.AMQQueue; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Session; + +public class Start +{ + public static void main(String[] argv) throws Exception + { + Connection con = new Config(argv).createConnection(); + AMQQueue ping = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("ping")); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createProducer(ping).send(session.createTextMessage("start")); + session.close(); + con.close(); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceProvider.java b/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceProvider.java new file mode 100644 index 0000000000..71d806b338 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceProvider.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.weblogic; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; + +import javax.jms.*; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.Context; +import java.net.InetAddress; +import java.util.Hashtable; + +public class ServiceProvider +{ + private static final String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory"; + private static final String JMS_FACTORY = "transientJMSConnectionFactory"; + + private static final Logger _logger = Logger.getLogger(ServiceProvider.class); + + private static MessageProducer _destinationProducer; + + private static Queue _destinationQ; + + public static void main(String[] args) + { + _logger.info("Starting..."); + + if (args.length != 2) + { + System.out.println("Usage: <WLS URI> <service queue>"); + System.exit(1); + } + try + { + String url = args[0]; + String receiveQueue = args[1]; + + final InitialContext ctx = getInitialContext(url); + + QueueConnectionFactory qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY); + QueueConnection qcon = qconFactory.createQueueConnection(); + final QueueSession qsession = qcon.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue receiveQ = (Queue) ctx.lookup(receiveQueue); + + _logger.info("Service (queue) name is '" + receiveQ + "'..."); + + String selector = (args.length > 2 && args[2] != null && args[2].length() > 1) ? args[2] : null; + + _logger.info("Message selector is <" + selector + ">..."); + + MessageConsumer consumer = qsession.createConsumer(receiveQ, selector); + + consumer.setMessageListener(new MessageListener() + { + private int _messageCount; + + public void onMessage(javax.jms.Message message) + { + //_logger.info("Got message '" + message + "'"); + + TextMessage tm = (TextMessage) message; + + try + { + Queue responseQueue = (Queue)tm.getJMSReplyTo(); + if (!responseQueue.equals(_destinationQ)) + { + _destinationQ = responseQueue; + _logger.info("Creating destination for " + responseQueue); + + try + { + _destinationProducer = qsession.createProducer(_destinationQ); + _destinationProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + } + catch (JMSException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + _messageCount++; + if (_messageCount % 1000 == 0) + { + _logger.info("Received message total: " + _messageCount); + _logger.info("Sending response to '" + responseQueue + "'"); + } + + String payload = "This is a response: sing together: 'Mahnah mahnah...'" + tm.getText(); + TextMessage msg = qsession.createTextMessage(payload); + if (tm.propertyExists("timeSent")) + { + _logger.info("timeSent property set on message"); + final long timeSent = tm.getLongProperty("timeSent"); + msg.setLongProperty("timeSent", timeSent); + _logger.info("time taken to go from service request to provider is: " + (System.currentTimeMillis() - timeSent)); + } + _destinationProducer.send(msg); + if (_messageCount % 1000 == 0) + { + tm.acknowledge(); + _logger.info("Sent response to '" + responseQueue + "'"); + } + } + catch (JMSException e) + { + _logger.error("Error sending message: " + e, e); + } + } + }); + qcon.start(); + } + catch (Throwable t) + { + System.err.println("Fatal error: " + t); + t.printStackTrace(); + } + + + System.out.println("Waiting..."); + } + + private static InitialContext getInitialContext(String url) throws NamingException + { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY); + env.put(Context.PROVIDER_URL, url); + return new InitialContext(env); + } +} diff --git a/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceRequestingClient.java b/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceRequestingClient.java new file mode 100644 index 0000000000..2f64a1dde5 --- /dev/null +++ b/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceRequestingClient.java @@ -0,0 +1,185 @@ +/* + * + * 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.weblogic; + +import org.apache.log4j.Logger; + +import javax.jms.*; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import java.util.Hashtable; + +/** + * Created by IntelliJ IDEA. + * User: U806869 + * Date: 28-May-2005 + * Time: 21:54:51 + * To change this template use File | Settings | File Templates. + */ +public class ServiceRequestingClient +{ + private static final Logger _log = Logger.getLogger(ServiceRequestingClient.class); + private static final String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory"; + private static final String JMS_FACTORY = "transientJMSConnectionFactory"; + + private static class CallbackHandler implements MessageListener + { + private int _expectedMessageCount; + + private int _actualMessageCount; + + private long _startTime; + + private long _averageLatency; + + public CallbackHandler(int expectedMessageCount, long startTime) + { + _expectedMessageCount = expectedMessageCount; + _startTime = startTime; + } + + public void onMessage(Message m) + { + if (_log.isDebugEnabled()) + { + _log.debug("Message received: " + m); + } + try + { + if (m.propertyExists("timeSent")) + { + long timeSent = m.getLongProperty("timeSent"); + long now = System.currentTimeMillis(); + if (_averageLatency == 0) + { + _averageLatency = now - timeSent; + _log.info("Latency " + _averageLatency); + } + else + { + _log.info("Individual latency: " + (now-timeSent)); + _averageLatency = (_averageLatency + (now - timeSent))/2; + _log.info("Average latency now: " + _averageLatency); + } + } + } + catch (JMSException e) + { + _log.error("Could not calculate latency"); + } + + _actualMessageCount++; + if (_actualMessageCount%1000 == 0) + { + try + { + m.acknowledge(); + } + catch (JMSException e) + { + _log.error("Error acknowledging message"); + } + _log.info("Received message count: " + _actualMessageCount); + } + /*if (!"henson".equals(m.toString())) + { + _log.error("Message response not correct: expected 'henson' but got " + m.toString()); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug("Message " + m + " received"); + } + else + { + _log.info("Message received"); + } + } */ + + if (_actualMessageCount == _expectedMessageCount) + { + long timeTaken = System.currentTimeMillis() - _startTime; + System.out.println("Total time taken to receive " + _expectedMessageCount+ " messages was " + + timeTaken + "ms, equivalent to " + + (_expectedMessageCount/(timeTaken/1000.0)) + " messages per second"); + System.out.println("Average latency is: " + _averageLatency); + } + } + } + + public static void main(String[] args) throws Exception + { + if (args.length != 3) + { + System.out.println("Usage: IXPublisher <WLS URL> <sendQueue> <count> will publish count messages to "); + System.out.println("queue sendQueue and waits for a response on a temp queue"); + System.exit(1); + } + + String url = args[0]; + String sendQueue = args[1]; + int messageCount = Integer.parseInt(args[2]); + + InitialContext ctx = getInitialContext(url); + + QueueConnectionFactory qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY); + QueueConnection qcon = qconFactory.createQueueConnection(); + QueueSession qsession = qcon.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue sendQ = (Queue) ctx.lookup(sendQueue); + Queue receiveQ = qsession.createTemporaryQueue(); + QueueSender qsender = qsession.createSender(sendQ); + qsender.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + _log.debug("Queue sender created for service queue " + sendQ); + + javax.jms.MessageConsumer messageConsumer = (javax.jms.MessageConsumer) qsession.createConsumer(receiveQ); + + //TextMessage msg = _session.createTextMessage(tempDestination.getQueueName() + "/Presented to in conjunction with Mahnah Mahnah and the Snowths"); + final long startTime = System.currentTimeMillis(); + + messageConsumer.setMessageListener(new CallbackHandler(messageCount, startTime)); + qcon.start(); + for (int i = 0; i < messageCount; i++) + { + TextMessage msg = qsession.createTextMessage("/Presented to in conjunction with Mahnah Mahnah and the Snowths:" + i); + msg.setJMSReplyTo(receiveQ); + if (i%1000 == 0) + { + long timeNow = System.currentTimeMillis(); + msg.setLongProperty("timeSent", timeNow); + } + qsender.send(msg); + } + + new Thread("foo").start(); + //qsession.close(); + //qcon.close(); + } + + private static InitialContext getInitialContext(String url) throws NamingException + { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY); + env.put(Context.PROVIDER_URL, url); + return new InitialContext(env); + } +} diff --git a/java/client/src/test/java/org/apache/mina/transport/vmpipe/support/VmPipeIdleStatusChecker.java b/java/client/src/test/java/org/apache/mina/transport/vmpipe/support/VmPipeIdleStatusChecker.java new file mode 100644 index 0000000000..5323ad28bf --- /dev/null +++ b/java/client/src/test/java/org/apache/mina/transport/vmpipe/support/VmPipeIdleStatusChecker.java @@ -0,0 +1,125 @@ +/* + * + * 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.mina.transport.vmpipe.support; + +import org.apache.mina.common.IdleStatus; + +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * This file is a patch to override MINA, because of the IdentityHashMap bug. Workaround to be supplied in MINA 1.0.7. + * This patched file will be removed once upgraded onto a newer MINA. + * + * Dectects idle sessions and fires <tt>sessionIdle</tt> events to them. + * + * @author The Apache Directory Project (mina-dev@directory.apache.org) + */ +public class VmPipeIdleStatusChecker +{ + private static final VmPipeIdleStatusChecker INSTANCE = new VmPipeIdleStatusChecker(); + + public static VmPipeIdleStatusChecker getInstance() + { + return INSTANCE; + } + + private final Map sessions = new HashMap(); // will use as a set + + private final Worker worker = new Worker(); + + private VmPipeIdleStatusChecker() + { + worker.start(); + } + + public void addSession(VmPipeSessionImpl session) + { + synchronized (sessions) + { + sessions.put(session, session); + } + } + + private class Worker extends Thread + { + private Worker() + { + super("VmPipeIdleStatusChecker"); + setDaemon(true); + } + + public void run() + { + for (;;) + { + try + { + Thread.sleep(1000); + } + catch (InterruptedException e) + { } + + long currentTime = System.currentTimeMillis(); + + synchronized (sessions) + { + Iterator it = sessions.keySet().iterator(); + while (it.hasNext()) + { + VmPipeSessionImpl session = (VmPipeSessionImpl) it.next(); + if (!session.isConnected()) + { + it.remove(); + } + else + { + notifyIdleSession(session, currentTime); + } + } + } + } + } + } + + private void notifyIdleSession(VmPipeSessionImpl session, long currentTime) + { + notifyIdleSession0(session, currentTime, session.getIdleTimeInMillis(IdleStatus.BOTH_IDLE), IdleStatus.BOTH_IDLE, + Math.max(session.getLastIoTime(), session.getLastIdleTime(IdleStatus.BOTH_IDLE))); + notifyIdleSession0(session, currentTime, session.getIdleTimeInMillis(IdleStatus.READER_IDLE), IdleStatus.READER_IDLE, + Math.max(session.getLastReadTime(), session.getLastIdleTime(IdleStatus.READER_IDLE))); + notifyIdleSession0(session, currentTime, session.getIdleTimeInMillis(IdleStatus.WRITER_IDLE), IdleStatus.WRITER_IDLE, + Math.max(session.getLastWriteTime(), session.getLastIdleTime(IdleStatus.WRITER_IDLE))); + } + + private void notifyIdleSession0(VmPipeSessionImpl session, long currentTime, long idleTime, IdleStatus status, + long lastIoTime) + { + if ((idleTime > 0) && (lastIoTime != 0) && ((currentTime - lastIoTime) >= idleTime)) + { + session.increaseIdleCount(status); + session.getFilterChain().fireSessionIdle(session, status); + } + } + +} diff --git a/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java b/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java deleted file mode 100644 index 849827216c..0000000000 --- a/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java +++ /dev/null @@ -1,765 +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.client; - -import java.util.ArrayList; -import java.util.List; - -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; - -import junit.framework.TestCase; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.transport.Binary; -import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.Connection.SessionFactory; -import org.apache.qpid.transport.Connection.State; -import org.apache.qpid.transport.ExchangeBound; -import org.apache.qpid.transport.ExchangeBoundResult; -import org.apache.qpid.transport.ExchangeDeclare; -import org.apache.qpid.transport.ExchangeDelete; -import org.apache.qpid.transport.ExchangeQuery; -import org.apache.qpid.transport.ExchangeQueryResult; -import org.apache.qpid.transport.ExecutionErrorCode; -import org.apache.qpid.transport.ExecutionException; -import org.apache.qpid.transport.ExecutionResult; -import org.apache.qpid.transport.ExecutionSync; -import org.apache.qpid.transport.Future; -import org.apache.qpid.transport.MessageCancel; -import org.apache.qpid.transport.MessageFlow; -import org.apache.qpid.transport.MessageRelease; -import org.apache.qpid.transport.MessageSubscribe; -import org.apache.qpid.transport.MessageTransfer; -import org.apache.qpid.transport.Method; -import org.apache.qpid.transport.Option; -import org.apache.qpid.transport.ProtocolEvent; -import org.apache.qpid.transport.QueueDelete; -import org.apache.qpid.transport.QueueQuery; -import org.apache.qpid.transport.QueueQueryResult; -import org.apache.qpid.transport.Sender; -import org.apache.qpid.transport.Session; -import org.apache.qpid.transport.SessionAttach; -import org.apache.qpid.transport.SessionDelegate; -import org.apache.qpid.transport.SessionDetach; -import org.apache.qpid.transport.SessionException; -import org.apache.qpid.transport.SessionRequestTimeout; -import org.apache.qpid.transport.TxCommit; -import org.apache.qpid.transport.TxRollback; -import org.apache.qpid.transport.TxSelect; - -/** - * Tests AMQSession_0_10 methods. - * <p> - * The main purpose of the tests in this test suite is to check that - * {@link SessionException} is not thrown from methods of - * {@link AMQSession_0_10}. - */ -public class AMQSession_0_10Test extends TestCase -{ - - public void testExceptionOnCommit() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - try - { - session.commit(); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testExceptionOnCreateMessageProducer() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - try - { - session.createMessageProducer(createDestination(), true, true, 1l); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected but got:" + e, e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testExceptionOnRollback() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - try - { - session.rollback(); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - } - } - - public void testExceptionOnRecover() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(javax.jms.Session.AUTO_ACKNOWLEDGE); - try - { - session.recover(); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - } - } - - public void testExceptionOnCreateBrowser() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - AMQQueue destination = createQueue(); - try - { - session.createBrowser(destination); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testExceptionOnCreateConsumer() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - AMQAnyDestination destination = createDestination(); - try - { - session.createConsumer(destination); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testExceptionOnCreateSubscriber() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - AMQAnyDestination destination = createDestination(); - try - { - session.createSubscriber(destination); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testExceptionOnUnsubscribe() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - try - { - session.unsubscribe("whatever"); - fail("JMSExceptiuon should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testCommit() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.commit(); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, TxCommit.class, false); - assertNotNull("TxCommit was not sent", event); - } - - public void testRollback() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.rollback(); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, TxRollback.class, false); - assertNotNull("TxRollback was not sent", event); - } - - public void testRecover() - { - AMQSession_0_10 session = createAMQSession_0_10(javax.jms.Session.AUTO_ACKNOWLEDGE); - try - { - session.recover(); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageRelease.class, false); - assertNotNull("MessageRelease was not sent", event); - } - - public void testCreateProducer() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.createProducer(createQueue()); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, ExchangeDeclare.class, false); - assertNotNull("ExchangeDeclare was not sent", event); - } - - public void testCreateConsumer() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.createConsumer(createQueue()); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageSubscribe.class, false); - assertNotNull("MessageSubscribe was not sent", event); - } - - public void testSync() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.sync(); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, ExecutionSync.class, false); - assertNotNull("ExecutionSync was not sent", event); - } - - public void testRejectMessage() - { - AMQSession_0_10 session = createAMQSession_0_10(); - session.rejectMessage(1l, true); - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageRelease.class, false); - assertNotNull("MessageRelease event was not sent", event); - } - - public void testReleaseForRollback() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.releaseForRollback(); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageRelease.class, false); - assertNotNull("MessageRelease event was not sent", event); - } - - public void testSendQueueDelete() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.sendQueueDelete(new AMQShortString("test")); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, QueueDelete.class, false); - assertNotNull("QueueDelete event was not sent", event); - QueueDelete exchangeDelete = (QueueDelete) event; - assertEquals("test", exchangeDelete.getQueue()); - } - - public void testSendConsume() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - BasicMessageConsumer_0_10 consumer = session.createMessageConsumer(createDestination(), 1, 1, true, false, - null, new FieldTable(), false, true); - session.sendConsume(consumer, new AMQShortString("test"), null, true, null, 1); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageSubscribe.class, false); - assertNotNull("MessageSubscribe event was not sent", event); - } - - public void testCreateMessageProducer() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.createMessageProducer(createDestination(), true, true, 1l); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, ExchangeDeclare.class, false); - assertNotNull("ExchangeDeclare event was not sent", event); - } - - public void testSendExchangeDelete() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - session.sendExchangeDelete("test", true); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, ExchangeDelete.class, false); - assertNotNull("ExchangeDelete event was not sent", event); - ExchangeDelete exchangeDelete = (ExchangeDelete) event; - assertEquals("test", exchangeDelete.getExchange()); - } - - public void testExceptionOnMessageConsumerReceive() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - try - { - BasicMessageConsumer_0_10 consumer = session.createMessageConsumer(createDestination(), 1, 1, true, false, - null, new FieldTable(), false, true); - session.start(); - consumer.receive(1); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testMessageConsumerReceive() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - BasicMessageConsumer_0_10 consumer = session.createMessageConsumer(createDestination(), 1, 1, true, false, - null, new FieldTable(), false, true); - session.start(); - consumer.receive(1); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageFlow.class, false); - assertNotNull("MessageFlow event was not sent", event); - } - - public void testExceptionOnMessageConsumerReceiveNoWait() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - try - { - BasicMessageConsumer_0_10 consumer = session.createMessageConsumer(createDestination(), 1, 1, true, false, - null, new FieldTable(), false, true); - session.start(); - consumer.receiveNoWait(); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testExceptionOnMessageConsumerSetMessageListener() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - try - { - BasicMessageConsumer_0_10 consumer = session.createMessageConsumer(createDestination(), 1, 1, true, false, - null, new FieldTable(), false, true); - consumer.setMessageListener(new MockMessageListener()); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testMessageConsumerSetMessageListener() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - BasicMessageConsumer_0_10 consumer = session.createMessageConsumer(createDestination(), 1, 1, true, false, - null, new FieldTable(), false, true); - consumer.setMessageListener(new MockMessageListener()); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageFlow.class, false); - assertNotNull("MessageFlow event was not sent", event); - } - - public void testMessageConsumerClose() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - BasicMessageConsumer_0_10 consumer = session.createMessageConsumer(createDestination(), 1, 1, true, false, - null, new FieldTable(), false, true); - consumer.close(); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageCancel.class, false); - assertNotNull("MessageCancel event was not sent", event); - } - - public void testExceptionOnMessageConsumerClose() - { - AMQSession_0_10 session = createThrowingExceptionAMQSession_0_10(); - try - { - BasicMessageConsumer_0_10 consumer = session.createMessageConsumer(createDestination(), 1, 1, true, false, - null, new FieldTable(), false, true); - consumer.close(); - fail("JMSException should be thrown"); - } - catch (Exception e) - { - assertTrue("JMSException is expected", e instanceof JMSException); - assertEquals("541 error code is expected", "541", ((JMSException) e).getErrorCode()); - } - } - - public void testMessageProducerSend() - { - AMQSession_0_10 session = createAMQSession_0_10(); - try - { - MessageProducer producer = session.createProducer(createQueue()); - producer.send(session.createTextMessage("Test")); - session.commit(); - } - catch (Exception e) - { - fail("Unexpected exception is cought:" + e.getMessage()); - } - ProtocolEvent event = findSentProtocolEventOfClass(session, MessageTransfer.class, false); - assertNotNull("MessageTransfer event was not sent", event); - event = findSentProtocolEventOfClass(session, ExchangeDeclare.class, false); - assertNotNull("ExchangeDeclare event was not sent", event); - } - - private AMQAnyDestination createDestination() - { - AMQAnyDestination destination = null; - try - { - destination = new AMQAnyDestination(new AMQShortString("amq.direct"), new AMQShortString("direct"), - new AMQShortString("test"), false, true, new AMQShortString("test"), true, null); - } - catch (Exception e) - { - fail("Failued to create destination:" + e.getMessage()); - } - return destination; - } - - private AMQQueue createQueue() - { - AMQQueue destination = null; - try - { - destination = new AMQQueue(new AMQShortString("amq.direct"), new AMQShortString("test"), - new AMQShortString("test")); - } - catch (Exception e) - { - fail("Failued to create destination:" + e.getMessage()); - } - return destination; - } - - private AMQSession_0_10 createThrowingExceptionAMQSession_0_10() - { - return createAMQSession_0_10(true, javax.jms.Session.SESSION_TRANSACTED); - } - - private AMQSession_0_10 createThrowingExceptionAMQSession_0_10(int akcnowledgeMode) - { - return createAMQSession_0_10(true, akcnowledgeMode); - } - - private ProtocolEvent findSentProtocolEventOfClass(AMQSession_0_10 session, Class<? extends ProtocolEvent> class1, - boolean isLast) - { - ProtocolEvent found = null; - List<ProtocolEvent> events = ((MockSession) session.getQpidSession()).getSender().getSendEvents(); - assertNotNull("Events list should not be null", events); - assertFalse("Events list should not be empty", events.isEmpty()); - if (isLast) - { - ProtocolEvent event = events.get(events.size() - 1); - if (event.getClass().isAssignableFrom(class1)) - { - found = event; - } - } - else - { - for (ProtocolEvent protocolEvent : events) - { - if (protocolEvent.getClass().isAssignableFrom(class1)) - { - found = protocolEvent; - break; - } - } - - } - return found; - } - - private AMQSession_0_10 createAMQSession_0_10() - { - return createAMQSession_0_10(false, javax.jms.Session.SESSION_TRANSACTED); - } - - private AMQSession_0_10 createAMQSession_0_10(int acknowledgeMode) - { - return createAMQSession_0_10(false, acknowledgeMode); - } - - private AMQSession_0_10 createAMQSession_0_10(boolean throwException, int acknowledgeMode) - { - AMQConnection amqConnection = null; - try - { - amqConnection = new MockAMQConnection( - "amqp://guest:guest@client/test?brokerlist='tcp://localhost:1'&maxprefetch='0'"); - } - catch (Exception e) - { - fail("Failure to create a mock connection:" + e.getMessage()); - } - boolean isTransacted = acknowledgeMode == javax.jms.Session.SESSION_TRANSACTED ? true : false; - AMQSession_0_10 session = new AMQSession_0_10(createConnection(throwException), amqConnection, 1, isTransacted, acknowledgeMode, - 1, 1, "test"); - return session; - } - - private Connection createConnection(final boolean throwException) - { - MockTransportConnection connection = new MockTransportConnection(); - connection.setState(State.OPEN); - connection.setSender(new MockSender()); - connection.setSessionFactory(new SessionFactory() - { - - @Override - public Session newSession(Connection conn, Binary name, long expiry) - { - return new MockSession(conn, new SessionDelegate(), name, expiry, throwException); - } - }); - return connection; - } - - private final class MockMessageListener implements MessageListener - { - @Override - public void onMessage(Message arg0) - { - } - } - - class MockSession extends Session - { - private final boolean _throwException; - private final Connection _connection; - private final SessionDelegate _delegate; - - protected MockSession(Connection connection, SessionDelegate delegate, Binary name, long expiry, - boolean throwException) - { - super(connection, delegate, name, expiry); - _throwException = throwException; - setState(State.OPEN); - _connection = connection; - _delegate = delegate; - } - - public void invoke(Method m, Runnable postIdSettingAction) - { - if (_throwException) - { - if (m instanceof SessionAttach || m instanceof SessionRequestTimeout || m instanceof TxSelect) - { - // do not throw exception for SessionAttach, - // SessionRequestTimeout and TxSelect - // session needs to be instantiated - return; - } - ExecutionException e = new ExecutionException(); - e.setErrorCode(ExecutionErrorCode.INTERNAL_ERROR); - throw new SessionException(e); - } - else - { - super.invoke(m, postIdSettingAction); - if (m instanceof SessionDetach) - { - setState(State.CLOSED); - } - } - } - - public void sync() - { - // to avoid recursive calls - setAutoSync(false); - // simply send sync command - super.executionSync(Option.SYNC); - } - - protected <T> Future<T> invoke(Method m, Class<T> klass) - { - int commandId = getCommandsOut(); - Future<T> future = super.invoke(m, klass); - ExecutionResult result = new ExecutionResult(); - result.setCommandId(commandId); - if (m instanceof ExchangeBound) - { - ExchangeBoundResult struc = new ExchangeBoundResult(); - struc.setQueueNotFound(true); - result.setValue(struc); - } - else if (m instanceof ExchangeQuery) - { - ExchangeQueryResult struc = new ExchangeQueryResult(); - result.setValue(struc); - } - else if (m instanceof QueueQuery) - { - QueueQueryResult struc = new QueueQueryResult(); - result.setValue(struc); - } - _delegate.executionResult(this, result); - return future; - } - - public MockSender getSender() - { - return (MockSender) _connection.getSender(); - } - } - - class MockTransportConnection extends Connection - { - public void setState(State state) - { - super.setState(state); - } - } - - class MockSender implements Sender<ProtocolEvent> - { - private List<ProtocolEvent> _sendEvents = new ArrayList<ProtocolEvent>(); - - @Override - public void setIdleTimeout(int i) - { - } - - @Override - public void send(ProtocolEvent msg) - { - _sendEvents.add(msg); - } - - @Override - public void flush() - { - } - - @Override - public void close() - { - } - - public List<ProtocolEvent> getSendEvents() - { - return _sendEvents; - } - - } - -} 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 index 73e67469ae..da44822ec3 100644 --- a/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java +++ b/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java @@ -23,6 +23,7 @@ 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; @@ -36,18 +37,53 @@ public class MockAMQConnection extends AMQConnection 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 { diff --git a/java/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java b/java/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java index b5c31e7c5e..7ee991b63c 100644 --- a/java/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java +++ b/java/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java @@ -43,9 +43,4 @@ public class TestMessageHelper { return new JMSStreamMessage(AMQMessageDelegateFactory.FACTORY_0_8); } - - public static JMSObjectMessage newJMSObjectMessage() - { - return new JMSObjectMessage(AMQMessageDelegateFactory.FACTORY_0_8); - } } 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 index e159ceb148..f520a21ba0 100644 --- 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 @@ -20,24 +20,23 @@ */ package org.apache.qpid.client.protocol; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import junit.framework.TestCase; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQAuthenticationException; -import org.apache.qpid.client.MockAMQConnection; -import org.apache.qpid.client.state.AMQState; -import org.apache.qpid.framing.AMQBody; 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.TestNetworkConnection; +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. * @@ -73,8 +72,8 @@ public class AMQProtocolHandlerTest extends TestCase public void setUp() throws Exception { //Create a new ProtocolHandler with a fake connection. - _handler = new AMQProtocolHandler(new MockAMQConnection("amqp://guest:guest@client/test?brokerlist='tcp://localhost:1'")); - _handler.setNetworkConnection(new TestNetworkConnection()); + _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); 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/client/security/CallbackHandlerRegistryTest.java b/java/client/src/test/java/org/apache/qpid/client/security/CallbackHandlerRegistryTest.java deleted file mode 100644 index cc5d48fbef..0000000000 --- a/java/client/src/test/java/org/apache/qpid/client/security/CallbackHandlerRegistryTest.java +++ /dev/null @@ -1,185 +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.client.security; - -import java.io.IOException; -import java.util.Properties; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; - -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.test.utils.QpidTestCase; - - -/** - * Tests the ability of {@link CallbackHandlerRegistry} to correctly parse - * the properties describing the available callback handlers. Ensures also - * that it is able to select the mechanism and create an implementation - * given a variety of starting conditions. - * - */ -public class CallbackHandlerRegistryTest extends QpidTestCase -{ - private CallbackHandlerRegistry _registry; // Object under test - - public void testCreateHandlerSuccess() - { - final Properties props = new Properties(); - props.put("TESTA.1", TestACallbackHandler.class.getName()); - - _registry = new CallbackHandlerRegistry(props); - assertEquals(1,_registry.getMechanisms().size()); - - final CallbackHandler handler = _registry.createCallbackHandler("TESTA"); - assertTrue(handler instanceof TestACallbackHandler); - } - - public void testCreateHandlerForUnknownMechanismName() - { - final Properties props = new Properties(); - props.put("TEST1.1", TestACallbackHandler.class.getName()); - - _registry = new CallbackHandlerRegistry(props); - - try - { - _registry.createCallbackHandler("NOTFOUND"); - fail("Exception not thrown"); - } - catch (IllegalArgumentException iae) - { - // PASS - } - } - - public void testSelectMechanism() - { - final Properties props = new Properties(); - props.put("TESTA.1", TestACallbackHandler.class.getName()); - props.put("TESTB.2", TestBCallbackHandler.class.getName()); - - _registry = new CallbackHandlerRegistry(props); - assertEquals(2,_registry.getMechanisms().size()); - - final String selectedMechanism = _registry.selectMechanism("TESTA"); - assertEquals("TESTA", selectedMechanism); - } - - public void testSelectReturnsFirstMutallyAvailableMechanism() - { - final Properties props = new Properties(); - props.put("TESTA.1", TestACallbackHandler.class.getName()); - props.put("TESTB.2", TestBCallbackHandler.class.getName()); - - _registry = new CallbackHandlerRegistry(props); - - final String selectedMechanism = _registry.selectMechanism("TESTD TESTB TESTA"); - // TESTA should be returned as it is higher than TESTB in the properties file. - assertEquals("Selected mechanism should respect the ordinal", "TESTA", selectedMechanism); - } - - public void testRestrictedSelectReturnsMechanismFromRestrictedList() - { - final Properties props = new Properties(); - props.put("TESTA.1", TestACallbackHandler.class.getName()); - props.put("TESTB.2", TestBCallbackHandler.class.getName()); - props.put("TESTC.3", TestCCallbackHandler.class.getName()); - - _registry = new CallbackHandlerRegistry(props); - - final String selectedMechanism = _registry.selectMechanism("TESTC TESTB TESTA", "TESTB TESTC"); - // TESTB should be returned as client has restricted the mechanism list to TESTB and TESTC - assertEquals("Selected mechanism should respect the ordinal and be limitted by restricted list","TESTB", selectedMechanism); - } - - public void testOldPropertyFormatRejected() - { - final Properties props = new Properties(); - props.put("CallbackHandler.TESTA", TestACallbackHandler.class.getName()); - - try - { - new CallbackHandlerRegistry(props); - fail("exception not thrown"); - } - catch(IllegalArgumentException iae) - { - // PASS - } - } - - public void testPropertyWithNonnumericalOrdinal() - { - final Properties props = new Properties(); - props.put("TESTA.z", TestACallbackHandler.class.getName()); - try - { - new CallbackHandlerRegistry(props); - fail("exception not thrown"); - } - catch(IllegalArgumentException iae) - { - // PASS - } - } - - public void testUnexpectedCallbackImplementationsIgnored() - { - final Properties props = new Properties(); - props.put("TESTA.1", TestACallbackHandler.class.getName()); - props.put("TESTB.2", "NotFound"); - props.put("TESTC.3", "java.lang.String"); - - _registry = new CallbackHandlerRegistry(props); - - assertEquals(1,_registry.getMechanisms().size()); - } - - static class TestACallbackHandler extends TestCallbackHandler - { - } - - static class TestBCallbackHandler extends TestCallbackHandler - { - } - - static class TestCCallbackHandler extends TestCallbackHandler - { - } - - static abstract class TestCallbackHandler implements AMQCallbackHandler - { - @Override - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException - { - throw new UnsupportedOperationException(); - } - - @Override - public void initialise(ConnectionURL connectionURL) - { - throw new UnsupportedOperationException(); - } - } - -} diff --git a/java/client/src/test/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandlerTest.java b/java/client/src/test/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandlerTest.java deleted file mode 100644 index 9e23f722eb..0000000000 --- a/java/client/src/test/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandlerTest.java +++ /dev/null @@ -1,99 +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.client.security; - -import java.security.MessageDigest; -import java.util.Arrays; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; - -import junit.framework.TestCase; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.client.MockAMQConnection; -import org.apache.qpid.client.protocol.AMQProtocolHandler; -import org.apache.qpid.client.protocol.AMQProtocolSession; - -/** - * Unit tests for the UsernameHashPasswordCallbackHandler. This callback handler is - * used by the CRAM-MD5-HASHED SASL mechanism. - * - */ -public class UsernameHashedPasswordCallbackHandlerTest extends TestCase -{ - private AMQCallbackHandler _callbackHandler = new UsernameHashedPasswordCallbackHandler(); // Class under test - private static final String PROMPT_UNUSED = "unused"; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - final String url = "amqp://username:password@client/test?brokerlist='tcp://localhost:1'"; - _callbackHandler.initialise(new AMQConnectionURL(url)); - } - - /** - * Tests that the callback handler can correctly retrieve the username from the connection url. - */ - public void testNameCallback() throws Exception - { - final String expectedName = "username"; - NameCallback nameCallback = new NameCallback(PROMPT_UNUSED); - - assertNull("Unexpected name before test", nameCallback.getName()); - _callbackHandler.handle(new Callback[] {nameCallback}); - assertEquals("Unexpected name", expectedName, nameCallback.getName()); - } - - /** - * Tests that the callback handler can correctly retrieve the password from the connection url - * and calculate a MD5. - */ - public void testDigestedPasswordCallback() throws Exception - { - final char[] expectedPasswordDigested = getHashPassword("password"); - - PasswordCallback passwordCallback = new PasswordCallback(PROMPT_UNUSED, false); - assertNull("Unexpected password before test", passwordCallback.getPassword()); - _callbackHandler.handle(new Callback[] {passwordCallback}); - assertTrue("Unexpected password", Arrays.equals(expectedPasswordDigested, passwordCallback.getPassword())); - } - - private char[] getHashPassword(final String password) throws Exception - { - MessageDigest md5Digester = MessageDigest.getInstance("MD5"); - final byte[] digest = md5Digester.digest(password.getBytes("UTF-8")); - - char[] hash = new char[digest.length]; - - int index = 0; - for (byte b : digest) - { - hash[index++] = (char) b; - } - - return hash; - } -} diff --git a/java/client/src/test/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandlerTest.java b/java/client/src/test/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandlerTest.java deleted file mode 100644 index 83ddfd72fa..0000000000 --- a/java/client/src/test/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandlerTest.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.client.security; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; - -import junit.framework.TestCase; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.client.MockAMQConnection; -import org.apache.qpid.client.protocol.AMQProtocolHandler; -import org.apache.qpid.client.protocol.AMQProtocolSession; - -/** - * Unit tests for the UsernamePasswordCallbackHandler. - * - */ -public class UsernamePasswordCallbackHandlerTest extends TestCase -{ - private AMQCallbackHandler _callbackHandler = new UsernamePasswordCallbackHandler(); // Class under test - private static final String PROMPT_UNUSED = "unused"; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - final String url = "amqp://username:password@client/test?brokerlist='tcp://localhost:1'"; - - _callbackHandler.initialise(new AMQConnectionURL(url)); - } - - /** - * Tests that the callback handler can correctly retrieve the username from the connection url. - */ - public void testNameCallback() throws Exception - { - final String expectedName = "username"; - NameCallback nameCallback = new NameCallback(PROMPT_UNUSED); - - assertNull("Unexpected name before test", nameCallback.getName()); - _callbackHandler.handle(new Callback[] {nameCallback}); - assertEquals("Unexpected name", expectedName, nameCallback.getName()); - } - - /** - * Tests that the callback handler can correctly retrieve the password from the connection url. - */ - public void testPasswordCallback() throws Exception - { - final String expectedPassword = "password"; - PasswordCallback passwordCallback = new PasswordCallback(PROMPT_UNUSED, false); - assertNull("Unexpected password before test", passwordCallback.getPassword()); - _callbackHandler.handle(new Callback[] {passwordCallback}); - assertEquals("Unexpected password", expectedPassword, new String(passwordCallback.getPassword())); - } -} diff --git a/java/client/src/test/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStreamTest.java b/java/client/src/test/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStreamTest.java deleted file mode 100644 index a12e4ce977..0000000000 --- a/java/client/src/test/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStreamTest.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.client.util; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.ObjectOutputStream; -import java.util.Arrays; -import java.util.List; - -import org.apache.qpid.test.utils.QpidTestCase; - -public class ClassLoadingAwareObjectInputStreamTest extends QpidTestCase -{ - InputStream _in; - ClassLoadingAwareObjectInputStream _claOIS; - - protected void setUp() throws Exception - { - //Create a viable input stream for instantiating the CLA OIS - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject("testString"); - out.flush(); - out.close(); - - - _in = new ByteArrayInputStream(baos.toByteArray()); - - _claOIS = new ClassLoadingAwareObjectInputStream(_in); - } - - /** - * Test that the resolveProxyClass method returns a proxy class implementing the desired interface - */ - public void testResolveProxyClass() throws Exception - { - //try to proxy an interface - Class<?> clazz = _claOIS.resolveProxyClass(new String[]{"java.lang.CharSequence"}); - - //verify the proxy supports the expected interface (only) - List<Class<?>> interfaces = Arrays.asList(clazz.getInterfaces()); - assertTrue("Unexpected interfaces supported by proxy", interfaces.contains(CharSequence.class)); - assertEquals("Unexpected interfaces supported by proxy", 1, interfaces.size()); - } - - /** - * Test that the resolveProxyClass method throws a ClassNotFoundException wrapping an - * IllegalArgumentException if it is provided arguments which violate the restrictions allowed - * by Proxy.getProxyClass (as required by the ObjectInputStream.resolveProxyClass javadoc). - */ - public void testResolveProxyClassThrowsCNFEWrappingIAE() throws Exception - { - try - { - //try to proxy a *class* rather than an interface, which is illegal - _claOIS.resolveProxyClass(new String[]{"java.lang.String"}); - fail("should have thrown an exception"); - } - catch(ClassNotFoundException cnfe) - { - //expected, but must verify it is wrapping an IllegalArgumentException - assertTrue(cnfe.getCause() instanceof IllegalArgumentException); - } - } -} diff --git a/java/client/src/test/java/org/apache/qpid/jms/FailoverPolicyTest.java b/java/client/src/test/java/org/apache/qpid/jms/FailoverPolicyTest.java deleted file mode 100644 index 438995aedc..0000000000 --- a/java/client/src/test/java/org/apache/qpid/jms/FailoverPolicyTest.java +++ /dev/null @@ -1,338 +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.jms; - -import javax.jms.ConnectionConsumer; -import javax.jms.ConnectionMetaData; -import javax.jms.Destination; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.ServerSessionPool; -import javax.jms.Topic; - -import org.apache.qpid.client.AMQConnectionURL; -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 junit.framework.TestCase; - -/** - * Tests the ability of FailoverPolicy to instantiate the correct FailoverMethod. - * - * This test presently does <i>not</i> test {@link FailoverPolicy#FailoverPolicy(FailoverMethod) or - * {@link FailoverPolicy#addMethod(FailoverMethod)} as it appears that this functionality - * is no longer in use. - * - */ -public class FailoverPolicyTest extends TestCase -{ - private FailoverPolicy _failoverPolicy = null; // class under test - private String _url; - private Connection _connection = null; - private ConnectionURL _connectionUrl = null; - - /** - * Tests single server method is selected for a brokerlist with one broker when - * the failover option is not specified. - */ - public void testBrokerListWithOneBrokerDefaultsToSingleServerPolicy() throws Exception - { - _url = "amqp://user:pass@clientid/test?brokerlist='tcp://localhost:5672'"; - _connectionUrl = new AMQConnectionURL(_url); - _connection = createStubConnection(); - - _failoverPolicy = new FailoverPolicy(_connectionUrl, _connection); - - assertTrue("Unexpected failover method", _failoverPolicy.getCurrentMethod() instanceof FailoverSingleServer); - } - - /** - * Tests round robin method is selected for a brokerlist with two brokers when - * the failover option is not specified. - */ - public void testBrokerListWithTwoBrokersDefaultsToRoundRobinPolicy() throws Exception - { - _url = "amqp://user:pass@clientid/test?brokerlist='tcp://localhost:5672;tcp://localhost:5673'"; - _connectionUrl = new AMQConnectionURL(_url); - _connection = createStubConnection(); - - _failoverPolicy = new FailoverPolicy(_connectionUrl, _connection); - - assertTrue("Unexpected failover method", _failoverPolicy.getCurrentMethod() instanceof FailoverRoundRobinServers); - } - - /** - * Tests single server method is selected for a brokerlist with one broker when - * the failover option passed as 'singlebroker'. - */ - public void testExplictFailoverOptionSingleBroker() throws Exception - { - _url = "amqp://user:pass@clientid/test?brokerlist='tcp://localhost:5672'&failover='singlebroker'"; - _connectionUrl = new AMQConnectionURL(_url); - _connection = createStubConnection(); - - _failoverPolicy = new FailoverPolicy(_connectionUrl, _connection); - - assertTrue("Unexpected failover method", _failoverPolicy.getCurrentMethod() instanceof FailoverSingleServer); - } - - /** - * Tests round robin method is selected for a brokerlist with two brokers when - * the failover option passed as 'roundrobin'. - */ - public void testExplictFailoverOptionRoundrobin() throws Exception - { - _url = "amqp://user:pass@clientid/test?brokerlist='tcp://localhost:5672;tcp://localhost:5673'&failover='roundrobin'"; - _connectionUrl = new AMQConnectionURL(_url); - _connection = createStubConnection(); - - _failoverPolicy = new FailoverPolicy(_connectionUrl, _connection); - - assertTrue("Unexpected failover method", _failoverPolicy.getCurrentMethod() instanceof FailoverRoundRobinServers); - } - - /** - * Tests no failover method is selected for a brokerlist with one broker when - * the failover option passed as 'nofailover'. - */ - public void testExplictFailoverOptionNofailover() throws Exception - { - _url = "amqp://user:pass@clientid/test?brokerlist='tcp://localhost:5672'&failover='nofailover'"; - _connectionUrl = new AMQConnectionURL(_url); - _connection = createStubConnection(); - - _failoverPolicy = new FailoverPolicy(_connectionUrl, _connection); - - assertTrue("Unexpected failover method", _failoverPolicy.getCurrentMethod() instanceof NoFailover); - } - - /** - * Tests failover exchange method is selected for a brokerlist with one broker when - * the failover option passed as 'failover_exchange'. - */ - public void testExplictFailoverOptionFailoverExchange() throws Exception - { - _url = "amqp://user:pass@clientid/test?brokerlist='tcp://localhost:5672'&failover='failover_exchange'"; - _connectionUrl = new AMQConnectionURL(_url); - _connection = createStubConnection(); - - _failoverPolicy = new FailoverPolicy(_connectionUrl, _connection); - - assertTrue("Unexpected failover method", _failoverPolicy.getCurrentMethod() instanceof FailoverExchangeMethod); - } - - /** - * Tests that a custom method can be selected for a brokerlist with one brokers when - * the failover option passed as a qualified class-name. - */ - public void testExplictFailoverOptionDynamicallyLoadedFailoverMethod() throws Exception - { - _url = "amqp://user:pass@clientid/test?brokerlist='tcp://localhost:5672'&failover='org.apache.qpid.jms.FailoverPolicyTest$MyFailoverMethod'"; - _connectionUrl = new AMQConnectionURL(_url); - _connection = createStubConnection(); - - _failoverPolicy = new FailoverPolicy(_connectionUrl, _connection); - - assertTrue("Unexpected failover method", _failoverPolicy.getCurrentMethod() instanceof MyFailoverMethod); - } - - /** - * Tests that an unknown method caused an exception. - */ - public void testUnknownFailoverMethod() throws Exception - { - _url = "amqp://user:pass@clientid/test?brokerlist='tcp://localhost:5672'&failover='unknown'"; - _connectionUrl = new AMQConnectionURL(_url); - _connection = createStubConnection(); - - try - { - new FailoverPolicy(_connectionUrl, _connection); - fail("Exception not thrown"); - } - catch(IllegalArgumentException iae) - { - // PASS - } - } - - private Connection createStubConnection() - { - return new Connection() - { - - @Override - public Session createSession(boolean transacted, - int acknowledgeMode, int prefetch) throws JMSException - { - return null; - } - - @Override - public Session createSession(boolean transacted, - int acknowledgeMode, int prefetchHigh, int prefetchLow) - throws JMSException - { - return null; - } - - @Override - public ConnectionListener getConnectionListener() - { - return null; - } - - @Override - public long getMaximumChannelCount() throws JMSException - { - return 0; - } - - @Override - public void setConnectionListener(ConnectionListener listener) - { - } - - @Override - public void close() throws JMSException - { - } - - @Override - public ConnectionConsumer createConnectionConsumer( - Destination arg0, String arg1, ServerSessionPool arg2, - int arg3) throws JMSException - { - return null; - } - - @Override - public ConnectionConsumer createDurableConnectionConsumer( - Topic arg0, String arg1, String arg2, - ServerSessionPool arg3, int arg4) throws JMSException - { - return null; - } - - @Override - public javax.jms.Session createSession(boolean arg0, int arg1) - throws JMSException - { - return null; - } - - @Override - public String getClientID() throws JMSException - { - return null; - } - - @Override - public ExceptionListener getExceptionListener() throws JMSException - { - return null; - } - - @Override - public ConnectionMetaData getMetaData() throws JMSException - { - return null; - } - - @Override - public void setClientID(String arg0) throws JMSException - { - } - - @Override - public void setExceptionListener(ExceptionListener arg0) - throws JMSException - { - } - - @Override - public void start() throws JMSException - { - } - - @Override - public void stop() throws JMSException - { - } - }; - } - - // Class used to test the ability of FailoverPolicy to load an implementation. - static class MyFailoverMethod implements FailoverMethod - { - public MyFailoverMethod(ConnectionURL connectionDetails) - { - } - - @Override - public void attainedConnection() - { - } - - @Override - public boolean failoverAllowed() - { - return false; - } - - @Override - public BrokerDetails getCurrentBrokerDetails() - { - return null; - } - - @Override - public BrokerDetails getNextBrokerDetails() - { - return null; - } - - @Override - public String methodName() - { - return null; - } - - @Override - public void reset() - { - } - - @Override - public void setBroker(BrokerDetails broker) - { - } - - @Override - public void setRetries(int maxRetries) - { - } - } - -} 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 9095f94960..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 @@ -43,6 +43,15 @@ public class BrokerDetailsTest extends TestCase assertTrue(broker.getProperty("immediatedelivery").equals("true")); } + public void testVMBroker() throws URLSyntaxException + { + String url = "vm://:2"; + + AMQBrokerDetails broker = new AMQBrokerDetails(url); + assertTrue(broker.getTransport().equals("vm")); + assertEquals(broker.getPort(), 2); + } + public void testTransportsDefaultToTCP() throws URLSyntaxException { String url = "localhost:5672"; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseMethodHandlerNoCloseOk.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseMethodHandlerNoCloseOk.java index d560c413e6..66f220643c 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseMethodHandlerNoCloseOk.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseMethodHandlerNoCloseOk.java @@ -73,7 +73,7 @@ public class ChannelCloseMethodHandlerNoCloseOk implements StateAwareMethodListe { throw new AMQNoRouteException("Error: " + reason, null, null); } - else if (errorCode == AMQConstant.ARGUMENT_INVALID) + else if (errorCode == AMQConstant.INVALID_ARGUMENT) { _logger.debug("Broker responded with Invalid Argument."); 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 4624b36fea..2be3720c20 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 @@ -300,6 +300,53 @@ public class ConnectionURLTest extends TestCase assertTrue(connectionurl.getOption("immediatedelivery").equals("true")); } + public void testSinglevmURL() throws URLSyntaxException + { + String url = "amqp://guest:guest@/test?brokerlist='vm://:2'"; + + ConnectionURL connectionurl = new AMQConnectionURL(url); + + assertTrue(connectionurl.getFailoverMethod() == null); + assertTrue(connectionurl.getUsername().equals("guest")); + assertTrue(connectionurl.getPassword().equals("guest")); + assertTrue(connectionurl.getVirtualHost().equals("/test")); + + assertTrue(connectionurl.getBrokerCount() == 1); + + BrokerDetails service = connectionurl.getBrokerDetails(0); + + assertTrue(service.getTransport().equals("vm")); + assertTrue(service.getHost().equals("")); + assertTrue(service.getPort() == 2); + + } + + public void testFailoverVMURL() throws URLSyntaxException + { + String url = "amqp://ritchiem:bob@/test?brokerlist='vm://:2;vm://:3',failover='roundrobin'"; + + ConnectionURL connectionurl = new AMQConnectionURL(url); + + assertTrue(connectionurl.getFailoverMethod().equals("roundrobin")); + assertTrue(connectionurl.getUsername().equals("ritchiem")); + assertTrue(connectionurl.getPassword().equals("bob")); + assertTrue(connectionurl.getVirtualHost().equals("/test")); + + assertTrue(connectionurl.getBrokerCount() == 2); + + BrokerDetails service = connectionurl.getBrokerDetails(0); + + assertTrue(service.getTransport().equals("vm")); + assertTrue(service.getHost().equals("")); + assertTrue(service.getPort() == 2); + + service = connectionurl.getBrokerDetails(1); + assertTrue(service.getTransport().equals("vm")); + assertTrue(service.getHost().equals("")); + assertTrue(service.getPort() == 3); + } + + public void testNoVirtualHostURL() { String url = "amqp://user@?brokerlist='tcp://localhost:5672'"; @@ -440,6 +487,27 @@ public class ConnectionURLTest extends TestCase } + public void testSocketProtocol() throws URLSyntaxException + { + String url = "amqp://guest:guest@id/test" + "?brokerlist='socket://VM-Unique-socketID'"; + + try + { + AMQConnectionURL curl = new AMQConnectionURL(url); + assertNotNull(curl); + assertEquals(1, curl.getBrokerCount()); + 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.replace(":guest", ":********"), curl.toString()); + } + catch (URLSyntaxException e) + { + fail(e.getMessage()); + } + } + public void testSingleTransportMultiOptionOnBrokerURL() throws URLSyntaxException { String url = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672?foo='jim'&bar='bob'&fred='jimmy'',routingkey='jim',timeout='200',immediatedelivery='true'"; @@ -481,37 +549,6 @@ public class ConnectionURLTest extends TestCase assertTrue("String representation should contain options and values", url.toString().contains("maxprefetch='12345'")); } - public void testHostNamesWithUnderScore() throws URLSyntaxException - { - String url = "amqp://guest:guest@clientid/test?brokerlist='tcp://under_score:6672'"; - - ConnectionURL connectionurl = new AMQConnectionURL(url); - - assertTrue(connectionurl.getUsername().equals("guest")); - assertTrue(connectionurl.getPassword().equals("guest")); - assertTrue(connectionurl.getVirtualHost().equals("/test")); - - assertTrue(connectionurl.getBrokerCount() == 1); - BrokerDetails service = connectionurl.getBrokerDetails(0); - assertTrue(service.getTransport().equals("tcp")); - assertTrue(service.getHost().equals("under_score")); - assertTrue(service.getPort() == 6672); - - url = "amqp://guest:guest@clientid/test?brokerlist='tcp://under_score'"; - - connectionurl = new AMQConnectionURL(url); - - assertTrue(connectionurl.getUsername().equals("guest")); - assertTrue(connectionurl.getPassword().equals("guest")); - assertTrue(connectionurl.getVirtualHost().equals("/test")); - - assertTrue(connectionurl.getBrokerCount() == 1); - service = connectionurl.getBrokerDetails(0); - assertTrue(service.getTransport().equals("tcp")); - assertTrue(service.getHost().equals("under_score")); - assertTrue(service.getPort() == 5672); - } - public static junit.framework.Test suite() { return new junit.framework.TestSuite(ConnectionURLTest.class); diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageUnitTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageUnitTest.java deleted file mode 100644 index e37970e9a2..0000000000 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageUnitTest.java +++ /dev/null @@ -1,105 +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.test.unit.client.message; - -import java.util.ArrayList; -import java.util.Arrays; - -import org.apache.qpid.client.message.JMSObjectMessage; -import org.apache.qpid.client.message.TestMessageHelper; -import org.apache.qpid.test.utils.QpidTestCase; - -public class ObjectMessageUnitTest extends QpidTestCase -{ - private JMSObjectMessage _om; - - protected void setUp() throws Exception - { - super.setUp(); - _om = TestMessageHelper.newJMSObjectMessage(); - } - - /** - * Test that setObject with a primitive works - */ - public void testSetObjectWithBooleanPrimitive() throws Exception - { - _om.setObject(true); - - //make the message readable - Object object = _om.getObject(); - - assertTrue("Unexpected type returned", object instanceof Boolean); - assertEquals("Unexpected value returned", true, object); - } - - /** - * Test that setObject with a serializable Object works - */ - public void testSetObjectWithString() throws Exception - { - _om.setObject("test string"); - - //make the message readable - Object object = _om.getObject(); - - assertTrue("Unexpected type returned", object instanceof String); - assertEquals("Unexpected value returned", "test string", object); - } - - /** - * Test that setObject with a Collection of serializable's works, returning - * the items in the list when deserialized and ignoring any values - * added to the collection after setObject() is called on the message. - */ - public void testSetObjectWithArrayListOfInteger() throws Exception - { - ArrayList<Integer> list = new ArrayList<Integer>(); - list.add(1234); - list.add(Integer.MIN_VALUE); - list.add(Integer.MAX_VALUE); - - _om.setObject(list); - - //add something extra to the list now, and check it isn't in the value read back - list.add(0); - - //make the message readable - - //retrieve the Object - Object object = _om.getObject(); - - ArrayList<?> returnedList = null; - if(object instanceof ArrayList<?>) - { - returnedList = (ArrayList<?>) object; - } - else - { - fail("returned object was not an ArrayList"); - } - - //verify the extra added Integer was not present, then remove it from original list again and compare contents with the returned list - assertFalse("returned list should not have had the value added after setObject() was used", returnedList.contains(0)); - list.remove(Integer.valueOf(0)); - assertTrue("list contents were not equal", Arrays.equals(list.toArray(), returnedList.toArray())); - } -} 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 index 20496026ce..9e76b0d468 100644 --- 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 @@ -21,10 +21,10 @@ 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 { @@ -34,9 +34,21 @@ public class ConnectionFactoryTest extends TestCase 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 testConnectionURLStringMasksPassword() throws Exception + public void testConnectionURLString() { - AMQConnectionFactory factory = new AMQConnectionFactory(URL); + 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()); 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 index 2052312f54..a1b14d5723 100644 --- 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 @@ -24,7 +24,6 @@ import java.util.Properties; import javax.jms.Queue; import javax.jms.Topic; -import javax.naming.ConfigurationException; import javax.naming.Context; import javax.naming.InitialContext; @@ -68,22 +67,4 @@ public class JNDIPropertyFileTest extends TestCase assertEquals("Topic" + i + "WithSpace",bindingKey.asString()); } } - - public void testConfigurationErrors() throws Exception - { - Properties properties = new Properties(); - properties.put("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory"); - properties.put("destination.my-queue","amq.topic/test;create:always}"); - - try - { - ctx = new InitialContext(properties); - fail("A configuration exception should be thrown with details about the address syntax error"); - } - catch(ConfigurationException e) - { - assertTrue("Incorrect exception", e.getMessage().contains("Failed to parse entry: amq.topic/test;create:always}")); - } - - } } 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 6759b43387..47c0359b94 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 @@ -20,24 +20,17 @@ */ package org.apache.qpid.test.unit.message; -import java.util.Map; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.TemporaryQueue; -import javax.jms.Topic; -import javax.jms.TopicSubscriber; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.BasicMessageConsumer_0_8; -import org.apache.qpid.client.BasicMessageProducer_0_8; -import org.apache.qpid.client.failover.FailoverException; +import org.apache.qpid.client.*; import org.apache.qpid.client.message.AMQMessageDelegateFactory; import org.apache.qpid.client.protocol.AMQProtocolHandler; +import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; + +import javax.jms.*; + +import java.util.Map; public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> { @@ -64,12 +57,7 @@ public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMe } - public void commitImpl() throws AMQException, FailoverException - { - - } - - public void acknowledgeImpl() + public void sendCommit() throws AMQException, FailoverException { } @@ -129,7 +117,7 @@ public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMe } - public BasicMessageProducer_0_8 createMessageProducer(Destination destination, boolean mandatory, boolean immediate, long producerId) + public BasicMessageProducer_0_8 createMessageProducer(Destination destination, boolean mandatory, boolean immediate, boolean waitUntilSent, long producerId) { return null; } @@ -207,10 +195,4 @@ public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMe { return false; } - - @Override - public AMQException getLastException() - { - return null; - } } |
