Files

353 lines
11 KiB
Java

import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import javax.management.ObjectName;
/**
* Sonic Management Application API helper (same restart as SMC).
*
* Uses reflection so this file compiles with Java 8 without Sonic jars on the
* compile classpath. At runtime SonicHome\\lib must provide:
* mgmt_client / mfcontext / sonic_Client (etc.)
*
* Flow (CX Messenger Management Application API):
* Hashtable ConnectionURLs/DefaultUser/DefaultPassword
* -> JMSConnectorAddress / JMSConnectorClient.connect
* -> MFProxyFactory.createAgentProxy(connector, ObjectName)
* -> IAgentProxy.restart()
*
* ObjectName: {domain}.{container}:ID=AGENT
*
* Compile: javac --release 8 SonicMfContainerTool.java
*/
public final class SonicMfContainerTool
{
public static void main(String[] args)
{
try
{
Args a = Args.parse(args);
if (a.command == null)
{
fail("Usage: SonicMfContainerTool ping|list|restart --domain D --url U --user U [--password P] [--container C] [--timeout SEC]");
return;
}
if (isBlank(a.domain) || isBlank(a.url) || isBlank(a.user))
{
fail("domain, url und user sind Pflicht.");
return;
}
if ("restart".equals(a.command) && isBlank(a.container))
{
fail("restart erfordert --container.");
return;
}
long timeoutMs = Math.max(5_000L, a.timeoutSec * 1000L);
Object connector = connect(a.url, a.user, a.password, timeoutMs);
try
{
if ("ping".equals(a.command))
{
ping(connector, a.domain);
}
else if ("list".equals(a.command))
{
list(connector, a.domain);
}
else if ("restart".equals(a.command))
{
restart(connector, a.domain, a.container);
}
else
{
fail("Unbekannter Befehl: " + a.command);
}
}
finally
{
try
{
connector.getClass().getMethod("disconnect").invoke(connector);
}
catch (Exception ignore)
{
/* ignore */
}
}
}
catch (Throwable t)
{
Throwable root = t;
while (root.getCause() != null && root.getCause() != root)
{
root = root.getCause();
}
fail(root.getClass().getName() + ": " + root.getMessage());
}
}
private static Object connect(String url, String user, String password, long timeoutMs)
throws Exception
{
Hashtable env = new Hashtable();
env.put("ConnectionURLs", url);
env.put("DefaultUser", user);
env.put("DefaultPassword", password == null ? "" : password);
Class addressCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorAddress");
Object address = addressCl.getConstructor(new Class[] { Hashtable.class }).newInstance(new Object[] { env });
Class clientCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorClient");
Object connector = clientCl.getConstructor(new Class[] {}).newInstance(new Object[] {});
Method connect = null;
Method[] methods = clientCl.getMethods();
for (int i = 0; i < methods.length; i++)
{
Method m = methods[i];
if ("connect".equals(m.getName()) && m.getParameterTypes().length == 2)
{
connect = m;
break;
}
}
if (connect == null)
{
fail("JMSConnectorClient.connect(address, timeout) nicht gefunden.");
return null;
}
Class[] pts = connect.getParameterTypes();
Object timeoutArg;
if (pts[1] == Long.TYPE || pts[1] == Long.class)
{
timeoutArg = Long.valueOf(timeoutMs);
}
else if (pts[1] == Integer.TYPE || pts[1] == Integer.class)
{
timeoutArg = Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs));
}
else
{
timeoutArg = Long.valueOf(timeoutMs);
}
connect.invoke(connector, new Object[] { address, timeoutArg });
System.out.println("INFO:Connected url=" + url + " user=" + user);
return connector;
}
private static void ping(Object connector, String domain) throws Exception
{
Set names = queryAgents(connector);
int matched = 0;
if (names != null)
{
for (Iterator it = names.iterator(); it.hasNext(); )
{
ObjectName on = (ObjectName) it.next();
if (extractContainer(on, domain) != null)
{
matched++;
}
}
}
System.out.println("OK:MfApiPing domain=" + domain + " agents=" + matched);
}
private static void list(Object connector, String domain) throws Exception
{
Set names = queryAgents(connector);
int count = 0;
if (names != null)
{
for (Iterator it = names.iterator(); it.hasNext(); )
{
ObjectName on = (ObjectName) it.next();
String container = extractContainer(on, domain);
if (container != null)
{
System.out.println(container);
count++;
}
}
}
if (count == 0)
{
System.out.println("WARN:KeineAgentContainer Domain=" + domain);
}
System.out.println("OK:List count=" + count);
}
private static void restart(Object connector, String domain, String container) throws Exception
{
String shortName = shortContainer(container);
ObjectName on = resolveAgentObjectName(connector, domain, shortName);
System.out.println("INFO:ObjectName=" + on);
Class factoryCl = Class.forName("com.sonicsw.mf.mgmtapi.runtime.MFProxyFactory");
Method create = factoryCl.getMethod("createAgentProxy", new Class[] {
Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorClient"),
ObjectName.class
});
Object agent = create.invoke(null, new Object[] { connector, on });
String stateBefore = safeState(agent);
System.out.println("INFO:StateBefore=" + stateBefore);
agent.getClass().getMethod("restart").invoke(agent);
System.out.println("OK:RestartInvoked container=" + shortName + " domain=" + domain
+ " stateBefore=" + stateBefore);
}
private static Set queryAgents(Object connector) throws Exception
{
Method query = connector.getClass().getMethod("queryNames", new Class[] {
ObjectName.class, javax.management.QueryExp.class
});
return (Set) query.invoke(connector, new Object[] { new ObjectName("*:ID=AGENT"), null });
}
private static ObjectName resolveAgentObjectName(Object connector, String domain, String container)
throws Exception
{
ObjectName preferred = new ObjectName(domain + "." + container + ":ID=AGENT");
Method query = connector.getClass().getMethod("queryNames", new Class[] {
ObjectName.class, javax.management.QueryExp.class
});
Set exact = (Set) query.invoke(connector, new Object[] { preferred, null });
if (exact != null && !exact.isEmpty())
{
return (ObjectName) exact.iterator().next();
}
Set names = queryAgents(connector);
if (names != null)
{
for (Iterator it = names.iterator(); it.hasNext(); )
{
ObjectName on = (ObjectName) it.next();
String c = extractContainer(on, domain);
if (c != null && c.equalsIgnoreCase(container))
{
return on;
}
}
}
return preferred;
}
private static String extractContainer(ObjectName on, String domain)
{
if (on == null || isBlank(domain))
{
return null;
}
String jmxDomain = on.getDomain();
if (jmxDomain == null)
{
return null;
}
String prefix = domain + ".";
if (jmxDomain.regionMatches(true, 0, prefix, 0, prefix.length()))
{
return jmxDomain.substring(prefix.length());
}
return null;
}
private static String shortContainer(String container)
{
if (container == null)
{
return "";
}
int dot = container.indexOf('.');
if (dot >= 0 && dot < container.length() - 1)
{
return container.substring(dot + 1);
}
return container;
}
private static String safeState(Object agent)
{
try
{
Object s = agent.getClass().getMethod("getStateString").invoke(agent);
return s == null ? "?" : String.valueOf(s);
}
catch (Throwable t)
{
return "?";
}
}
private static void fail(String message)
{
System.err.println("ERROR:" + message);
System.exit(2);
}
private static boolean isBlank(String s)
{
return s == null || s.trim().length() == 0;
}
private static final class Args
{
String command;
String domain;
String url;
String user;
String password;
String container;
int timeoutSec = 120;
static Args parse(String[] args)
{
Args a = new Args();
if (args == null || args.length == 0)
{
return a;
}
a.command = args[0].toLowerCase();
for (int i = 1; i < args.length; i++)
{
String key = args[i];
if (!key.startsWith("--") || i + 1 >= args.length)
{
continue;
}
String val = args[++i];
if ("--domain".equals(key)) a.domain = val;
else if ("--url".equals(key)) a.url = val;
else if ("--user".equals(key)) a.user = val;
else if ("--password".equals(key)) a.password = val;
else if ("--container".equals(key)) a.container = val;
else if ("--timeout".equals(key))
{
try { a.timeoutSec = Integer.parseInt(val); } catch (Exception ignore) { /* keep */ }
}
}
if (isBlank(a.password))
{
String env = System.getenv("ESB_SONIC_PASSWORD");
if (!isBlank(env))
{
a.password = env;
}
}
return a;
}
}
}