This file details various configuration options for the client, such as how to configure and create a JNDI InitialContext, the syntax for its related configuration, and various URI options that can be set when defining a ConnectionFactory.
Applications use a JNDI InitialContext, itself obtained from an InitialContextFactory, to look up JMS objects such as ConnectionFactory. The Qpid JMS client provides an implementation of the InitialContextFactory in class org.apache.qpid.jms.jndi.JmsInitialContextFactory. This may be configured and used in three main ways:
Via jndi.properties file on the Java Classpath.
By including a file named jndi.properties on the Classpath and setting the java.naming.factory.initial property to value org.apache.qpid.jms.jndi.JmsInitialContextFactory, the Qpid InitialContextFactory implementation will be discovered when instantiating InitialContext object.
javax.naming.Context ctx = new javax.naming.InitialContext();
The particular ConnectionFactory, Queue and Topic objects you wish the context to contain are configured using properties (the syntax for which is detailed below) either directly within the jndi.properties file, or in a separate file which is referenced in jndi.properties using the java.naming.provider.url property.
Via system properties.
By setting the java.naming.factory.initial system property to value org.apache.qpid.jms.jndi.JmsInitialContextFactory, the Qpid InitialContextFactory implementation will be discovered when instantiating InitialContext object.
javax.naming.Context ctx = new javax.naming.InitialContext();
The particular ConnectionFactory, Queue and Topic objects you wish the context to contain are configured as properties in a file, which is passed using the java.naming.provider.url system property. The syntax for these properties is detailed below.
Programmatically using an environment Hashtable.
The InitialContext may also be configured directly by passing an environment during creation:
Hashtable<Object, Object> env = new Hashtable<Object, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
javax.naming.Context context = new javax.naming.InitialContext(env);
The particular ConnectionFactory, Queue and Topic objects you wish the context to contain are configured as properties (the syntax for which is detailed below), either directly within the environment Hashtable, or in a separate file which is referenced using the java.naming.provider.url property within the environment Hashtable.
The property syntax used in the properties file or environment Hashtable is as follows:
The property values which which constitute the connection URI, queue name, or topic name can also utilise simple ${variable} or ${variable:-default} expansion, with these resolved in order from system properties, environment variables, or the properties file / environment Hashtable. For more details of the Connection URI, see the next section.
As an example, consider the following properties used to define a ConnectionFactory, Queue, and Topic:
connectionfactory.myFactoryLookup = amqp://localhost:5672
queue.myQueueLookup = queueA
topic.myTopicLookup = topicA
These objects could then be looked up from a Context as follows:
ConnectionFactory factory = (ConnectionFactory) context.lookup("myFactoryLookup");
Queue queue = (Queue) context.lookup("myQueueLookup");
Topic topic = (Topic) context.lookup("myTopicLookup");
The basic format of the clients Connection URI is as follows:
amqp[s]://hostname:port[?option=value[&option2=value...]]
or for WebSocket connections:
amqpws[s]://hostname:port[/path][?option=value[&option2=value...]]
Where the amqps and amqpwss scheme is specified to use SSL/TLS, the hostname segment from the URI can be used by the JVM for the TLS SNI (Server Name Indication) extension in order to communicate the desired server hostname during a TLS handshake. The SNI extension will be automatically included if a Fully Qualified name (e.g myhost.mydomain) is specified, but not when an unqualified name (e.g myhost) or bare IP address are used.
The client can be configured with a number of different settings using the URI while defining the ConnectionFactory, these are detailed in the following sections.
The options apply to the behaviour of the JMS objects such as Connection, Session, MessageConsumer and MessageProducer.
The Prefetch Policy controls how many messages the remote peer can send to the client and be held in a prefetch buffer for each consumer instance.
The Redelivery Policy controls how redelivered messages are handled on the client.
The MessageID Policy controls the type of the Message ID assigned to messages sent from the client.
The Presettle Policy controls when a producer or consumer instance will be configured to use AMQP presettled messaging semantics.
The Deserialization Policy provides a means of controlling which types are trusted to be deserialized from the object stream while retrieving the body from an incoming JMS ObjectMessage composed of serialized Java Object content. By default all types are trusted during attempt to deserialize the body. The default Deserialization Policy object provides URI options that allow specifying a allow list and a deny list of Java class or package names.
jms.deserializationPolicy.allowList A comma separated list of class/package names that should be allowed when deserializing the contents of a JMS ObjectMessage, unless overridden by the deny list. The names in this list are not pattern values, the exact class or package name must be configured, e.g "java.util.Map" or "java.util". Package matches include sub-packages. Default is to allow all. jms.deserializationPolicy.denyList A comma separated list of class/package names that should be rejected when deserializing the contents of a JMS ObjectMessage. The names in this list are not pattern values, the exact class or package name must be configured, e.g "java.util.Map" or "java.util". Package matches include sub-packages. Default is to prevent none.
When connected to a remote using plain TCP these options configure the behaviour of the underlying socket. These options are appended to the connection URI along with the other configuration options, for example:
amqp://localhost:5672?jms.clientID=foo&transport.connectTimeout=30000
The complete set of TCP Transport options is listed below:
The SSL Transport extends the TCP Transport and is enabled using the amqps URI scheme. Because the SSL Transport extends the functionality of the TCP based Transport all the TCP Transport options are valid on an SSL Transport URI.
A simple SSL/TLS based client URI is shown below:
amqps://myhost.mydomain:5671
The complete set of SSL Transport options is listed below:
The WebSocket (WS) Transport extends the TCP and SSL Transports to provide both unsecured and secured Websocket connectivity and is enabled using the amqpws and amqpwss URI schemes. The unsecured WS Transport extends the basic TCP transport which means all the normal TCP Transport configuration options also apply to the WS Transport. Similarly the WSS Transport extends the SSL Transport which means both the TCP and SSL Transport options can be applied to configure it.
A simple WS[S] based client URI is shown below:
amqpws[s]://myhost.mydomain:5671/[optional-path]
The WS Transport can be configured to add additional HTTP Headers during the WebSocket upgrade request using URI options for each HTTP header and value to be added, an example is shown below:
amqpws[s]://myhost.mydomain:5671/[optional-path]?transport.ws.httpHeader.<Header>=<Value>
These options apply to the behaviour of certain AMQP functionality.
With failover enabled the client can reconnect to another server automatically when connection to the current server is lost for some reason. The failover URI is always initiated with the failover prefix and a list of URIs for the server(s) is contained inside a set of parentheses. The "jms." options are applied to the overall failover URI, outside the parentheses, and affect the JMS Connection object for its lifetime.
The URI for failover looks something like the following:
failover:(amqp://host1:5672,amqp://host2:5672)?jms.clientID=foo&failover.maxReconnectAttempts=20
The individual broker details within the parentheses can use the "transport." or "amqp." options defined earlier, with these being applied as each host is connected to:
failover:(amqp://host1:5672?amqp.option=value,amqp://host2:5672?transport.option=value)?jms.clientID=foo
The complete set of configuration options for failover is listed below:
The failover URI also supports defining 'nested' options as a means of specifying AMQP and transport option values applicable to all the individual nested broker URI's, which can be useful to avoid repetition. This is accomplished using the same "transport." and "amqp." URI options outlined earlier for a non-failover broker URI but prefixed with failover.nested.. For example, to apply the same value for the amqp.vhost option to every broker connected to you might have a URI like:
failover:(amqp://host1:5672,amqp://host2:5672)?jms.clientID=foo&failover.nested.amqp.vhost=myhost
The client has an optional Discovery module, which provides a customised failover layer where the broker URIs to connect to are not given in the initial URI, but discovered as the client operates via associated discovery agents. There are currently two discovery agent implementations, a file watcher that loads URIs from a file, and a multicast listener that works with ActiveMQ 5 brokers which have been configured to broadcast their broker addresses for listening clients.
The general set of failover related options when using discovery are the same as those detailed earlier, with the main prefix updated from failover. to discovery., and with the 'nested' options prefix used to supply URI options common to all the discovered broker URIs bring updated from failover.nested. to discovery.discovered. For example, without the agent URI details, a general discovery URI might look like:
discovery:(<agent-uri>)?discovery.maxReconnectAttempts=20&discovery.discovered.jms.clientID=foo
To use the file watcher discovery agent, utilise an agent URI of the form:
discovery:(file:///path/to/monitored-file?updateInterval=60000)
The URI options for the file watcher discovery agent are listed below:
To use the multicast discovery agent with an ActiveMQ 5 broker, utilise an agent URI of the form:
discovery:(multicast://default?group=default)
Note that the use of default as the host in the multicast agent URI above is a special value (that is substituted by the agent with the default "239.255.2.3:6155"). You may change this to specify the actual IP and port in use with your multicast configuration.
The URI options for the multicast discovery agent are listed below:
SSL connections can be configured to use a native OpenSSL implementation which can provide increased performance. To use this support the transport useOpenSSL option must be enabled and the OpenSSL support libraries must be configured on the classpath. The client tests make use of an uber jar containing static libraries for multiple platforms based on Google's boringssl project libraries. To include this dependency in your own project you might include the maven dependency as follows:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>${netty-tcnative-version}</version>
</dependency>
The Netty project provides other options to choose from when using OpenSSL libraries which are documented on the Netty site. https://netty.io/wiki/forked-tomcat-native.html
The client makes use of the SLF4J API, allowing users to select a particular logging implementation based on their needs by supplying a SLF4J 'binding', such as slf4j-log4j in order to use Log4J. More details on SLF4J are available from http://www.slf4j.org/.
The client uses Logger names residing within the org.apache.qpid.jms hierarchy, which you can use to configure a logging implementation based on your needs.
When debugging some issues, it may sometimes be useful to enable additional protocol trace logging from the Qpid Proton AMQP 1.0 library. There are two options to achieve this:
The client can perform distributed tracing of message production and consumption using an OpenTracing implementation.
When tracing is enabled, upon producing messages a Span is created for the AMQP delivery process, with the delivery outcome logged on it upon completion. When consuming messages, an active Span is created while the onMessage method of a MessageListener is called. For synchronous receive calls, a Span is created and finished internally while returning a Message. This is also the case for any messages expired before delivery or which exceed the configured redelivery policy.
There are two ways of enabling this support:
Configure the client via URI option to utilise the GlobalTracer independently set by the application.
The tracing implementation can be enabled using the jms.tracing URI option:
amqp://localhost:5672?jms.tracing=opentracing
The application must create a Tracer and register it as the GlobalTracer. An overview of doing this would be:
io.opentracing.Tracer tracer = ...;
io.opentracing.util.GlobalTracer.registerIfAbsent(tracer);
If no registration is performed, the GlobalTracer acts as a no-op Tracer.
Set a JmsTracer instance to use directly on the JmsConnectionFactory object.
io.opentracing.Tracer tracer = ...;
org.apache.qpid.jms.tracing.JmsTracer jmsTracer =
org.apache.qpid.jms.tracing.opentracing.OpenTracingTracerFactory.create(tracer);
JmsConnectionFactory connectionFactory = ...;
connectionFactory.setTracer(jmsTracer);
This method of enabling tracing overrides the URI configuration option if also set.
In order to perform tracing a suitable OpenTracing implementation must be provided by the application (along with the io.opentracing:opentracing-api and io.opentracing:opentracing-util dependencies, should the tracing implementation not provide them).
An example distributed tracing system would be Jaeger. The related application dependency to utilise it would be:
<dependency>
<groupId>io.jaegertracing</groupId>
<artifactId>jaeger-client</artifactId>
<version>${jaeger-version}</version>
</dependency>
The client supports two additional session acknowledgement modes beyond the standard JMS specification modes.
In this mode messages must be acknowledged individually by the application via the Message#acknowledge() method used when the Session is in CLIENT_ACKNOWLEDGE mode. Unlike with CLIENT_ACKNOWLEDGE mode only the target message will be acknowledged, all other delivered messages remain un-acknowledged. The integer value used to activate this mode is 101.
connection.createSession(false, 101);
In this mode messages are accepted at the server before being dispatched to the client, and no acknowledgement is performed by the client. The client supports two integer values to activate this mode, 100 and 257.
connection.createSession(false, 100);
The client can be configured to authenticate using Kerberos when used with an appropriately configured server. To do so, you must:
Configure the client to use the GSSAPI mechanism for SASL authentication using the amqp.saslMechanisms URI option, e.g:
amqp://myhost:5672?amqp.saslMechanisms=GSSAPI
failover:(amqp://myhost:5672?amqp.saslMechanisms=GSSAPI)
Set the java.security.auth.login.config system property to the path of a JAAS Login Configuration file containing appropriate configuration for a Kerberos LoginModule, e.g:
-Djava.security.auth.login.config=/path/to/login.config
An example login.config configuration file might look like the following:
amqp-jms-client {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true;
};
The precise configuration used will depend on how you wish the credentials to be established for the connection, and the particular LoginModule in use. For details of the Sun/Oracle Krb5LoginModule, see https://docs.oracle.com/javase/8/docs/jre/api/security/jaas/spec/com/sun/security/auth/module/Krb5LoginModule.html. For details of the IBM Java 8 Krb5LoginModule, see https://www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.security.api.doc/jgss/com/ibm/security/auth/module/Krb5LoginModule.html.
It is possible to configure the LoginModule to establish the credentials to use for the Kerberos process, such as specifying a Principal and whether to use an existing ticket cache or keytab. If however the LoginModule configuration does not provide means to establish all necessary credentials, it may then request and be passed the username and/or password values from the client Connection object if they were either supplied when creating the Connection using the ConnectionFactory or previously configured via its URI options.
Note that Kerberos is only only supported for authentication purposes. Use SSL/TLS connections for encryption.
The following URI options can be used to influence the Kerberos authentication process:
Similar to the "amqp." and "transport." options detailed previously, these options must be specified on a per-host basis or as all-host nested options in a failover URI.
Apache Qpid, Messaging built on AMQP; Copyright © 2015 The Apache Software Foundation; Licensed under the Apache License, Version 2.0; Apache Qpid, Qpid, Qpid Proton, Proton, Apache, the Apache feather logo, and the Apache Qpid project logo are trademarks of The Apache Software Foundation; All other marks mentioned may be trademarks or registered trademarks of their respective owners