From 03cff78ded53707789824dd5840fe8d862d899c7 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Wed, 13 Oct 2010 20:04:09 +0000 Subject: Minor updates git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/grkvlt-network-20101013@1022275 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/build.deps | 18 +- .../qpid/client/AMQConnectionDelegate_8_0.java | 4 +- .../qpid/client/protocol/AMQProtocolHandler.java | 14 +- .../pool/ReferenceCountingExecutorService.java | 45 +- .../apache/qpid/transport/network/Assembler.java | 7 - .../qpid/transport/network/Disassembler.java | 13 +- .../org/apache/qpid/transport/network/Frame.java | 1 - .../qpid/transport/network/InputHandler.java | 2 - .../apache/qpid/transport/network/Transport.java | 5 + .../transport/network/io/IoNetworkConnection.java | 8 +- .../transport/network/io/IoNetworkHandler.java | 4 +- .../transport/network/io/IoNetworkTransport.java | 10 +- .../network/mina/MinaNetworkTransport.java | 41 +- .../qpid/transport/network/mina/MinaSender.java | 29 +- .../org/apache/qpid/util/CommandLineParser.java | 695 --------------------- .../apache/qpid/util/CommandLineParserTest.java | 556 ----------------- .../org/apache/qpid/util/CommandLineParser.java | 695 +++++++++++++++++++++ .../qpid/server/queue/PersistentTestManual.java | 9 +- 18 files changed, 784 insertions(+), 1372 deletions(-) delete mode 100644 qpid/java/common/src/main/java/org/apache/qpid/util/CommandLineParser.java delete mode 100644 qpid/java/common/src/test/java/org/apache/qpid/util/CommandLineParserTest.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/util/CommandLineParser.java diff --git a/qpid/java/build.deps b/qpid/java/build.deps index c89a1550bb..815ff35058 100644 --- a/qpid/java/build.deps +++ b/qpid/java/build.deps @@ -60,25 +60,24 @@ core-lib=lib/core-3.1.1.jar servlet-api=lib/servlet-api.jar muse.libs = ${muse-core} ${muse-platform-mini} ${muse-util} ${muse-util-qname} \ -${muse-util-xml} ${muse-wsa-soap} ${muse-wsdm-muws-adv-api} ${muse-wsdm-muws-adv-impl} \ -${muse-wsdm-muws-api} ${muse-wsdm-muws-impl} ${muse-wsdm-wef-api} ${muse-wsdm-wef-impl} \ -${muse-wsn-api} ${muse-wsn-impl} ${muse-wsrf-api} ${muse-wsrf-impl} ${muse-wsrf-rmd} \ -${muse-wsx-api} ${muse-wsx-impl} ${wsdl4j} ${xercesImpl} ${xml-apis} ${jetty} ${jetty-util} ${jetty-bootstrap} + ${muse-util-xml} ${muse-wsa-soap} ${muse-wsdm-muws-adv-api} ${muse-wsdm-muws-adv-impl} \ + ${muse-wsdm-muws-api} ${muse-wsdm-muws-impl} ${muse-wsdm-wef-api} ${muse-wsdm-wef-impl} \ + ${muse-wsn-api} ${muse-wsn-impl} ${muse-wsrf-api} ${muse-wsrf-impl} ${muse-wsrf-rmd} \ + ${muse-wsx-api} ${muse-wsx-impl} ${wsdl4j} ${xercesImpl} ${xml-apis} ${jetty} ${jetty-util} ${jetty-bootstrap} jsp.libs = ${jsp-api} ${jsp-impl} ${core-lib} -osgi-core=lib/org.osgi.core-1.0.0.jar felix-framework=lib/org.apache.felix.framework-2.0.5.jar geronimo-servlet=lib/geronimo-servlet_2.5_spec-1.2.jar -felix.libs=${osgi-core} ${felix-framework} +felix.libs=${felix-framework} commons-configuration.libs = ${commons-beanutils-core} ${commons-digester} \ - ${commons-codec} ${commons-lang} ${commons-collections} ${commons-configuration} + ${commons-codec} ${commons-lang} ${commons-collections} ${commons-configuration} common.libs=${slf4j-api} ${mina-core} ${mina-filter-ssl} -client.libs=${geronimo-jms} -tools.libs=${commons-configuration.libs} +client.libs=${geronimo-jms} ${common.libs} +tools.libs=${commons-configuration.libs} ${broker.libs} broker.libs=${commons-cli} ${commons-logging} ${log4j} ${slf4j-log4j} \ ${xalan} ${felix.libs} ${derby-db} ${commons-configuration.libs} @@ -154,7 +153,6 @@ management-eclipse-plugin.platform-libs=${ecl-equinox-launcher-win32-win32-x86} management-eclipse-plugin.libs=${management-eclipse-plugin.core-libs} ${management-eclipse-plugin.platform-libs} - management-tools-qpid-cli.libs=${jline} ${commons-configuration.libs} common.test.libs=${test.libs} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java index 47b8d82d0b..7d34be587c 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java @@ -104,9 +104,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate sslFactory = new SSLContextFactory(sslConfig.getKeystorePath(), sslConfig.getKeystorePassword(), sslConfig.getCertType()); } - OutgoingNetworkTransport transport = Transport.getOutgoingTransport(); - NetworkConnection network = transport.connect(settings, _conn._protocolHandler, sslFactory); - _conn._protocolHandler.connect(transport, network); + _conn._protocolHandler.connect(settings, sslFactory); _conn._protocolHandler.getProtocolSession().init(); // this blocks until the connection has been set up or when an error diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java index ee1009af61..edfb4bb16b 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java @@ -61,10 +61,14 @@ import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; +import org.apache.qpid.ssl.SSLContextFactory; +import org.apache.qpid.transport.ConnectionSettings; import org.apache.qpid.transport.Receiver; import org.apache.qpid.transport.Sender; import org.apache.qpid.transport.network.NetworkConnection; import org.apache.qpid.transport.network.NetworkTransport; +import org.apache.qpid.transport.network.OutgoingNetworkTransport; +import org.apache.qpid.transport.network.Transport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -174,7 +178,7 @@ public class AMQProtocolHandler implements Receiver private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance(); private Sender _sender; private NetworkConnection _network; - private NetworkTransport _transport; + private OutgoingNetworkTransport _transport; private ProtocolVersion _suggestedProtocolVersion; private long _writtenBytes; @@ -807,11 +811,11 @@ public class AMQProtocolHandler implements Receiver return _transport.getAddress(); } - public void connect(NetworkTransport transport, NetworkConnection network) + public void connect(ConnectionSettings settings, SSLContextFactory sslFactory) { - _transport = transport; - _network = network; - _sender = network.getSender(); + _transport = Transport.getOutgoingTransport(); + _network = _transport.connect(settings, this, sslFactory); + _sender = _network.getSender(); } /** @param delay delay in seconds (not ms) */ diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java index 20a30b3ed3..e891d05c26 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java @@ -25,6 +25,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; /** * ReferenceCountingExecutorService wraps an ExecutorService in order to provide shared reference to it. It counts @@ -75,14 +76,11 @@ public class ReferenceCountingExecutorService */ private static final ReferenceCountingExecutorService _instance = new ReferenceCountingExecutorService(); - /** This lock is used to ensure that reference counts are updated atomically with create/destroy operations. */ - private final Object _lock = new Object(); - /** The shared executor service that is reference counted. */ private ExecutorService _pool; /** Holds the number of references given out to the executor service. */ - private int _refCount = 0; + private AtomicInteger _refCount = new AtomicInteger(0); /** Holds the number of executor threads to create. */ private int _poolSize = Integer.getInteger("amqj.read_write_pool_size", DEFAULT_POOL_SIZE); @@ -112,28 +110,24 @@ public class ReferenceCountingExecutorService */ public ExecutorService acquireExecutorService() { - synchronized (_lock) + if (_refCount.getAndIncrement() == 0) { - if (_refCount++ == 0) - { // _pool = Executors.newFixedThreadPool(_poolSize); - // Use a job queue that biases to writes - if(_useBiasedPool) - { - _pool = new ThreadPoolExecutor(_poolSize, _poolSize, - 0L, TimeUnit.MILLISECONDS, - new ReadWriteJobQueue()); - } - else - { - _pool = Executors.newFixedThreadPool(_poolSize); - } + // Use a job queue that biases to writes + if(_useBiasedPool) + { + _pool = new ThreadPoolExecutor(_poolSize, _poolSize, + 0L, TimeUnit.MILLISECONDS, + new ReadWriteJobQueue()); } + else + { + _pool = Executors.newFixedThreadPool(_poolSize); + } + } - - return _pool; - } + return _pool; } /** @@ -142,12 +136,9 @@ public class ReferenceCountingExecutorService */ public void releaseExecutorService() { - synchronized (_lock) + if (_refCount.decrementAndGet() == 0) { - if (--_refCount == 0) - { - _pool.shutdownNow(); - } + _pool.shutdownNow(); } } @@ -167,6 +158,6 @@ public class ReferenceCountingExecutorService */ public int getReferenceCount() { - return _refCount; + return _refCount.get(); } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java index 1fbca9aad0..37e731206c 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java @@ -24,12 +24,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import java.nio.ByteBuffer; import org.apache.qpid.transport.codec.BBDecoder; -import org.apache.qpid.transport.codec.Decoder; -import org.apache.qpid.transport.util.Functions; import org.apache.qpid.transport.Header; import org.apache.qpid.transport.Method; @@ -37,17 +34,13 @@ import org.apache.qpid.transport.ProtocolError; import org.apache.qpid.transport.ProtocolEvent; import org.apache.qpid.transport.ProtocolHeader; import org.apache.qpid.transport.Receiver; -import org.apache.qpid.transport.SegmentType; import org.apache.qpid.transport.Struct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /** * Assembler - * */ - public class Assembler implements Receiver, NetworkDelegate { private static final Logger _log = LoggerFactory.getLogger(Assembler.class); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java index 87e1e17df9..87cabeb874 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java @@ -20,6 +20,10 @@ */ package org.apache.qpid.transport.network; +import static org.apache.qpid.transport.network.Frame.*; + +import static java.lang.Math.min; + import org.apache.qpid.transport.Header; import org.apache.qpid.transport.Method; import org.apache.qpid.transport.ProtocolDelegate; @@ -30,22 +34,13 @@ import org.apache.qpid.transport.SegmentType; import org.apache.qpid.transport.Sender; import org.apache.qpid.transport.Struct; import org.apache.qpid.transport.codec.BBEncoder; -import static org.apache.qpid.transport.network.Frame.FIRST_FRAME; -import static org.apache.qpid.transport.network.Frame.FIRST_SEG; -import static org.apache.qpid.transport.network.Frame.HEADER_SIZE; -import static org.apache.qpid.transport.network.Frame.LAST_FRAME; -import static org.apache.qpid.transport.network.Frame.LAST_SEG; -import static java.lang.Math.min; import java.nio.ByteBuffer; import java.nio.ByteOrder; - /** * Disassembler converts protocol events to byte buffers that can be sent on the network. - * */ - public final class Disassembler implements Sender, ProtocolDelegate { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Frame.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Frame.java index 780b725219..67639c3cb0 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Frame.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Frame.java @@ -26,7 +26,6 @@ import java.nio.ByteBuffer; import org.apache.qpid.transport.SegmentType; - /** * Frame */ diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java index 145ab02ae4..34d733860b 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java @@ -30,11 +30,9 @@ import org.apache.qpid.transport.ProtocolError; import org.apache.qpid.transport.ProtocolHeader; import org.apache.qpid.transport.Receiver; import org.apache.qpid.transport.SegmentType; -import org.apache.qpid.transport.util.Functions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /** * InputHandler * diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java index a6ad1679fa..bb7f059d15 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java @@ -35,6 +35,11 @@ public class Transport public static final String VM = "vm"; public static final String SOCKET = "socket"; public static final String MULTICAST = "multicast"; + + public static final int DEFAULT_BUFFER_SIZE = 32 * 1024; + public static final long DEFAULT_TIMEOUT = 60000; + + public static final boolean WINDOWS = ((String) System.getProperties().get("os.name")).matches("(?i).*windows.*"); public static final String MINA_TRANSPORT = "org.apache.qpid.transport.network.mina.MinaNetworkTransport"; public static final String IO_TRANSPORT = "org.apache.qpid.transport.network.io.IoNetworkTransport"; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java index 0392428606..2c175a27bb 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java @@ -31,6 +31,7 @@ import org.apache.qpid.transport.Receiver; import org.apache.qpid.transport.Sender; import org.apache.qpid.transport.TransportException; import org.apache.qpid.transport.network.NetworkConnection; +import org.apache.qpid.transport.network.Transport; /** * IoNetworkConnection @@ -42,7 +43,6 @@ public class IoNetworkConnection implements NetworkConnection private final long _timeout; private final AtomicBoolean _closed = new AtomicBoolean(false); private final Thread _receiverThread; - private final boolean _shutdownBroken = ((String) System.getProperties().get("os.name")).matches("(?i).*windows.*"); public IoNetworkConnection(Socket socket, Receiver receiver, int sendBufferSize, int receiveBufferSize, long timeout) @@ -58,11 +58,11 @@ public class IoNetworkConnection implements NetworkConnection } catch(Exception e) { - throw new Error("Error creating IoNetworkTransport thread",e); + throw new Error("Error creating IoNetworkConnection thread",e); } _receiverThread.setDaemon(true); - _receiverThread.setName(String.format("IoNetworkTransport-%s", socket.getRemoteSocketAddress())); + _receiverThread.setName(String.format("IoNetworkConnection-%s", socket.getRemoteSocketAddress())); _receiverThread.start(); } @@ -73,7 +73,7 @@ public class IoNetworkConnection implements NetworkConnection { try { - if (_shutdownBroken) + if (Transport.WINDOWS) { _socket.close(); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkHandler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkHandler.java index a0ca358a13..2af6b103fe 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkHandler.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkHandler.java @@ -26,6 +26,7 @@ import java.net.SocketException; import java.nio.ByteBuffer; import org.apache.qpid.transport.Receiver; +import org.apache.qpid.transport.network.Transport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +40,6 @@ public class IoNetworkHandler implements Runnable private final Receiver _receiver; private final int _bufSize; private final Socket _socket; - private final boolean _shutdownBroken = ((String) System.getProperties().get("os.name")).matches("(?i).*windows.*"); public IoNetworkHandler(Socket socket, Receiver receiver, int bufSize) { @@ -77,7 +77,7 @@ public class IoNetworkHandler implements Runnable } catch (Throwable t) { - if (!(_shutdownBroken && + if (!(Transport.WINDOWS && t instanceof SocketException && t.getMessage().equalsIgnoreCase("socket closed") && _socket.isClosed()) && _socket.isConnected()) diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java index 301d6b0fad..aa480554ea 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java @@ -44,13 +44,10 @@ public class IoNetworkTransport implements OutgoingNetworkTransport { private static final Logger _log = LoggerFactory.getLogger(IoNetworkTransport.class); - private static final int DEFAULT_BUFFER_SIZE = 32 * 1024; - public static final List SUPPORTED = Arrays.asList(Transport.TCP); private Socket _socket; private IoNetworkConnection _connection; - private long _timeout = 60000; public NetworkConnection connect(ConnectionSettings settings, Receiver delegate, SSLContextFactory sslfactory) { @@ -61,8 +58,9 @@ public class IoNetworkTransport implements OutgoingNetworkTransport boolean noDelay = Boolean.getBoolean("amqj.tcpNoDelay"); boolean keepAlive = Boolean.getBoolean("amqj.keepAlive"); - Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize", DEFAULT_BUFFER_SIZE); - Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize", DEFAULT_BUFFER_SIZE); + Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize", Transport.DEFAULT_BUFFER_SIZE); + Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize", Transport.DEFAULT_BUFFER_SIZE); + Long timeout = Long.getLong("amqj.timeout", Transport.DEFAULT_TIMEOUT); try { @@ -92,7 +90,7 @@ public class IoNetworkTransport implements OutgoingNetworkTransport throw new TransportException("Error connecting to broker", e); } - _connection = new IoNetworkConnection(_socket, delegate, sendBufferSize, receiveBufferSize, _timeout); + _connection = new IoNetworkConnection(_socket, delegate, sendBufferSize, receiveBufferSize, timeout); return _connection; } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaNetworkTransport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaNetworkTransport.java index 2200c5805f..5c84f405e2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaNetworkTransport.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaNetworkTransport.java @@ -68,11 +68,9 @@ public class MinaNetworkTransport implements IncomingNetworkTransport, OutgoingN { private static final Logger _log = LoggerFactory.getLogger(MinaNetworkTransport.class); - private static final int DEFAULT_BUFFER_SIZE = 32 * 1024; - public static final List SUPPORTED = Arrays.asList(Transport.SOCKET, Transport.TCP, Transport.UDP, Transport.VM); - private int _processors; + private int _threads; private Executor _executor; private ConnectionSettings _settings; private SocketAddress _address; @@ -86,16 +84,17 @@ public class MinaNetworkTransport implements IncomingNetworkTransport, OutgoingN org.apache.mina.common.ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers")); // the default is to use the simple allocator -// if (Boolean.getBoolean("amqj.enablePooledAllocator")) -// { + if (Boolean.getBoolean("amqj.enablePooledAllocator")) + { org.apache.mina.common.ByteBuffer.setAllocator(new PooledByteBufferAllocator()); -// } -// else -// { -// org.apache.mina.common.ByteBuffer.setAllocator(new SimpleByteBufferAllocator()); -// } + } + else + { + org.apache.mina.common.ByteBuffer.setAllocator(new SimpleByteBufferAllocator()); + } - _processors = Integer.parseInt(System.getProperty("amqj.processors", "4")); + int processors = Runtime.getRuntime().availableProcessors(); + _threads = Integer.parseInt(System.getProperty("amqj.processors", Integer.toString(processors))); _executor = Executors.newCachedThreadPool(Threading.getThreadFactory()); } @@ -109,7 +108,7 @@ public class MinaNetworkTransport implements IncomingNetworkTransport, OutgoingN if (_settings.getProtocol().equalsIgnoreCase(Transport.TCP)) { _address = new InetSocketAddress(_settings.getHost(), _settings.getPort()); - _connector = new SocketConnector(_processors, _executor); // non-blocking connector + _connector = new SocketConnector(_threads, _executor); // non-blocking connector } else if (_settings.getProtocol().equalsIgnoreCase(Transport.UDP)) { @@ -134,7 +133,7 @@ public class MinaNetworkTransport implements IncomingNetworkTransport, OutgoingN "with 'socket://' transport"); } _address = socket.getRemoteSocketAddress(); - _connector = new ExistingSocketConnector(_processors, _executor); + _connector = new ExistingSocketConnector(_threads, _executor); ((ExistingSocketConnector) _connector).setOpenSocket(socket); } else @@ -162,8 +161,8 @@ public class MinaNetworkTransport implements IncomingNetworkTransport, OutgoingN { SocketSessionConfig scfg = (SocketSessionConfig) cfg.getSessionConfig(); scfg.setTcpNoDelay(Boolean.getBoolean("amqj.tcpNoDelay")); - Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize", DEFAULT_BUFFER_SIZE); - Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize", DEFAULT_BUFFER_SIZE); + Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize", Transport.DEFAULT_BUFFER_SIZE); + Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize", Transport.DEFAULT_BUFFER_SIZE); scfg.setSendBufferSize(sendBufferSize); scfg.setReceiveBufferSize(receiveBufferSize); @@ -190,15 +189,16 @@ public class MinaNetworkTransport implements IncomingNetworkTransport, OutgoingN { if (settings.getProtocol().equalsIgnoreCase(Transport.TCP)) { - _acceptor = new SocketAcceptor(_processors, _executor); + _acceptor = new SocketAcceptor(_threads, _executor); SocketAcceptorConfig sconfig = (SocketAcceptorConfig) _acceptor.getDefaultConfig(); + sconfig.setDisconnectOnUnbind(true); SocketSessionConfig ssc = (SocketSessionConfig) sconfig.getSessionConfig(); ssc.setReuseAddress(true); ssc.setKeepAlive(Boolean.getBoolean("amqj.keepAlive")); ssc.setTcpNoDelay(Boolean.getBoolean("amqj.tcpNoDelay")); - Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize", DEFAULT_BUFFER_SIZE); - Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize", DEFAULT_BUFFER_SIZE); + Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize", Transport.DEFAULT_BUFFER_SIZE); + Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize", Transport.DEFAULT_BUFFER_SIZE); ssc.setSendBufferSize(sendBufferSize); ssc.setReceiveBufferSize(receiveBufferSize); @@ -216,10 +216,11 @@ public class MinaNetworkTransport implements IncomingNetworkTransport, OutgoingN _acceptor = new DatagramAcceptor(_executor); DatagramAcceptorConfig dconfig = (DatagramAcceptorConfig) _acceptor.getDefaultConfig(); + dconfig.setDisconnectOnUnbind(true); DatagramSessionConfig dsc = (DatagramSessionConfig) dconfig.getSessionConfig(); dsc.setReuseAddress(true); - Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize", DEFAULT_BUFFER_SIZE); - Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize", DEFAULT_BUFFER_SIZE); + Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize", Transport.DEFAULT_BUFFER_SIZE); + Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize", Transport.DEFAULT_BUFFER_SIZE); dsc.setSendBufferSize(sendBufferSize); dsc.setReceiveBufferSize(receiveBufferSize); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java index d1e0541981..5fc3032d35 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java @@ -52,29 +52,22 @@ public class MinaSender implements Sender { throw new TransportException("attempted to write to a closed socket"); } -// synchronized (this) - { - ByteBuffer mina = ByteBuffer.allocate(buf.capacity()); - mina.put(buf); - mina.flip(); - flush(); - _lastWrite = _session.write(mina); - flush(); - } + ByteBuffer mina = ByteBuffer.allocate(buf.capacity()); + mina.put(buf); + mina.flip(); + flush(); + _lastWrite = _session.write(mina); } public synchronized void flush() { -// synchronized (this) + if (_lastWrite != null) { - if (_lastWrite != null) - { - _lastWrite.join(); - if (!_lastWrite.isWritten()) - { - throw new RuntimeException("Error flushing buffe"); - } - } + _lastWrite.join(); + if (!_lastWrite.isWritten()) + { + throw new RuntimeException("Error flushing buffer"); + } } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/util/CommandLineParser.java b/qpid/java/common/src/main/java/org/apache/qpid/util/CommandLineParser.java deleted file mode 100644 index 09478d4157..0000000000 --- a/qpid/java/common/src/main/java/org/apache/qpid/util/CommandLineParser.java +++ /dev/null @@ -1,695 +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.util; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.regex.*; - -/** - * CommandLineParser provides a utility for specifying the format of a command line and parsing command lines to ensure - * that they fit their specified format. A command line is made up of flags and options, both may be refered to as - * options. A flag is an option that does not take an argument (specifying it means it has the value 'true' and not - * specifying it means it has the value 'false'). Options must take arguments but they can be set up with defaults so - * that they take a default value when not set. Options may be mandatory in wich case it is an error not to specify - * them on the command line. Flags are never mandatory because they are implicitly set to false when not specified. - * - *

