package org.kannel.admin;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
/**
* Implementation of KannelAdmin using Kannel's HTTP administration interface
*
* @author Garth Patil <garthpatil@gmail.com>
*/
public class HttpKannelAdmin
implements KannelAdmin
{
/**
* @param baseUrl The base URL of the Kannel HTTP administration interface
* @param password The admin-password
*/
public HttpKannelAdmin(URL baseUrl, String password) {
this.baseUrl = baseUrl;
this.password = password;
}
private URL baseUrl;
private String password;
private URL getUrl(String method, boolean requiresPassword) throws Exception
{
if (requiresPassword) method = addPassword(method);
return this.baseUrl.toURI().resolve(method).toURL();
}
private String addPassword(String method)
{
StringBuffer o = new StringBuffer(method);
if (!method.contains("?")) o.append("?").append("password=").append(this.password);
else o.append("&").append("password=").append(this.password);
return o.toString();
}
/**
* status
* Get the current status of the gateway in a text version. Tells the current state
* (see above) and total number of messages relied and queuing in the system right now.
* Also lists the total number of smsbox and wapbox connections. No password required,
* unless status-password set, in which case either that or main admin password must be
* supplied.
* @return A Status containing conveniences to access the XML.
*/
public Status getStatus() throws AdminException
{
try {
InputStream is = getUrl("status.xml", true).openStream();
Status s = Status.parse(is);
is.close();
return s;
} catch (Exception e) {
throw new AdminException("Error executing status", e);
}
}
/**
* store-status
* Get the current content of the store queue of the gateway in a text version. No
* password required, unless status-password set, in which case either that or main
* admin password must be supplied.
* @return A StoreStatus containing conveniences to access the XML.
*/
public StoreStatus getStoreStatus() throws AdminException
{
try {
InputStream is = getUrl("store-status.xml", true).openStream();
StoreStatus s = StoreStatus.parse(is);
is.close();
return s;
} catch (Exception e) {
throw new AdminException("Error executing store-status", e);
}
}
/**
* suspend
* Set Kannel state as 'suspended' (see above). Password required.
*/
public void suspend() throws AdminException
{
try {
String response = getContent(getUrl("suspend", true));
if (response.contains("Already susptended")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing suspend", e);
}
}
/**
* isolate
* Set Kannel state as 'isolated' (see above). Password required.
*/
public void isolate() throws AdminException
{
try {
String response = getContent(getUrl("isolate", true));
if (response.contains("Already isolated")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing isolate", e);
}
}
/**
* resume
* Set Kannel state as 'running' if it is suspended or isolated. Password required.
*/
public void resume() throws AdminException
{
try {
String response = getContent(getUrl("resume", true));
if (response.contains("Already running")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing resume", e);
}
}
/**
* shutdown
* Bring down the gateway, by setting state to 'shutdown'. After a shutdown is initiated,
* there is no other chance to resume normal operation. However, 'status' command still
* works. Password required. If shutdown is sent for a second time, the gateway is forced
* down, even if it has still messages in queue.
*/
public void shutdown() throws AdminException
{
try {
String response = getContent(getUrl("shutdown", true));
} catch (Exception e) {
throw new AdminException("Error executing shutdown", e);
}
}
/**
* flush-dlr
* If Kannel state is 'suspended' this will flush all queued DLR messages in the current
* storage space. Password required.
*/
public void flushDLR() throws AdminException
{
try {
String response = getContent(getUrl("flush-dlr", true));
if (response.contains("before trying to flush DLR queue")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing flush-dlr", e);
}
}
/**
* start-smsc
* Re-start a single SMSC link. Password required. Additionally the smsc parameter must
* be given to identify which smsc-admin-id should be re-started. The configuration
* for the SMSC link is re-read from disk before the action is performed.
* @param smsc The smsc-id
*/
public void startSMSC(String smsc) throws AdminException
{
try {
StringBuffer query = new StringBuffer("start-smsc");
query.append("?").append("smsc=").append(smsc);
String response = getContent(getUrl(query.toString(), true));
if (response.contains("Could not re-start smsc-id") ||
response.contains("SMSC id not given")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing start-smsc", e);
}
}
/**
* stop-smsc
* Shutdown a single SMSC link. Password required. Additionally the smsc parameter must
* be given (see above).
* @param smsc The smsc-id
*/
public void stopSMSC(String smsc) throws AdminException
{
try {
StringBuffer query = new StringBuffer("stop-smsc");
query.append("?").append("smsc=").append(smsc);
String response = getContent(getUrl(query.toString(), true));
if (response.contains("Could not shut down smsc-id") ||
response.contains("SMSC id not given")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing stop-smsc", e);
}
}
/**
* add-smsc
* Adds an SMSC link previously removed or created after the service was started. Password
* required. Additionally the smsc parameter must be given (see above).
* @param smsc The smsc-id
*/
public void addSMSC(String smsc) throws AdminException
{
try {
StringBuffer query = new StringBuffer("add-smsc");
query.append("?").append("smsc=").append(smsc);
String response = getContent(getUrl(query.toString(), true));
if (response.contains("Could not add smsc-id") ||
response.contains("SMSC id not given")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing add-smsc", e);
}
}
/**
* remove-smsc
* Removes an existing SMSC link. Password required. Additionally the smsc parameter
* must be given (see above). If you want a permanent removal, you should also remove
* the entry from the configuration file or it will be recreated after a service restart.
* @param smsc The smsc-id
*/
public void removeSMSC(String smsc) throws AdminException
{
try {
StringBuffer query = new StringBuffer("remove-smsc");
query.append("?").append("smsc=").append(smsc);
String response = getContent(getUrl(query.toString(), true));
if (response.contains("Could not remove smsc-id") ||
response.contains("SMSC id not given")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing remove-smsc", e);
}
}
/**
* restart
* Re-start whole bearerbox, hence all SMSC links. Password required. Beware that you
* loose the smsbox connections in such a case.
*/
public void restart() throws AdminException
{
try {
String response = getContent(getUrl("restart", true));
if (response.contains("Trying harder to restart")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing restart", e);
}
}
/**
* loglevel
* Set Kannel log-level of log-files while running. This allows you to change the current
* log-level of the log-files on the fly.
* @param logLevel The new log level to set
*/
public void logLevel(int logLevel) throws AdminException
{
try {
StringBuffer query = new StringBuffer("log-level");
query.append("?").append("level=").append(Integer.toString(logLevel));
String response = getContent(getUrl(query.toString(), true));
if (response.contains("New level not given")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing log-level", e);
}
}
/**
* reload-lists
* Re-loads the 'white-list' and 'black-list' URLs provided in the core group. This
* allows Kannel to keep running while the remote lists change and signal bearerbox
* to re-load them on the fly.
*/
public void reloadLists() throws AdminException
{
try {
String response = getContent(getUrl("reload-lists", true));
if (response.contains("Could not re-load lists")) throw new AdminException(response.trim());
} catch (Exception e) {
throw new AdminException("Error executing reload-lists", e);
}
}
private static String getContent(URL u) throws IOException
{
// InputStream is = u.openStream();
// Need to set HTTP accept header to text only. Java's default includes HTML, which
// causes Kannel to auto-detect and send HTML.
URLConnection uc = u.openConnection();
uc.setRequestProperty("Accept", "text/plain");
uc.connect();
InputStream is = uc.getInputStream();
String response = parseStreamToString(is, -1);
is.close();
return response;
}
private static String parseStreamToString(InputStream is, int maxSize) throws IOException
{
BufferedReader bf = new BufferedReader(new InputStreamReader(is));
StringBuffer o = new StringBuffer();
String line = null;
while ((line = bf.readLine()) != null && ((maxSize < 0) || (o.length() < maxSize))) {
o.append(line + "\n");
}
bf.close();
return o.toString();
}
/**
* A command line client for testing.
* usage: HttpKannelAdmin <host> <password> <method> <opt:param>
*/
public static void main(String[] argv)
{
org.apache.log4j.BasicConfigurator.configure();
if (argv.length < 3) {
System.err.println("usage: HttpKannelAdmin <host> <password> <method> <opt:param>");
System.exit(1);
}
try {
KannelAdmin admin = new HttpKannelAdmin(new URL(argv[0]), argv[1]);
String method = argv[2];
String param = null;
if (argv.length == 4) param = argv[3];
if (method.equals("status")) System.out.println(admin.getStatus().getGateway().xmlText());
if (method.equals("store-status")) System.out.println(admin.getStoreStatus());
if (method.equals("suspend")) admin.suspend();
if (method.equals("isolate")) admin.isolate();
if (method.equals("resume")) admin.resume();
if (method.equals("shutdown")) admin.shutdown();
if (method.equals("flush-dlr")) admin.flushDLR();
if (method.equals("start-smsc")) admin.startSMSC(param);
if (method.equals("stop-smsc")) admin.stopSMSC(param);
if (method.equals("add-smsc")) admin.addSMSC(param);
if (method.equals("remove-smsc")) admin.removeSMSC(param);
if (method.equals("restart")) admin.restart();
if (method.equals("log-level")) admin.logLevel(Integer.parseInt(param));
if (method.equals("reload-lists")) admin.reloadLists();
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}