CLI Admin API
Introduction
CLI may be activated out of a Java program for programmatic administration. This administration API offers a simple but powerful instrument for the administration of SwiftMQ router networks.
The administration takes place by performing any CLI command via an executeCommand
method of CLI. All property values and entities of routers of the network can be retrieved. Furthermore, it is possible to wait for the availability of certain routers or to receive notification events.
Preparation
The following import needs to exist to use the CLI Admin API:
import com.swiftmq.admin.cli.*;
If router events should be received, the following further import statement is needed:
import com.swiftmq.admin.cli.event.*;
CLI requires a QueueConnection
in stopped mode (default on creation). The user of this QueueConnection
needs to have full administration rights of the routers to be administered. This is the case when placing send/receive grants to the queue swiftmqmgmt
of the respective routers.
Creation of a QueueConnection:
QueueConnection connection = null;
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.swiftmq.jndi.InitialContextFactoryImpl");
env.put(Context.PROVIDER_URL,"smqp://localhost:4001/timeout=10000");
InitialContext ctx = new InitialContext(env);
QueueConnectionFactory connectionFactory =
(QueueConnectionFactory)ctx.lookup("QueueConnectionFactory");
connection = connectionFactory.createQueueConnection();
ctx.close();
} catch (Exception e)
{
System.out.println(e);
System.exit(-1);
}
After that CLI may be created:
CLI cli = null;
try {
cli = new CLI(connection);
} catch (Exception e)
{
System.out.println(e);
System.exit(-1);
}
At construction, CLI produces several sessions and starts the connection.
Waiting for Routers
After creating CLI it receives asynchronous availability notifications from the network routers. A router may not be administered until it is available. One can wait for the availability to administer a specific router. This is done by calling the method waitForRouter
. This method exists in two versions, one without and one with a timeout. The one without timeout waits until the router is available. The one with timeout waits until the availability or until timeout. If the router is already available at the call of the method, it returns straight away.
Example without timeout:
cli.waitForRouter("router1");
Example with timeout:
cli.waitForRouter("router1", 20000); // max 20 secs
Router Listener
Besides the synchronous waitForRouter
methods a RouterListener
may also be registered. In this case, CLI informs these listeners asynchronous by router availabilities.
Example:
cli.addRouterListener(new RouterListener()
{
public void onRouterEvent(String routerName, boolean available)
{
System.out.println("Router '"+routerName+"' is `+(available?"AVAILABLE":"UNAVAILABLE"));
}
});
Getting available Routers
CLI may be requested at any time, which routers are currently available. This is done by the method getAvailableRouters
. The method returns a string array with router names.
Example:
String[] availableRouters = cli.getAvailableRouters();
Getting the actual Router
The router mentioned at the last sr
command is the current one. It may be requested by getActRouter
. If no sr
command has been set, null is passed back.
Example:
System.out.println("Act Router: `+cli.getActRouter());
Getting the actual Context
The context, given at the last cc
command, is the current one. It may be requested by getActContext. If no cc
command has been set, null
is passed back. After an sr
command, /
is the current context.
Example:
System.out.println("Act Context: `+cli.getActContext());
Getting Context Entities
After setting the actual context with cc
, it is possible to get the actual entity names defined whithin this context.
Example:
cli.executeCommand("sr router1");
// getting all defined queues
cli.executeCommand("cc /sys$queuemanager/queues");
String[] allQueueNames = cli.getContextEntities();
// getting all defined users
cli.executeCommand("cc /sys$authentication/users");
String[] allUserNames = cli.getContextEntities();
Executing CLI Commands
The execution of CLI commands takes place by the method executeCommand
, which has the corresponding CLI command as a parameter. Here it is to be taken into account that the command mustn't deliver a result, otherwise, a CLIException
is thrown. Thus, commands like lc
, ar
, show template
are unauthorized.
Example:
cli.waitForRouter("router1");
try {
cli.executeCommand("sr router1");
cli.executeCommand("cc /sys$queuemanager/queues");
cli.executeCommand("new mynewqueue cache.size 1000");
cli.executeCommand("save");
} catch (CLIException e)
{
processError(e);
}
This example creates a new queue and saves the configuration.
Getting Property Values
After setting oneself in a context by cc
, any property in this context may be readout. This is done by the method getContextProperty
. The name of the property is given as a parameter. The current value is given back as String type. If the property is unknown within the current context, a CLIException
is thrown. If the property value is null
, null
will be passed back.
Example:
cli.executeCommand("sr router1");
cli.executeCommand("cc /sys$queuemanager/queues/mynewqueue");
int cacheSize = Integer.parseInt(cli.getContextProperty("cache.size"));
Closing CLI
With the completion of the use of CLI Admin API, it should be closed by close()
. Hereby, all resources used by CLI are released. The QueueConnection
given with the construction is not closed and remains in the started mode.
Example:
cli.close();
Exception Listener
In order to recognize if the QueueConnection
committed to CLI got lost, a JMS ExceptionListener
needs to be registered at the QueueConnection
and it needs to be responded to accordingly.
Transparent Reconnect
It is possible to configure JMS connection factories to automatically and transparent reconnect to the same or (in case SwiftMQ HA Router is used) to another router instance. If CLI is created with a connection from a connection factory configured for transparent reconnect, CLI will reconnect as well and will restore its internal state. However, it does not restore the router, set with the last sr
command nor the last CLI context, set with a cc
command. This is the responsibility of the application that uses CLI admin API.
The CLI methods throw a CLIReconnectedException
(extends CLIException
) if a command fails and a reconnect happened in the meantime (so the reason for the exception is actually a reconnect). An application must catch CLIReconnectedException
and must restore the last router and context by issuing the appropriate sr
and cc
commands (a call to waitForRouter
may also be required). Thereafter it must issue the failed command again.
The following example polls the free and total memory properties of the management tree and acts on a CLIReconnectedException
:
// Setup the CLI context
private static void setUp()
{
try
{
cli.waitForRouter("router1");
cli.executeCommand("sr router1");
cli.executeCommand("cc .env/router-memory-list/router1");
} catch (CLIException e)
{
}
}
// Get a value from a property
private static String getValue(String propName)
{
for (;;)
{
try
{
return cli.getContextProperty(propName);
} catch (CLIReconnectedException e)
{
setUp();
} catch (CLIException e)
{
e.printStackTrace();
}
}
}
// And here's the main loop...
public static void main(String[] args)
{
// Lookup connection factory, create connection, create CLI
// (excluded here)
// First time context set up
setUp();
// Continuously poll and print memory status of the router
for (; ;)
{
System.out.println("Free: ` + getValue("free-memory") + ` Total: ` + getValue("total-memory"));
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
}
}
}
Example
The SwiftMQ distribution contains an example AdminClient.java
within the directory samples/cli
. This is an easy administration client, that reads CLI commands by System.in
and executes them.