Some example command lines are: - * - *

    - *
  • This one has two options that expect arguments: - *
    - * cruisecontrol -configfile cruisecontrol.xml -port 9000
    - * 
    - *
  • This has one no-arg flag and two 'free' arguments: - *
    - * zip -r project.zip project/*
    - * 
    - *
  • This one concatenates multiple flags into a single block with only one '-': - *
    - * jar -tvf mytar.tar
    - * 
    - * - *

    The parsing rules are: - * - *

      - *
    1. Flags may be combined after a single '-' because they never take arguments. Normally such flags are single letter - * flags but this is only a convention and not enforced. Flags of more than one letter are usually specified on their own. - *
    2. Options expecting arguments must always be on their own. - *
    3. The argument to an option may be seperated from it by whitespace or appended directly onto the option. - *
    4. The argument to an option may never begin with a '-' character. - *
    5. All other arguments not beginning with a '-' character are free arguments that do not belong to any option. - *
    6. The second or later of a set of duplicate or repeated flags are ignored. - *
    7. Options are matched up to the shortest matching option. This is because of the possibility of having no space - * between an option and its argument. This rules out the possibility of using two options where one is an opening - * substring of the other. For example, the options "foo" and "foobar" cannot be used on the same command line because - * it is not possible to distinguish the argument "-foobar" from being the "foobar" option or the "foo" option with - * the "bar" argument. - *
    - * - *

    By default, unknown options are simply ignored if specified on the command line. This behaviour may be changed - * so that the parser reports all unknowns as errors by using the {@link #setErrorsOnUnknowns} method. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Accept a command line specification. - *
    Parse a command line into properties, validating it against its specification. - *
    Report all errors between a command line and its specification. - *
    Provide a formatted usage string for a command line. - *
    Provide a formatted options in force string for a command line. - *
    Allow errors on unknowns behaviour to be turned on or off. - *
    - */ -public class CommandLineParser -{ - /** Holds a mapping from command line option names to detailed information about those options. */ - private Map optionMap = new HashMap(); - - /** Holds a list of parsing errors. */ - private List parsingErrors = new ArrayList(); - - /** Holds the regular expression matcher to match command line options with. */ - private Matcher optionMatcher = null; - - /** Holds the parsed command line properties after parsing. */ - private Properties parsedProperties = null; - - /** Flag used to indicate that errors should be created for unknown options. False by default. */ - private boolean errorsOnUnknowns = false; - - /** - * Creates a command line options parser from a command line specification. This is passed to this constructor - * as an array of arrays of strings. Each array of strings specifies the command line for a single option. A static - * array may therefore easily be used to configure the command line parser in a single method call with an easily - * readable format. - * - *

    Each array of strings must be 2, 3, 4 or 5 elements long. If any of the last three elements are missing they - * are assumed to be null. The elements specify the following parameters: - *

      - *
    1. The name of the option without the leading '-'. For example, "file". To specify the format of the 'free' - * arguments use the option names "1", "2", ... and so on. - *
    2. The option comment. A line of text describing the usage of the option. For example, "The file to be processed." - *
    3. The options argument. This is a very short description of the argument to the option, often a single word - * or a reminder as to the arguments format. When this element is null the option is a flag and does not - * accept any arguments. For example, "filename" or "(unix | windows)" or null. The actual text specified - * is only used to print in the usage message to remind the user of the usage of the option. - *
    4. The mandatory flag. When set to "true" an option must always be specified. Any other value, including null, - * means that the option is mandatory. Flags are always mandatory (see class javadoc for explanation of why) so - * this is ignored for flags. - *
    5. A regular expression describing the format that the argument must take. Ignored if null. - *
    - *

    An example call to this constructor is: - * - *

    -     * CommandLineParser commandLine = new CommandLineParser(
    -     *     new String[][] {{"file", "The file to be processed. ", "filename", "true"},
    -     *                     {"dir", "Directory to store results in. Current dir used if not set.", "out dir"},
    -     *                     {"os", "Operating system EOL format to use.", "(windows | unix)", null, "windows\|unix"},
    -     *                     {"v", "Verbose mode. Prints information about the processing as it goes."},
    -     *                     {"1", "The processing command to run.", "command", "true", "add\|remove\|list"}});
    -     * 
    - * - * @param config The configuration as an array of arrays of strings. - */ - public CommandLineParser(String[][] config) - { - // Loop through all the command line option specifications creating details for each in the options map. - for (int i = 0; i < config.length; i++) - { - String[] nextOptionSpec = config[i]; - - addOption(nextOptionSpec[0], nextOptionSpec[1], (nextOptionSpec.length > 2) ? nextOptionSpec[2] : null, - (nextOptionSpec.length > 3) ? ("true".equals(nextOptionSpec[3]) ? true : false) : false, - (nextOptionSpec.length > 4) ? nextOptionSpec[4] : null); - } - } - - /** - * Lists all the parsing errors from the most recent parsing in a string. - * - * @return All the parsing errors from the most recent parsing. - */ - public String getErrors() - { - // Return the empty string if there are no errors. - if (parsingErrors.isEmpty()) - { - return ""; - } - - // Concatenate all the parsing errors together. - StringBuilder result = new StringBuilder(); - - for (String s : parsingErrors) - { - result.append(s); - } - - return result.toString(); - } - - /** - * Lists the properties set from the most recent parsing or an empty string if no parsing has been done yet. - * - * @return The properties set from the most recent parsing or an empty string if no parsing has been done yet. - */ - public String getOptionsInForce() - { - // Check if there are no properties to report and return and empty string if so. - if (parsedProperties == null) - { - return ""; - } - - // List all the properties. - StringBuilder result = new StringBuilder("Options in force:\n"); - - for (Map.Entry property : parsedProperties.entrySet()) - { - result.append(property.getKey()) - .append(" = ") - .append(property.getValue()) - .append('\n'); - } - - return result.toString(); - } - - /** - * Generates a usage string consisting of the name of each option and each options argument description and - * comment. - * - * @return A usage string for all the options. - */ - public String getUsage() - { - String result = "Options:\n"; - - // Print usage on each of the command line options. - for (CommandLineOption optionInfo : optionMap.values()) - { - result += - "-" + optionInfo.option + " " + ((optionInfo.argument != null) ? (optionInfo.argument + " ") : "") - + optionInfo.comment + "\n"; - } - - return result; - } - - /** - * Control the behaviour of the errors on unkowns reporting. When turned on this reports all unkowns options - * as errors. When turned off, all unknowns are simply ignored. - * - * @param errors The setting of the errors on unkown flag. True to turn it on. - */ - public void setErrorsOnUnknowns(boolean errors) - { - errorsOnUnknowns = errors; - } - - /** - * Parses a set of command line arguments into a set of properties, keyed by the argument flag. The free arguments - * are keyed by integers as strings starting at "1" and then "2", ... and so on. - * - *

    See the class level comment for a description of the parsing rules. - * - * @param args The command line arguments. - * - * @return The arguments as a set of properties. - * - * @throws IllegalArgumentException If the command line cannot be parsed against its specification. If this exception - * is thrown a call to {@link #getErrors} will provide a diagnostic of the command - * line errors. - */ - public Properties parseCommandLine(String[] args) throws IllegalArgumentException - { - Properties options = new Properties(); - - // Used to keep count of the current 'free' argument. - int free = 1; - - // Used to indicate that the most recently parsed option is expecting arguments. - boolean expectingArgs = false; - - // The option that is expecting arguments from the next element of the command line. - String optionExpectingArgs = null; - - // Used to indicate that the most recently parsed option is a duplicate and should be ignored. - boolean ignore = false; - - // Create the regular expression matcher for the command line options. - StringBuilder regexp = new StringBuilder("^("); - int optionsAdded = 0; - - for (Iterator i = optionMap.keySet().iterator(); i.hasNext();) - { - String nextOption = i.next(); - - // Check that the option is not a free argument definition. - boolean notFree = false; - - try - { - Integer.parseInt(nextOption); - } - catch (NumberFormatException e) - { - notFree = true; - } - - // Add the option to the regular expression matcher if it is not a free argument definition. - if (notFree) - { - regexp.append(nextOption) - .append(i.hasNext() ? "|" : ""); - optionsAdded++; - } - } - - // There has to be more that one option in the regular expression or else the compiler complains that the close - // cannot be nullable if the '?' token is used to make the matched option string optional. - regexp.append(')') - .append(((optionsAdded > 0) ? "?" : "")) - .append("(.*)"); - Pattern pattern = Pattern.compile(regexp.toString()); - - // Loop through all the command line arguments. - for (int i = 0; i < args.length; i++) - { - // Check if the next command line argument begins with a '-' character and is therefore the start of - // an option. - if (args[i].startsWith("-")) - { - // Extract the value of the option without the leading '-'. - String arg = args[i].substring(1); - - // Match up to the longest matching option. - optionMatcher = pattern.matcher(arg); - optionMatcher.matches(); - - String matchedOption = optionMatcher.group(1); - - // Match any argument directly appended onto the longest matching option. - String matchedArg = optionMatcher.group(2); - - // Check that a known option was matched. - if ((matchedOption != null) && !"".equals(matchedOption)) - { - // Get the command line option information for the matched option. - CommandLineOption optionInfo = optionMap.get(matchedOption); - - // Check if this option is expecting arguments. - if (optionInfo.expectsArgs) - { - // The option is expecting arguments so swallow the next command line argument as an - // argument to this option. - expectingArgs = true; - optionExpectingArgs = matchedOption; - - // In the mean time set this options argument to the empty string in case no argument is ever - // supplied. - // options.put(matchedOption, ""); - } - - // Check if the option was matched on its own and is a flag in which case set that flag. - if ("".equals(matchedArg) && !optionInfo.expectsArgs) - { - options.put(matchedOption, "true"); - } - // The option was matched as a substring with its argument appended to it or is a flag that is - // condensed together with other flags. - else if (!"".equals(matchedArg)) - { - // Check if the option is a flag and therefore is allowed to be condensed together - // with other flags. - if (!optionInfo.expectsArgs) - { - // Set the first matched flag. - options.put(matchedOption, "true"); - - // Repeat the longest matching process on the remainder but ensure that the remainder - // consists only of flags as only flags may be condensed together in this fashion. - do - { - // Match the remainder against the options. - optionMatcher = pattern.matcher(matchedArg); - optionMatcher.matches(); - - matchedOption = optionMatcher.group(1); - matchedArg = optionMatcher.group(2); - - // Check that an option was matched. - if (matchedOption != null) - { - // Get the command line option information for the next matched option. - optionInfo = optionMap.get(matchedOption); - - // Ensure that the next option is a flag or raise an error if not. - if (optionInfo.expectsArgs == true) - { - parsingErrors.add("Option " + matchedOption + " cannot be combined with flags.\n"); - } - - options.put(matchedOption, "true"); - } - // The remainder could not be matched against a flag it is either an unknown flag - // or an illegal argument to a flag. - else - { - parsingErrors.add("Illegal argument to a flag in the option " + arg + "\n"); - - break; - } - } - // Continue until the remainder of the argument has all been matched with flags. - while (!"".equals(matchedArg)); - } - // The option is expecting an argument, so store the unmatched portion against it - // as its argument. - else - { - // Check the arguments format is correct against any specified format. - checkArgumentFormat(optionInfo, matchedArg); - - // Store the argument against its option (regardless of its format). - options.put(matchedOption, matchedArg); - - // The argument to this flag has already been supplied to it. Do not swallow the - // next command line argument as an argument to this flag. - expectingArgs = false; - } - } - } - else // No matching option was found. - { - // Add this to the list of parsing errors if errors on unkowns is being used. - if (errorsOnUnknowns) - { - parsingErrors.add("Option " + matchedOption + " is not a recognized option.\n"); - } - } - } - // The command line argument did not being with a '-' so it is an argument to the previous flag or it - // is a free argument. - else - { - // Check if a previous flag is expecting to swallow this next argument as its argument. - if (expectingArgs) - { - // Get the option info for the option waiting for arguments. - CommandLineOption optionInfo = optionMap.get(optionExpectingArgs); - - // Check the arguments format is correct against any specified format. - checkArgumentFormat(optionInfo, args[i]); - - // Store the argument against its option (regardless of its format). - options.put(optionExpectingArgs, args[i]); - - // Clear the expecting args flag now that the argument has been swallowed. - expectingArgs = false; - optionExpectingArgs = null; - } - // This command line option is not an argument to any option. Add it to the set of 'free' options. - else - { - // Get the option info for the free option, if there is any. - CommandLineOption optionInfo = optionMap.get(Integer.toString(free)); - - if (optionInfo != null) - { - // Check the arguments format is correct against any specified format. - checkArgumentFormat(optionInfo, args[i]); - } - - // Add to the list of free options. - options.put(Integer.toString(free), args[i]); - - // Move on to the next free argument. - free++; - } - } - } - - // Scan through all the specified options to check that all mandatory options have been set and that all flags - // that were not set are set to false in the set of properties. - for (CommandLineOption optionInfo : optionMap.values()) - { - // Check if this is a flag. - if (!optionInfo.expectsArgs) - { - // Check if the flag is not set in the properties and set it to false if so. - if (!options.containsKey(optionInfo.option)) - { - options.put(optionInfo.option, "false"); - } - } - // Check if this is a mandatory option and was not set. - else if (optionInfo.mandatory && !options.containsKey(optionInfo.option)) - { - // Create an error for the missing option. - parsingErrors.add("Option -" + optionInfo.option + " is mandatory but not was not specified.\n"); - } - } - - // Check if there were any errors. - if (!parsingErrors.isEmpty()) - { - // Throw an illegal argument exception to signify that there were parsing errors. - throw new IllegalArgumentException(); - } - - // Convert any name/value pairs in the free arguments into properties in the parsed options. - options = takeFreeArgsAsProperties(options, 1); - - parsedProperties = options; - - return options; - } - - /** - * If a command line has been parsed, calling this method sets all of its parsed options into the specified properties. - */ - public void addCommandLineToProperties(Properties properties) - { - if (parsedProperties != null) - { - for (Object propKey : parsedProperties.keySet()) - { - String name = (String) propKey; - String value = parsedProperties.getProperty(name); - - properties.setProperty(name, value); - } - } - } - - /** - * Resets this command line parser after it has been used to parse a command line. This method will only need - * to be called to use this parser a second time which is not likely seeing as a command line is usually only - * specified once. However, it is exposed as a public method for the rare case where this may be done. - * - *

    Cleans the internal state of this parser, removing all stored errors and information about the options in - * force. - */ - public void reset() - { - parsingErrors = new ArrayList(); - parsedProperties = null; - } - - /** - * Adds the option to list of available command line options. - * - * @param option The option to add as an available command line option. - * @param comment A comment for the option. - * @param argument The text that appears after the option in the usage string. - * @param mandatory When true, indicates that this option is mandatory. - * @param formatRegexp The format that the argument must take, defined as a regular expression. - */ - protected void addOption(String option, String comment, String argument, boolean mandatory, String formatRegexp) - { - // Check if usage text has been set in which case this option is expecting arguments. - boolean expectsArgs = ((argument == null) || argument.equals("")) ? false : true; - - // Add the option to the map of command line options. - CommandLineOption opt = new CommandLineOption(option, expectsArgs, comment, argument, mandatory, formatRegexp); - optionMap.put(option, opt); - } - - /** - * Converts the free arguments into property declarations. After parsing the command line the free arguments - * are numbered from 1, such that the parsed properties contain values for the keys "1", "2", ... This method - * converts any free arguments declared using the 'name=value' syntax into properties with key 'name', value - * 'value'. - * - *

    For example the comand line: - *

    -     * ... debug=true
    -     * 
    - * - *

    After parsing has properties: - *

    [[1, debug=true]]
    - * - *

    After applying this method the properties are: - *

    [[1, debug=true], [debug, true]]
    - * - * @param properties The parsed command line properties. - * @param from The free argument index to convert to properties from. - * - * @return The parsed command line properties, with free argument name value pairs too. - */ - private Properties takeFreeArgsAsProperties(Properties properties, int from) - { - for (int i = from; true; i++) - { - String nextFreeArg = properties.getProperty(Integer.toString(i)); - - // Terminate the loop once all free arguments have been consumed. - if (nextFreeArg == null) - { - break; - } - - // Split it on the =, strip any whitespace and set it as a system property. - String[] nameValuePair = nextFreeArg.split("="); - - if (nameValuePair.length == 2) - { - properties.setProperty(nameValuePair[0], nameValuePair[1]); - } - } - - return properties; - } - - /** - * Checks the format of an argument to an option against its specified regular expression format if one has - * been set. Any errors are added to the list of parsing errors. - * - * @param optionInfo The command line option information for the option which is havings its argument checked. - * @param matchedArg The string argument to the option. - */ - private void checkArgumentFormat(CommandLineOption optionInfo, String matchedArg) - { - // Check if this option enforces a format for its argument. - if (optionInfo.argumentFormatRegexp != null) - { - Pattern pattern = Pattern.compile(optionInfo.argumentFormatRegexp); - Matcher argumentMatcher = pattern.matcher(matchedArg); - - // Check if the argument does not meet its required format. - if (!argumentMatcher.matches()) - { - // Create an error for this badly formed argument. - parsingErrors.add("The argument to option -" + optionInfo.option + " does not meet its required format.\n"); - } - } - } - - /** - * Extracts all name=value pairs from the command line, sets them all as system properties and also returns - * a map of properties containing them. - * - * @param args The command line. - * @param commandLine The command line parser. - * @param properties The properties object to inject all parsed properties into (optional may be null). - * - * @return A set of properties containing all name=value pairs from the command line. - */ - public static Properties processCommandLine(String[] args, CommandLineParser commandLine, Properties properties) - { - // Capture the command line arguments or display errors and correct usage and then exit. - Properties options = null; - - try - { - options = commandLine.parseCommandLine(args); - - // Add all the trailing command line options (name=value pairs) to system properties. They may be picked up - // from there. - commandLine.addCommandLineToProperties(properties); - } - catch (IllegalArgumentException e) - { - System.out.println(commandLine.getErrors()); - System.out.println(commandLine.getUsage()); - System.exit(1); - } - - return options; - } - - /** - * Holds information about a command line options. This includes what its name is, whether or not it is a flag, - * whether or not it is mandatory, what its user comment is, what its argument reminder text is and what its - * regular expression format is. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Hold details of a command line option. - *
    - */ - protected static class CommandLineOption - { - /** Holds the text for the flag to match this argument with. */ - public String option = null; - - /** Holds a string describing how to use this command line argument. */ - public String argument = null; - - /** Flag that determines whether or not this command line argument can take arguments. */ - public boolean expectsArgs = false; - - /** Holds a short comment describing what this command line argument is for. */ - public String comment = null; - - /** Flag that determines whether or not this is an mandatory command line argument. */ - public boolean mandatory = false; - - /** A regular expression describing what format the argument to this option muist have. */ - public String argumentFormatRegexp = null; - - /** - * Create a command line option object that holds specific information about a command line option. - * - * @param option The text that matches the option. - * @param expectsArgs Whether or not the option expects arguments. It is a flag if this is false. - * @param comment A comment explaining how to use this option. - * @param argument A short reminder of the format of the argument to this option/ - * @param mandatory Set to true if this option is mandatory. - * @param formatRegexp The regular expression that the argument to this option must meet to be valid. - */ - public CommandLineOption(String option, boolean expectsArgs, String comment, String argument, boolean mandatory, - String formatRegexp) - { - this.option = option; - this.expectsArgs = expectsArgs; - this.comment = comment; - this.argument = argument; - this.mandatory = mandatory; - this.argumentFormatRegexp = formatRegexp; - } - } -} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/CommandLineParserTest.java b/qpid/java/common/src/test/java/org/apache/qpid/util/CommandLineParserTest.java deleted file mode 100644 index 5835da95ef..0000000000 --- a/qpid/java/common/src/test/java/org/apache/qpid/util/CommandLineParserTest.java +++ /dev/null @@ -1,556 +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.util; - -import java.util.Properties; - -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.qpid.test.utils.QpidTestCase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit tests the {@link CommandLineParser} class. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Check that parsing a single flag works ok. - *
    Check that parsing multiple flags condensed together works ok. - *
    Check that parsing an option with a space between it and its argument works ok. - *
    Check that parsing an option with no space between it and its argument works ok. - *
    Check that parsing an option with specific argument format works ok. - *
    Check that parsing an option with specific argument format fails on bad argument. - *
    Check that parsing a flag condensed together with an option fails. - *
    Check that parsing a free argument works ok. - *
    Check that parsing a free argument with specific format works ok. - *
    Check that parsing a free argument with specific format fails on bad argument. - *
    Check that parsing a mandatory option works ok. - *
    Check that parsing a mandatory free argument works ok. - *
    Check that parsing a mandatory option fails when no option is set. - *
    Check that parsing a mandatory free argument fails when no argument is specified. - *
    Check that parsing an unknown option works when unknowns not errors. - *
    Check that parsing an unknown flag fails when unknowns are to be reported as errors. - *
    Check that parsing an unknown option fails when unknowns are to be reported as errors. - *
    Check that get errors returns a string on errors. - *
    Check that get errors returns an empty string on no errors. - *
    Check that get usage returns a string. - *
    Check that get options in force returns an empty string before parsing. - *
    Check that get options in force return a non-empty string after parsing. - *
    - */ -public class CommandLineParserTest extends QpidTestCase -{ - private static final Logger log = LoggerFactory.getLogger(CommandLineParserTest.class); - - public CommandLineParserTest(String name) - { - super(name); - } - - /** - * Compile all the tests for the default test implementation of a traversable state into a test suite. - */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("CommandLineParser Tests"); - - // Add all the tests defined in this class (using the default constructor) - suite.addTestSuite(CommandLineParserTest.class); - - return suite; - } - - /** Check that get errors returns an empty string on no errors. */ - public void testGetErrorsReturnsEmptyStringOnNoErrors() throws Exception - { - // Create a command line parser for some flags and options. - CommandLineParser parser = - new CommandLineParser( - new String[][] - { - { "t1", "Test Flag 1." }, - { "t2", "Test Option 2.", "test" }, - { "t3", "Test Option 3.", "test", "true" }, - { "t4", "Test Option 4.", "test", null, "^test$" } - }); - - // Do some legal parsing. - parser.parseCommandLine(new String[] { "-t1", "-t2test", "-t3test", "-t4test" }); - - // Check that the get errors message returns an empty string. - assertTrue("The errors method did not return an empty string.", "".equals(parser.getErrors())); - } - - /** Check that get errors returns a string on errors. */ - public void testGetErrorsReturnsStringOnErrors() throws Exception - { - // Create a command line parser for some flags and options. - CommandLineParser parser = - new CommandLineParser( - new String[][] - { - { "t1", "Test Flag 1." }, - { "t2", "Test Option 2.", "test" }, - { "t3", "Test Option 3.", "test", "true" }, - { "t4", "Test Option 4.", "test", null, "^test$" } - }); - - try - { - // Do some illegal parsing. - parser.parseCommandLine(new String[] { "-t1", "-t1t2test", "-t4fail" }); - } - catch (IllegalArgumentException e) - { } - - // Check that the get errors message returns a string. - assertTrue("The errors method returned an empty string.", - !((parser.getErrors() == null) || "".equals(parser.getErrors()))); - - } - - /** Check that get options in force returns an empty string before parsing. */ - public void testGetOptionsInForceReturnsEmptyStringBeforeParsing() throws Exception - { - // Create a command line parser for some flags and options. - CommandLineParser parser = - new CommandLineParser( - new String[][] - { - { "t1", "Test Flag 1." }, - { "t2", "Test Option 2.", "test" }, - { "t3", "Test Option 3.", "test", "true" }, - { "t4", "Test Option 4.", "test", null, "^test$" } - }); - - // Check that the options in force method returns an empty string. - assertTrue("The options in force method did not return an empty string.", "".equals(parser.getOptionsInForce())); - } - - /** Check that get options in force return a non-empty string after parsing. */ - public void testGetOptionsInForceReturnsNonEmptyStringAfterParsing() throws Exception - { - // Create a command line parser for some flags and options. - CommandLineParser parser = - new CommandLineParser( - new String[][] - { - { "t1", "Test Flag 1." }, - { "t2", "Test Option 2.", "test" }, - { "t3", "Test Option 3.", "test", "true" }, - { "t4", "Test Option 4.", "test", null, "^test$" } - }); - - // Do some parsing. - parser.parseCommandLine(new String[] { "-t1", "-t2test", "-t3test", "-t4test" }); - - // Check that the options in force method returns a string. - assertTrue("The options in force method did not return a non empty string.", - !((parser.getOptionsInForce() == null) || "".equals(parser.getOptionsInForce()))); - } - - /** Check that get usage returns a string. */ - public void testGetUsageReturnsString() throws Exception - { - // Create a command line parser for some flags and options. - CommandLineParser parser = - new CommandLineParser( - new String[][] - { - { "t1", "Test Flag 1." }, - { "t2", "Test Option 2.", "test" }, - { "t3", "Test Option 3.", "test", "true" }, - { "t4", "Test Option 4.", "test", null, "^test$" } - }); - - // Check that the usage method returns a string. - assertTrue("The usage method did not return a non empty string.", - !((parser.getUsage() == null) || "".equals(parser.getUsage()))); - } - - /** Check that parsing multiple flags condensed together works ok. */ - public void testParseCondensedFlagsOk() throws Exception - { - // Create a command line parser for multiple flags. - CommandLineParser parser = - new CommandLineParser( - new String[][] - { - { "t1", "Test Flag 1." }, - { "t2", "Test Flag 2." }, - { "t3", "Test Flag 3." } - }); - - // Parse a command line with the flags set and condensed together. - Properties testProps = parser.parseCommandLine(new String[] { "-t1t2t3" }); - - // Check that the flags were set in the parsed properties. - assertTrue("The t1 flag was not \"true\", it was: " + testProps.get("t1"), "true".equals(testProps.get("t1"))); - assertTrue("The t2 flag was not \"true\", it was: " + testProps.get("t2"), "true".equals(testProps.get("t2"))); - assertTrue("The t3 flag was not \"true\", it was: " + testProps.get("t3"), "true".equals(testProps.get("t3"))); - } - - /** Check that parsing a flag condensed together with an option fails. */ - public void testParseFlagCondensedWithOptionFails() throws Exception - { - // Create a command line parser for a flag and an option. - CommandLineParser parser = - new CommandLineParser(new String[][] - { - { "t1", "Test Flag 1." }, - { "t2", "Test Option 2.", "test" } - }); - - // Check that the parser reports an error. - boolean testPassed = false; - - try - { - // Parse a command line with the flag and option condensed together. - Properties testProps = parser.parseCommandLine(new String[] { "-t1t2" }); - } - catch (IllegalArgumentException e) - { - testPassed = true; - } - - assertTrue("IllegalArgumentException not thrown when a flag and option are condensed together.", testPassed); - } - - /** Check that parsing a free argument with specific format fails on bad argument. */ - public void testParseFormattedFreeArgumentFailsBadArgument() throws Exception - { - // Create a command line parser for a formatted free argument. - CommandLineParser parser = - new CommandLineParser(new String[][] - { - { "1", "Test Free Argument.", "test", null, "^test$" } - }); - - // Check that the parser signals an error for a badly formatted argument. - boolean testPassed = false; - - try - { - // Parse a command line with this option set incorrectly. - Properties testProps = parser.parseCommandLine(new String[] { "fail" }); - } - catch (IllegalArgumentException e) - { - testPassed = true; - } - - assertTrue("IllegalArgumentException not thrown when a badly formatted argument was set.", testPassed); - } - - /** Check that parsing a free argument with specific format works ok. */ - public void testParseFormattedFreeArgumentOk() throws Exception - { - // Create a command line parser for a formatted free argument. - CommandLineParser parser = - new CommandLineParser(new String[][] - { - { "1", "Test Free Argument.", "test", null, "^test$" } - }); - - // Parse a command line with this argument set correctly. - Properties testProps = parser.parseCommandLine(new String[] { "test" }); - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("The first free argument was not equal to \"test\" but was: " + testProps.get("1"), - "test".equals(testProps.get("1"))); - } - - /** Check that parsing an option with specific argument format fails on bad argument. */ - public void testParseFormattedOptionArgumentFailsBadArgument() throws Exception - { - // Create a command line parser for a formatted option. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "t", "Test Option.", "test", null, "^test$" } - }); - - // Check that the parser signals an error for a badly formatted argument. - boolean testPassed = false; - - try - { - // Parse a command line with this option set incorrectly. - Properties testProps = parser.parseCommandLine(new String[] { "-t", "fail" }); - } - catch (IllegalArgumentException e) - { - testPassed = true; - } - - assertTrue("IllegalArgumentException not thrown when a badly formatted argument was set.", testPassed); - } - - /** Check that parsing an option with specific argument format works ok. */ - public void testParseFormattedOptionArgumentOk() throws Exception - { - // Create a command line parser for a formatted option. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "t", "Test Option.", "test", null, "^test$" } - }); - - // Parse a command line with this option set correctly. - Properties testProps = parser.parseCommandLine(new String[] { "-t", "test" }); - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("The test option was not equal to \"test\" but was: " + testProps.get("t"), - "test".equals(testProps.get("t"))); - } - - /** Check that parsing a free argument works ok. */ - public void testParseFreeArgumentOk() throws Exception - { - // Create a command line parser for a free argument. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "1", "Test Free Argument.", "test" } - }); - - // Parse a command line with this argument set. - Properties testProps = parser.parseCommandLine(new String[] { "test" }); - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("The first free argument was not equal to \"test\" but was: " + testProps.get("1"), - "test".equals(testProps.get("1"))); - } - - /** Check that parsing a mandatory option works ok. */ - public void testParseMandatoryOptionOk() throws Exception - { - // Create a command line parser for a mandatory option. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "t", "Test Option.", "test", "true" } - }); - - // Parse a command line with this option set correctly. - Properties testProps = parser.parseCommandLine(new String[] { "-t", "test" }); - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("The test option was not equal to \"test\" but was: " + testProps.get("t"), - "test".equals(testProps.get("t"))); - } - - /** Check that parsing a mandatory free argument works ok. */ - public void testParseMandatoryFreeArgumentOk() throws Exception - { - // Create a command line parser for a mandatory free argument. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "1", "Test Option.", "test", "true" } - }); - - // Parse a command line with this argument set. - Properties testProps = parser.parseCommandLine(new String[] { "test" }); - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("The first free argument was not equal to \"test\" but was: " + testProps.get("1"), - "test".equals(testProps.get("1"))); - } - - /** Check that parsing a mandatory free argument fails when no argument is specified. */ - public void testParseManadatoryFreeArgumentFailsNoArgument() throws Exception - { - // Create a command line parser for a mandatory free argument. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "1", "Test Option.", "test", "true" } - }); - - // Check that parsing fails when this mandatory free argument is missing. - boolean testPassed = false; - - try - { - // Parse a command line with this free argument not set. - Properties testProps = parser.parseCommandLine(new String[] {}); - } - catch (IllegalArgumentException e) - { - testPassed = true; - } - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("IllegalArgumentException not thrown for a missing mandatory option.", testPassed); - } - - /** Check that parsing a mandatory option fails when no option is set. */ - public void testParseMandatoryFailsNoOption() throws Exception - { - // Create a command line parser for a mandatory option. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "t", "Test Option.", "test", "true" } - }); - - // Check that parsing fails when this mandatory option is missing. - boolean testPassed = false; - - try - { - // Parse a command line with this option not set. - Properties testProps = parser.parseCommandLine(new String[] {}); - } - catch (IllegalArgumentException e) - { - testPassed = true; - } - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("IllegalArgumentException not thrown for a missing mandatory option.", testPassed); - } - - /** Check that parsing an option with no space between it and its argument works ok. */ - public void testParseOptionWithNoSpaceOk() throws Exception - { - // Create a command line parser for an option. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "t", "Test Option.", "test" } - }); - - // Parse a command line with this option set with no space. - Properties testProps = parser.parseCommandLine(new String[] { "-ttest" }); - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("The test option was not equal to \"test\" but was: " + testProps.get("t"), - "test".equals(testProps.get("t"))); - } - - /** Check that parsing an option with a space between it and its argument works ok. */ - public void testParseOptionWithSpaceOk() throws Exception - { - // Create a command line parser for an option. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "t", "Test Option.", "test" } - }); - - // Parse a command line with this option set with a space. - Properties testProps = parser.parseCommandLine(new String[] { "-t", "test" }); - - // Check that the resultant properties contains the correctly parsed option. - assertTrue("The test option was not equal to \"test\" but was: " + testProps.get("t"), - "test".equals(testProps.get("t"))); - } - - /** Check that parsing a single flag works ok. */ - public void testParseSingleFlagOk() throws Exception - { - // Create a command line parser for a single flag. - CommandLineParser parser = new CommandLineParser(new String[][] - { - { "t", "Test Flag." } - }); - - // Parse a command line with the single flag set. - Properties testProps = parser.parseCommandLine(new String[] { "-t" }); - - // Check that the flag is set in the parsed properties. - assertTrue("The t flag was not \"true\", it was: " + testProps.get("t"), "true".equals(testProps.get("t"))); - - // Reset the parser. - parser.reset(); - - // Parse a command line with the single flag not set. - testProps = parser.parseCommandLine(new String[] {}); - - // Check that the flag is cleared in the parsed properties. - assertTrue("The t flag was not \"false\", it was: " + testProps.get("t"), "false".equals(testProps.get("t"))); - } - - /** Check that parsing an unknown option works when unknowns not errors. */ - public void testParseUnknownOptionOk() throws Exception - { - // Create a command line parser for no flags or options - CommandLineParser parser = new CommandLineParser(new String[][] {}); - - // Check that parsing does not fail on an unknown flag. - try - { - parser.parseCommandLine(new String[] { "-t" }); - } - catch (IllegalArgumentException e) - { - fail("The parser threw an IllegalArgumentException on an unknown flag when errors on unkowns is off."); - } - } - - /** Check that parsing an unknown flag fails when unknowns are to be reported as errors. */ - public void testParseUnknownFlagFailsWhenUnknownsAreErrors() throws Exception - { - // Create a command line parser for no flags or options - CommandLineParser parser = new CommandLineParser(new String[][] {}); - - // Turn on fail on unknowns mode. - parser.setErrorsOnUnknowns(true); - - // Check that parsing fails on an unknown flag. - boolean testPassed = false; - - try - { - parser.parseCommandLine(new String[] { "-t" }); - } - catch (IllegalArgumentException e) - { - testPassed = true; - } - - assertTrue("IllegalArgumentException not thrown for an unknown flag when errors on unknowns mode is on.", - testPassed); - } - - /** Check that parsing an unknown option fails when unknowns are to be reported as errors. */ - public void testParseUnknownOptionFailsWhenUnknownsAreErrors() throws Exception - { - // Create a command line parser for no flags or options - CommandLineParser parser = new CommandLineParser(new String[][] {}); - - // Turn on fail on unknowns mode. - parser.setErrorsOnUnknowns(true); - - // Check that parsing fails on an unknown flag. - boolean testPassed = false; - - try - { - parser.parseCommandLine(new String[] { "-t", "test" }); - } - catch (IllegalArgumentException e) - { - testPassed = true; - } - - assertTrue("IllegalArgumentException not thrown for an unknown option when errors on unknowns mode is on.", - testPassed); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/util/CommandLineParser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/util/CommandLineParser.java new file mode 100644 index 0000000000..09478d4157 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/util/CommandLineParser.java @@ -0,0 +1,695 @@ +/* + * + * 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.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.regex.*; + +/** + * CommandLineParser provides a utility for specifying the format of a command line and parsing command lines to ensure + * that they fit their specified format. A command line is made up of flags and options, both may be refered to as + * options. A flag is an option that does not take an argument (specifying it means it has the value 'true' and not + * specifying it means it has the value 'false'). Options must take arguments but they can be set up with defaults so + * that they take a default value when not set. Options may be mandatory in wich case it is an error not to specify + * them on the command line. Flags are never mandatory because they are implicitly set to false when not specified. + * + *

    Some example command lines are: + * + *

      + *
    • This one has two options that expect arguments: + *
      + * cruisecontrol -configfile cruisecontrol.xml -port 9000
      + * 
      + *
    • This has one no-arg flag and two 'free' arguments: + *
      + * zip -r project.zip project/*
      + * 
      + *
    • This one concatenates multiple flags into a single block with only one '-': + *
      + * jar -tvf mytar.tar
      + * 
      + * + *

      The parsing rules are: + * + *

        + *
      1. Flags may be combined after a single '-' because they never take arguments. Normally such flags are single letter + * flags but this is only a convention and not enforced. Flags of more than one letter are usually specified on their own. + *
      2. Options expecting arguments must always be on their own. + *
      3. The argument to an option may be seperated from it by whitespace or appended directly onto the option. + *
      4. The argument to an option may never begin with a '-' character. + *
      5. All other arguments not beginning with a '-' character are free arguments that do not belong to any option. + *
      6. The second or later of a set of duplicate or repeated flags are ignored. + *
      7. Options are matched up to the shortest matching option. This is because of the possibility of having no space + * between an option and its argument. This rules out the possibility of using two options where one is an opening + * substring of the other. For example, the options "foo" and "foobar" cannot be used on the same command line because + * it is not possible to distinguish the argument "-foobar" from being the "foobar" option or the "foo" option with + * the "bar" argument. + *
      + * + *

      By default, unknown options are simply ignored if specified on the command line. This behaviour may be changed + * so that the parser reports all unknowns as errors by using the {@link #setErrorsOnUnknowns} method. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Accept a command line specification. + *
      Parse a command line into properties, validating it against its specification. + *
      Report all errors between a command line and its specification. + *
      Provide a formatted usage string for a command line. + *
      Provide a formatted options in force string for a command line. + *
      Allow errors on unknowns behaviour to be turned on or off. + *
      + */ +public class CommandLineParser +{ + /** Holds a mapping from command line option names to detailed information about those options. */ + private Map optionMap = new HashMap(); + + /** Holds a list of parsing errors. */ + private List parsingErrors = new ArrayList(); + + /** Holds the regular expression matcher to match command line options with. */ + private Matcher optionMatcher = null; + + /** Holds the parsed command line properties after parsing. */ + private Properties parsedProperties = null; + + /** Flag used to indicate that errors should be created for unknown options. False by default. */ + private boolean errorsOnUnknowns = false; + + /** + * Creates a command line options parser from a command line specification. This is passed to this constructor + * as an array of arrays of strings. Each array of strings specifies the command line for a single option. A static + * array may therefore easily be used to configure the command line parser in a single method call with an easily + * readable format. + * + *

      Each array of strings must be 2, 3, 4 or 5 elements long. If any of the last three elements are missing they + * are assumed to be null. The elements specify the following parameters: + *

        + *
      1. The name of the option without the leading '-'. For example, "file". To specify the format of the 'free' + * arguments use the option names "1", "2", ... and so on. + *
      2. The option comment. A line of text describing the usage of the option. For example, "The file to be processed." + *
      3. The options argument. This is a very short description of the argument to the option, often a single word + * or a reminder as to the arguments format. When this element is null the option is a flag and does not + * accept any arguments. For example, "filename" or "(unix | windows)" or null. The actual text specified + * is only used to print in the usage message to remind the user of the usage of the option. + *
      4. The mandatory flag. When set to "true" an option must always be specified. Any other value, including null, + * means that the option is mandatory. Flags are always mandatory (see class javadoc for explanation of why) so + * this is ignored for flags. + *
      5. A regular expression describing the format that the argument must take. Ignored if null. + *
      + *

      An example call to this constructor is: + * + *

      +     * CommandLineParser commandLine = new CommandLineParser(
      +     *     new String[][] {{"file", "The file to be processed. ", "filename", "true"},
      +     *                     {"dir", "Directory to store results in. Current dir used if not set.", "out dir"},
      +     *                     {"os", "Operating system EOL format to use.", "(windows | unix)", null, "windows\|unix"},
      +     *                     {"v", "Verbose mode. Prints information about the processing as it goes."},
      +     *                     {"1", "The processing command to run.", "command", "true", "add\|remove\|list"}});
      +     * 
      + * + * @param config The configuration as an array of arrays of strings. + */ + public CommandLineParser(String[][] config) + { + // Loop through all the command line option specifications creating details for each in the options map. + for (int i = 0; i < config.length; i++) + { + String[] nextOptionSpec = config[i]; + + addOption(nextOptionSpec[0], nextOptionSpec[1], (nextOptionSpec.length > 2) ? nextOptionSpec[2] : null, + (nextOptionSpec.length > 3) ? ("true".equals(nextOptionSpec[3]) ? true : false) : false, + (nextOptionSpec.length > 4) ? nextOptionSpec[4] : null); + } + } + + /** + * Lists all the parsing errors from the most recent parsing in a string. + * + * @return All the parsing errors from the most recent parsing. + */ + public String getErrors() + { + // Return the empty string if there are no errors. + if (parsingErrors.isEmpty()) + { + return ""; + } + + // Concatenate all the parsing errors together. + StringBuilder result = new StringBuilder(); + + for (String s : parsingErrors) + { + result.append(s); + } + + return result.toString(); + } + + /** + * Lists the properties set from the most recent parsing or an empty string if no parsing has been done yet. + * + * @return The properties set from the most recent parsing or an empty string if no parsing has been done yet. + */ + public String getOptionsInForce() + { + // Check if there are no properties to report and return and empty string if so. + if (parsedProperties == null) + { + return ""; + } + + // List all the properties. + StringBuilder result = new StringBuilder("Options in force:\n"); + + for (Map.Entry property : parsedProperties.entrySet()) + { + result.append(property.getKey()) + .append(" = ") + .append(property.getValue()) + .append('\n'); + } + + return result.toString(); + } + + /** + * Generates a usage string consisting of the name of each option and each options argument description and + * comment. + * + * @return A usage string for all the options. + */ + public String getUsage() + { + String result = "Options:\n"; + + // Print usage on each of the command line options. + for (CommandLineOption optionInfo : optionMap.values()) + { + result += + "-" + optionInfo.option + " " + ((optionInfo.argument != null) ? (optionInfo.argument + " ") : "") + + optionInfo.comment + "\n"; + } + + return result; + } + + /** + * Control the behaviour of the errors on unkowns reporting. When turned on this reports all unkowns options + * as errors. When turned off, all unknowns are simply ignored. + * + * @param errors The setting of the errors on unkown flag. True to turn it on. + */ + public void setErrorsOnUnknowns(boolean errors) + { + errorsOnUnknowns = errors; + } + + /** + * Parses a set of command line arguments into a set of properties, keyed by the argument flag. The free arguments + * are keyed by integers as strings starting at "1" and then "2", ... and so on. + * + *

      See the class level comment for a description of the parsing rules. + * + * @param args The command line arguments. + * + * @return The arguments as a set of properties. + * + * @throws IllegalArgumentException If the command line cannot be parsed against its specification. If this exception + * is thrown a call to {@link #getErrors} will provide a diagnostic of the command + * line errors. + */ + public Properties parseCommandLine(String[] args) throws IllegalArgumentException + { + Properties options = new Properties(); + + // Used to keep count of the current 'free' argument. + int free = 1; + + // Used to indicate that the most recently parsed option is expecting arguments. + boolean expectingArgs = false; + + // The option that is expecting arguments from the next element of the command line. + String optionExpectingArgs = null; + + // Used to indicate that the most recently parsed option is a duplicate and should be ignored. + boolean ignore = false; + + // Create the regular expression matcher for the command line options. + StringBuilder regexp = new StringBuilder("^("); + int optionsAdded = 0; + + for (Iterator i = optionMap.keySet().iterator(); i.hasNext();) + { + String nextOption = i.next(); + + // Check that the option is not a free argument definition. + boolean notFree = false; + + try + { + Integer.parseInt(nextOption); + } + catch (NumberFormatException e) + { + notFree = true; + } + + // Add the option to the regular expression matcher if it is not a free argument definition. + if (notFree) + { + regexp.append(nextOption) + .append(i.hasNext() ? "|" : ""); + optionsAdded++; + } + } + + // There has to be more that one option in the regular expression or else the compiler complains that the close + // cannot be nullable if the '?' token is used to make the matched option string optional. + regexp.append(')') + .append(((optionsAdded > 0) ? "?" : "")) + .append("(.*)"); + Pattern pattern = Pattern.compile(regexp.toString()); + + // Loop through all the command line arguments. + for (int i = 0; i < args.length; i++) + { + // Check if the next command line argument begins with a '-' character and is therefore the start of + // an option. + if (args[i].startsWith("-")) + { + // Extract the value of the option without the leading '-'. + String arg = args[i].substring(1); + + // Match up to the longest matching option. + optionMatcher = pattern.matcher(arg); + optionMatcher.matches(); + + String matchedOption = optionMatcher.group(1); + + // Match any argument directly appended onto the longest matching option. + String matchedArg = optionMatcher.group(2); + + // Check that a known option was matched. + if ((matchedOption != null) && !"".equals(matchedOption)) + { + // Get the command line option information for the matched option. + CommandLineOption optionInfo = optionMap.get(matchedOption); + + // Check if this option is expecting arguments. + if (optionInfo.expectsArgs) + { + // The option is expecting arguments so swallow the next command line argument as an + // argument to this option. + expectingArgs = true; + optionExpectingArgs = matchedOption; + + // In the mean time set this options argument to the empty string in case no argument is ever + // supplied. + // options.put(matchedOption, ""); + } + + // Check if the option was matched on its own and is a flag in which case set that flag. + if ("".equals(matchedArg) && !optionInfo.expectsArgs) + { + options.put(matchedOption, "true"); + } + // The option was matched as a substring with its argument appended to it or is a flag that is + // condensed together with other flags. + else if (!"".equals(matchedArg)) + { + // Check if the option is a flag and therefore is allowed to be condensed together + // with other flags. + if (!optionInfo.expectsArgs) + { + // Set the first matched flag. + options.put(matchedOption, "true"); + + // Repeat the longest matching process on the remainder but ensure that the remainder + // consists only of flags as only flags may be condensed together in this fashion. + do + { + // Match the remainder against the options. + optionMatcher = pattern.matcher(matchedArg); + optionMatcher.matches(); + + matchedOption = optionMatcher.group(1); + matchedArg = optionMatcher.group(2); + + // Check that an option was matched. + if (matchedOption != null) + { + // Get the command line option information for the next matched option. + optionInfo = optionMap.get(matchedOption); + + // Ensure that the next option is a flag or raise an error if not. + if (optionInfo.expectsArgs == true) + { + parsingErrors.add("Option " + matchedOption + " cannot be combined with flags.\n"); + } + + options.put(matchedOption, "true"); + } + // The remainder could not be matched against a flag it is either an unknown flag + // or an illegal argument to a flag. + else + { + parsingErrors.add("Illegal argument to a flag in the option " + arg + "\n"); + + break; + } + } + // Continue until the remainder of the argument has all been matched with flags. + while (!"".equals(matchedArg)); + } + // The option is expecting an argument, so store the unmatched portion against it + // as its argument. + else + { + // Check the arguments format is correct against any specified format. + checkArgumentFormat(optionInfo, matchedArg); + + // Store the argument against its option (regardless of its format). + options.put(matchedOption, matchedArg); + + // The argument to this flag has already been supplied to it. Do not swallow the + // next command line argument as an argument to this flag. + expectingArgs = false; + } + } + } + else // No matching option was found. + { + // Add this to the list of parsing errors if errors on unkowns is being used. + if (errorsOnUnknowns) + { + parsingErrors.add("Option " + matchedOption + " is not a recognized option.\n"); + } + } + } + // The command line argument did not being with a '-' so it is an argument to the previous flag or it + // is a free argument. + else + { + // Check if a previous flag is expecting to swallow this next argument as its argument. + if (expectingArgs) + { + // Get the option info for the option waiting for arguments. + CommandLineOption optionInfo = optionMap.get(optionExpectingArgs); + + // Check the arguments format is correct against any specified format. + checkArgumentFormat(optionInfo, args[i]); + + // Store the argument against its option (regardless of its format). + options.put(optionExpectingArgs, args[i]); + + // Clear the expecting args flag now that the argument has been swallowed. + expectingArgs = false; + optionExpectingArgs = null; + } + // This command line option is not an argument to any option. Add it to the set of 'free' options. + else + { + // Get the option info for the free option, if there is any. + CommandLineOption optionInfo = optionMap.get(Integer.toString(free)); + + if (optionInfo != null) + { + // Check the arguments format is correct against any specified format. + checkArgumentFormat(optionInfo, args[i]); + } + + // Add to the list of free options. + options.put(Integer.toString(free), args[i]); + + // Move on to the next free argument. + free++; + } + } + } + + // Scan through all the specified options to check that all mandatory options have been set and that all flags + // that were not set are set to false in the set of properties. + for (CommandLineOption optionInfo : optionMap.values()) + { + // Check if this is a flag. + if (!optionInfo.expectsArgs) + { + // Check if the flag is not set in the properties and set it to false if so. + if (!options.containsKey(optionInfo.option)) + { + options.put(optionInfo.option, "false"); + } + } + // Check if this is a mandatory option and was not set. + else if (optionInfo.mandatory && !options.containsKey(optionInfo.option)) + { + // Create an error for the missing option. + parsingErrors.add("Option -" + optionInfo.option + " is mandatory but not was not specified.\n"); + } + } + + // Check if there were any errors. + if (!parsingErrors.isEmpty()) + { + // Throw an illegal argument exception to signify that there were parsing errors. + throw new IllegalArgumentException(); + } + + // Convert any name/value pairs in the free arguments into properties in the parsed options. + options = takeFreeArgsAsProperties(options, 1); + + parsedProperties = options; + + return options; + } + + /** + * If a command line has been parsed, calling this method sets all of its parsed options into the specified properties. + */ + public void addCommandLineToProperties(Properties properties) + { + if (parsedProperties != null) + { + for (Object propKey : parsedProperties.keySet()) + { + String name = (String) propKey; + String value = parsedProperties.getProperty(name); + + properties.setProperty(name, value); + } + } + } + + /** + * Resets this command line parser after it has been used to parse a command line. This method will only need + * to be called to use this parser a second time which is not likely seeing as a command line is usually only + * specified once. However, it is exposed as a public method for the rare case where this may be done. + * + *

      Cleans the internal state of this parser, removing all stored errors and information about the options in + * force. + */ + public void reset() + { + parsingErrors = new ArrayList(); + parsedProperties = null; + } + + /** + * Adds the option to list of available command line options. + * + * @param option The option to add as an available command line option. + * @param comment A comment for the option. + * @param argument The text that appears after the option in the usage string. + * @param mandatory When true, indicates that this option is mandatory. + * @param formatRegexp The format that the argument must take, defined as a regular expression. + */ + protected void addOption(String option, String comment, String argument, boolean mandatory, String formatRegexp) + { + // Check if usage text has been set in which case this option is expecting arguments. + boolean expectsArgs = ((argument == null) || argument.equals("")) ? false : true; + + // Add the option to the map of command line options. + CommandLineOption opt = new CommandLineOption(option, expectsArgs, comment, argument, mandatory, formatRegexp); + optionMap.put(option, opt); + } + + /** + * Converts the free arguments into property declarations. After parsing the command line the free arguments + * are numbered from 1, such that the parsed properties contain values for the keys "1", "2", ... This method + * converts any free arguments declared using the 'name=value' syntax into properties with key 'name', value + * 'value'. + * + *

      For example the comand line: + *

      +     * ... debug=true
      +     * 
      + * + *

      After parsing has properties: + *

      [[1, debug=true]]
      + * + *

      After applying this method the properties are: + *

      [[1, debug=true], [debug, true]]
      + * + * @param properties The parsed command line properties. + * @param from The free argument index to convert to properties from. + * + * @return The parsed command line properties, with free argument name value pairs too. + */ + private Properties takeFreeArgsAsProperties(Properties properties, int from) + { + for (int i = from; true; i++) + { + String nextFreeArg = properties.getProperty(Integer.toString(i)); + + // Terminate the loop once all free arguments have been consumed. + if (nextFreeArg == null) + { + break; + } + + // Split it on the =, strip any whitespace and set it as a system property. + String[] nameValuePair = nextFreeArg.split("="); + + if (nameValuePair.length == 2) + { + properties.setProperty(nameValuePair[0], nameValuePair[1]); + } + } + + return properties; + } + + /** + * Checks the format of an argument to an option against its specified regular expression format if one has + * been set. Any errors are added to the list of parsing errors. + * + * @param optionInfo The command line option information for the option which is havings its argument checked. + * @param matchedArg The string argument to the option. + */ + private void checkArgumentFormat(CommandLineOption optionInfo, String matchedArg) + { + // Check if this option enforces a format for its argument. + if (optionInfo.argumentFormatRegexp != null) + { + Pattern pattern = Pattern.compile(optionInfo.argumentFormatRegexp); + Matcher argumentMatcher = pattern.matcher(matchedArg); + + // Check if the argument does not meet its required format. + if (!argumentMatcher.matches()) + { + // Create an error for this badly formed argument. + parsingErrors.add("The argument to option -" + optionInfo.option + " does not meet its required format.\n"); + } + } + } + + /** + * Extracts all name=value pairs from the command line, sets them all as system properties and also returns + * a map of properties containing them. + * + * @param args The command line. + * @param commandLine The command line parser. + * @param properties The properties object to inject all parsed properties into (optional may be null). + * + * @return A set of properties containing all name=value pairs from the command line. + */ + public static Properties processCommandLine(String[] args, CommandLineParser commandLine, Properties properties) + { + // Capture the command line arguments or display errors and correct usage and then exit. + Properties options = null; + + try + { + options = commandLine.parseCommandLine(args); + + // Add all the trailing command line options (name=value pairs) to system properties. They may be picked up + // from there. + commandLine.addCommandLineToProperties(properties); + } + catch (IllegalArgumentException e) + { + System.out.println(commandLine.getErrors()); + System.out.println(commandLine.getUsage()); + System.exit(1); + } + + return options; + } + + /** + * Holds information about a command line options. This includes what its name is, whether or not it is a flag, + * whether or not it is mandatory, what its user comment is, what its argument reminder text is and what its + * regular expression format is. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Hold details of a command line option. + *
      + */ + protected static class CommandLineOption + { + /** Holds the text for the flag to match this argument with. */ + public String option = null; + + /** Holds a string describing how to use this command line argument. */ + public String argument = null; + + /** Flag that determines whether or not this command line argument can take arguments. */ + public boolean expectsArgs = false; + + /** Holds a short comment describing what this command line argument is for. */ + public String comment = null; + + /** Flag that determines whether or not this is an mandatory command line argument. */ + public boolean mandatory = false; + + /** A regular expression describing what format the argument to this option muist have. */ + public String argumentFormatRegexp = null; + + /** + * Create a command line option object that holds specific information about a command line option. + * + * @param option The text that matches the option. + * @param expectsArgs Whether or not the option expects arguments. It is a flag if this is false. + * @param comment A comment explaining how to use this option. + * @param argument A short reminder of the format of the argument to this option/ + * @param mandatory Set to true if this option is mandatory. + * @param formatRegexp The regular expression that the argument to this option must meet to be valid. + */ + public CommandLineOption(String option, boolean expectsArgs, String comment, String argument, boolean mandatory, + String formatRegexp) + { + this.option = option; + this.expectsArgs = expectsArgs; + this.comment = comment; + this.argument = argument; + this.mandatory = mandatory; + this.argumentFormatRegexp = formatRegexp; + } + } +} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java index c4e744573f..f017c58c1e 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java @@ -27,7 +27,6 @@ import org.apache.qpid.AMQException; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQSession; import org.apache.qpid.url.URLSyntaxException; -import org.apache.qpid.util.CommandLineParser; import javax.jms.JMSException; import javax.jms.MessageProducer; @@ -257,12 +256,8 @@ public class PersistentTestManual public static void main(String[] args) { - PersistentTestManual test; - - Properties options = - CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][]{}), System.getProperties()); - - test = new PersistentTestManual(options); + Properties options = System.getProperties(); + PersistentTestManual test = new PersistentTestManual(options); try { test.test(); -- cgit v1.2.1