3. Your First AMPS Program¶
In this chapter, we will learn more about the structure and features of the AMPS Java client library, and build our first Java program using AMPS.
About the Client Library¶
The AMPS client is packaged as a single JAR file, amps_client.jar
.
You can find amps_client.jar
in the dist/lib
directory of the
AMPS Java client installation. Every Java application you build will
need to reference this JAR file, and the JAR file must be deployed along
with your application in order for your application to function
properly.
Connecting to AMPS¶
Let’s begin by writing a simple program that connects to an AMPS server and sends a single message to a topic:
import com.crankuptheamps.client.Client;
import com.crankuptheamps.client.exception.AMPSException;
public class TestPublisher
{
public static void main(String[] args) {
Client client = new Client("TestPublisher-Client");
try {
client.connect("tcp://127.0.0.1:9007/amps/json");
client.logon();
client.publish("messages", "{ \"message\" : \"Hello, world!\" } ");
}
catch (AMPSException aex) {
System.err.println("TestListener caught exception.");
} finally {
client.close();
}
}
}
Example 3.1: Connecting to AMPS
In the preceding Example 3.1, we show the entire program; but future examples will isolate one or more specific portions of the code. The next section describes how to build and run the application and explains the code in further detail.
Build and Run with a Java Command Line¶
To build this program, you can run the following javac
command,
substituting the path to the amps_client.jar
with the path where you
have installed the AMPS Java Client:
javac -classpath /opt/AMPS/api/client/java/dist/lib/amps_client.jar ./TestPublisher.java
TestPublisher.class
This will create the TestPublisher.class
file. To run the class file and send your first message to AMPS, you can
issue the following command:
java -cp .:/opt/AMPS/api/client/java/dist/lib/amps_client.jar TestPublisher
If the message is published successfully, there is no output to the console. We will demonstrate how to create a subscriber to receive messages in ` <#java-subscriptions-chapter>`_.
Build and Run in Eclipse¶
To include the JAR file in a standalone Eclipse environment:
- JAR files
amps_client.jar
amps_client.jar
Right-click the project to which you would like to addamps_client.jar
and selectProperties
to open theProperties
configuration window. - Click the
Java Build Path
item in the left menu, and then select theLibraries
tab. - Click the
Add External JARS
button and choose the location of youramps_client.jar
. - Click
OK
.
Your Eclipse build path should now include the amps_client.jar
.
To run the project:
- Select the menu option
Run # Run Configuration
, which opens theRun Configuration
window. - Right-click
Java Application
and selectNew
from the menu. - Fill in the
Name
field (for this example, you could use “Test Publisher”). - Click the
Search...
button for theMain
class field. - Select the
TestPublisher
class. - Finally, click the
Run
button to run the application.
If the message is published successfully, there is no output to the console. We will demonstrate how to create a subscriber to receive messages in Chapter 4.
Examining the Code¶
Let us now revisit the code we listed earlier.
/* The import statements add names into reference for convenience in typing later
* on in the code. These import the names from the AMPS namespaces:
* com.crankuptheamps.client.Client — contains the
* methods for interacting with AMPS
* com.crankuptheamps.client.exception.AMPSException — the
* package contains the exception classes thrown by AMPS when
* errors occur.
*/
import com.crankuptheamps.client.Client;
import com.crankuptheamps.client.exception.AMPSException;
public class TestPublisher
{
public static void main(String[] args) {
/* This line creates a new Client object. Client encapsulates a single
* connection to an AMPS server. Methods on Client allow for connecting,
* disconnecting, publishing, and subscribing to an AMPS server. The
* argument to the Client constructor, "TestPublisher-Client", is a name
* chosen by the client to identify itself to the server. Errors
* relating to this connection will be logged with reference to this
* name, and AMPS will use this name to help detect duplicate messages.
* AMPS enforces uniqueness for client names when a transaction log is
* configured, and it is good practice to always use unique client names.
*/
Client client = new Client("TestPublisher-Client");
// Here, we open a try block that concludes with catch (AMPSException aex).
try
{
/* This statement declares a connection to AMPS with the provided
* URI. The URI consists of the transport, the address, and the
* protocol to use for the AMPS connection. In this case, the
* transport is tcp, the address is 127.0.0.1:9007, and the protocol
* is amps. This connection will be used for JSON messages. Check
* with the person who manages the AMPS instance to get the connection
* string to use for your programs.
*/
client.connect("tcp://127.0.0.1:9007/amps/json");
/* The AMPS logon() command connects to AMPS and creates a named
* connection. If we had provided logon credentials in the URI, the
* command would pass those credentials to AMPS. Without credentials,
* the client logs on to AMPS anonymously. AMPS versions 5.0 and
* later require a logon() command in the default configuration.
*
* This version of logon uses the DefaultAuthenticator, which provides
* credentials from the URI, if any are present. To use a different
* authentication scheme, implement an Authenticator.
*/
client.logon();
client.publish("messages", "{ \"message\" : \"Hello, world!\" } ");
}
// All caught exceptions in AMPS derive from AMPSException.
catch (AMPSException aex)
{
System.err.println("TestListener caught exception.");
}
/* We close out the example with a finally block that closes the
* Client connection and releases all accompanying resources, making
* the connection eligible for garbage collection.
*/
finally
{
client.close();
}
}
}
Client Names¶
AMPS uses the name of the client as a session identifier and as part of the identifier for a message. For this reason, when a transaction log is enabled in the AMPS instance (that is, when the instance is recording a sequence of publishes and attempting to eliminate duplicate publishes), an AMPS instance will only allow one application with a given client name to connect to the instance.
When a transaction log is present, AMPS requires the Client Name for a publisher to be:
- Unique within a set of replicated AMPS instances
- Consistent from invocation to invocation if the publisher will be publishing the same logical stream of messages
If publishers do not meet this contract (for example, if the publisher changes its name and publishes the same messages, or if a different publisher uses the same session name), message loss or duplication can happen.
60East recommends always using consistent, unique client names. For example, the client name could be formed by combining the application name, an identifier for the host system, and the id of the user running the application. A strategy like this provides a name that will be different for different users or on different systems, but consistent for instances of the application that should be treated as equivalent to the AMPS system.
Likewise, if a publisher is sending a completely independent stream of messages (for example, a microservice that sends a different, unrelated sequences of messages each time it connects to AMPS), there is no need for a publisher to retain the same name each time it starts. However, if a publisher is resuming a stream of messages (such as happens when using a file-backed publish store), that publisher must use the same client name, since the publisher is resuming the session.
Connection Strings¶
The AMPS clients use connection strings to determine the server, port, transport, and protocol to use to connect to AMPS. When the connection point in AMPS accepts multiple message types, the connection string also specifies the precise message type to use for this connection. Connection strings have a number of elements.
Figure 3.1: elements of a connection string
As shown in the figure above, connection strings have the following elements:
Transport defines the network used to send and receive messages from AMPS. In this case, the transport is
tcp
. For connections to transports that use the Secure Sockets Layer (SSL), usetcps
.Host address defines the destination on the network where the AMPS instance receives messages. The format of the address is dependent on the transport. For
tcp
andtcps
, the address consists of a host name and port number. In this case, the host address islocalhost:9007
.Protocol sets the format in which AMPS receives commands from the client. Most code uses the default
amps
protocol, which sends header information in JSON format. AMPS supports the ability to develop custom protocols as extension modules, and AMPS also supports legacy protocols for backward compatibility.MessageType specifies the message type that this connection uses. This component of the connection string is required if the protocol accepts multiple message types and the transport is configured to accept multiple message types. If the protocol does not accept multiple message types, this component of the connection string is optional, and defaults to the message type specified in the transport.
Legacy protocols such as
fix
,nvfix
andxml
only accept a single message type, and therefore do not require or accept a message type in the connection string.
As an example, a connection string such as
tcp://localhost:9007/amps/json
would work for programs connecting from the local host to a
Transport
configured as follows:
<AMPSConfig>
...
<!-- This transport accepts any known message type for the instance: the
client must specify the message type. -->
<Transport>
<Name>any-tcp</Name>
<Type>tcp</Type>
<InetAddr>9007</InetAddr>
<Protocol>amps</Protocol>
</Transport>
...
</AMPSConfig>
See the AMPS Configuration Guide for more information on configuring transports.
Providing Credentials in a Connection String¶
When using the default authenticator, the AMPS clients support the standard format for including a username and password in a URI, as shown below:
tcp://user:password@host:port/protocol/message_type
When provided in this form, the default authenticator provides the username and password specified in the URI. If you have implemented another authenticator, that authenticator controls how passwords are provided to the AMPS server.
Connection Parameters¶
When specifying a URI for connection to an AMPS server, you may specify a number of transport-specific options in the parameters section of the URIconnection parameters. Here is an example:
tcp://localhost:9007/amps/json?tcp_nodelay=true&tcp_sndbuf=100000
In this example, we have specified the AMPS instance on localhost
,
port 9007
, connecting to a transport that uses the amps
protocol
and sending JSON messages. We have also set two parameters,
tcp_nodelay
tcp_nodelay, a Boolean (true/false) parameter, and
tcp_sndbuf
tcp_sndbuf, an integer parameter. Multiple parameters
may be combined to finely tune settings available on the transport.
Normally, you’ll want to stick with the defaults on your platform, but
there may be some cases where experimentation and fine-tuning will yield
higher or more efficient performance.
AMPS supports the value of tcp
in the connection string for TCP/IP
connections, and the value of tcps
in the connection string for SSL
encrypted connections.
IPv6 connections¶
Starting with version 5.3.3.0, the AMPS Client supports creating connections over both IPv4 and IPv6 protocols if supported by the underlying Operating System.
By Default, the AMPS client will prefer to resolve host names to ipv4 addresses,
but this behavior can be adjusted by supplying the ip_protocol_prefer
transport
option, described below.
Transport options¶
The following transport options are available for TCP connections:
bind |
(ip address) Sets the interface to bind the outgoing socket to. starting with version 5.3.3.0, ipv4 and ipv6 addresses are fully supported for use with this parameter. |
tcp_rcvbuf |
(integer) Sets the socket receive buffer size. This defaults to the
system default size. (On Linux, you can find the system default size
in /proc/sys/net/core/rmem_default .) |
tcp_sndbuf |
(integer) Sets the socket send buffer size. This defaults to the
system default size. (On Linux, you can find the system default size
in /proc/sys/net/core/wmem_default .) |
tcp_nodelay |
(boolean) Enables or disables the TCP_NODELAY setting on the
socket. By default TCP_NODELAY is disabled. |
tcp_linger |
(integer) Enables and sets the SO_LINGER value for
the socket. By default, SO_LINGER is enabled with a value of
10 , which specifies that the socket will linger for 10 seconds. |
tcp_keepalive |
(boolean) . Enables or disables the SO_KEEPALIVE
value for the socket. The default value for this option is true. |
ip_protocol_prefer |
(string) Influence the IP protocol to prefer during DNS resolution of the host. If a DNS entry of the preferred protocol can not be found, the other non-preferred protocol will then be tried. If this parameter is not set, the default will be to prefer ipv4. If an explicit ipv4 address or ipv6 ip address is provided as the host, the format of the ip address is used to determine the IP protocol used and this setting has no effect. Supported Values:
This parameter is available starting with version 5.3.3.0. |
AMPS additional logon options¶
The connection string can also be used to pass logon parameters to AMPS. AMPS supports the following additional logon option:
pretty |
Provide formatted representations of binary messages rather than the original message contents. |
Next Steps¶
You are now able to develop and deploy an application in Java that publishes messages to AMPS. In the following chapters, you will learn how to subscribe to messages, use content filters, work with SOW caches, and fine-tune messages that you send.