689 lines
17 KiB
Java
689 lines
17 KiB
Java
import java.lang.reflect.Method;
|
|
import java.util.Hashtable;
|
|
import java.util.Iterator;
|
|
import java.util.Set;
|
|
|
|
import javax.management.ObjectName;
|
|
|
|
/**
|
|
* Sonic-MfApi-Hilfsprogramm.
|
|
*
|
|
* Befehle:
|
|
* validate - Anmeldung + lesender Container-Zugriff
|
|
* restart - Container neu starten (stop/restart)
|
|
* list - Container der Domain auflisten
|
|
*
|
|
* javac -source 8 -target 8 SonicMfContainerTool.java
|
|
*/
|
|
public final class SonicMfContainerTool
|
|
{
|
|
public static final String TOOL_VERSION =
|
|
"2026-07-29-validate-restart-list";
|
|
|
|
public static void main(String[] args)
|
|
{
|
|
info("ToolVersion=" + TOOL_VERSION);
|
|
|
|
try
|
|
{
|
|
Args parsedArguments = Args.parse(args);
|
|
|
|
if (!"validate".equals(parsedArguments.command)
|
|
&& !"restart".equals(parsedArguments.command)
|
|
&& !"list".equals(parsedArguments.command))
|
|
{
|
|
fail(
|
|
"Usage: SonicMfContainerTool "
|
|
+ "<validate|restart|list> "
|
|
+ "--domain D "
|
|
+ "--url U "
|
|
+ "--user U "
|
|
+ "[--container C] "
|
|
+ "[--timeout SEC]");
|
|
return;
|
|
}
|
|
|
|
if (isBlank(parsedArguments.domain)
|
|
|| isBlank(parsedArguments.url)
|
|
|| isBlank(parsedArguments.user))
|
|
{
|
|
fail("domain, url und user sind Pflicht.");
|
|
return;
|
|
}
|
|
|
|
boolean needsContainer =
|
|
"validate".equals(parsedArguments.command)
|
|
|| "restart".equals(parsedArguments.command);
|
|
|
|
if (needsContainer
|
|
&& isBlank(parsedArguments.container))
|
|
{
|
|
fail("container ist Pflicht fuer validate/restart.");
|
|
return;
|
|
}
|
|
|
|
if (isBlank(parsedArguments.password))
|
|
{
|
|
fail(
|
|
"Das Sonic-Kennwort wurde nicht ueber "
|
|
+ "ESB_SONIC_PASSWORD bereitgestellt.");
|
|
return;
|
|
}
|
|
|
|
long timeoutMilliseconds = Math.max(
|
|
5_000L,
|
|
parsedArguments.timeoutSec * 1000L);
|
|
|
|
Object connector = connect(
|
|
parsedArguments.url,
|
|
parsedArguments.user,
|
|
parsedArguments.password,
|
|
timeoutMilliseconds);
|
|
|
|
try
|
|
{
|
|
if ("list".equals(parsedArguments.command))
|
|
{
|
|
listContainers(
|
|
connector,
|
|
parsedArguments.domain);
|
|
}
|
|
else if ("validate".equals(
|
|
parsedArguments.command))
|
|
{
|
|
validateConnection(
|
|
connector,
|
|
parsedArguments.domain,
|
|
parsedArguments.container);
|
|
}
|
|
else
|
|
{
|
|
restart(
|
|
connector,
|
|
parsedArguments.domain,
|
|
parsedArguments.container);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
disconnect(connector);
|
|
}
|
|
}
|
|
catch (Throwable throwable)
|
|
{
|
|
Throwable root = rootOf(throwable);
|
|
String message = root.getMessage();
|
|
|
|
if (message == null)
|
|
{
|
|
message = "(keine Detailmeldung)";
|
|
}
|
|
|
|
fail(
|
|
root.getClass().getName()
|
|
+ ": "
|
|
+ message);
|
|
}
|
|
}
|
|
|
|
private static void listContainers(
|
|
Object connector,
|
|
String domain)
|
|
throws Exception
|
|
{
|
|
Method queryNamesMethod =
|
|
findMethod(
|
|
connector.getClass(),
|
|
"queryNames",
|
|
new Class[]
|
|
{
|
|
ObjectName.class,
|
|
javax.management.QueryExp.class
|
|
});
|
|
|
|
if (queryNamesMethod == null)
|
|
{
|
|
throw new IllegalStateException(
|
|
"queryNames(ObjectName, QueryExp) wurde nicht gefunden.");
|
|
}
|
|
|
|
ObjectName pattern =
|
|
new ObjectName("*:ID=AGENT");
|
|
|
|
Object rawResult = queryNamesMethod.invoke(
|
|
connector,
|
|
new Object[]
|
|
{
|
|
pattern,
|
|
null
|
|
});
|
|
|
|
if (!(rawResult instanceof Set))
|
|
{
|
|
throw new IllegalStateException(
|
|
"queryNames lieferte kein Set.");
|
|
}
|
|
|
|
Set names = (Set) rawResult;
|
|
String domainPrefix = domain + ".";
|
|
int count = 0;
|
|
|
|
System.out.println("OK:ContainerListBegin");
|
|
|
|
Iterator iterator = names.iterator();
|
|
|
|
while (iterator.hasNext())
|
|
{
|
|
Object entry = iterator.next();
|
|
|
|
if (!(entry instanceof ObjectName))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ObjectName objectName = (ObjectName) entry;
|
|
String canonical = objectName.getCanonicalName();
|
|
|
|
if (canonical == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Erwartet: domain.containerName:ID=AGENT
|
|
if (!canonical.regionMatches(
|
|
true,
|
|
0,
|
|
domainPrefix,
|
|
0,
|
|
domainPrefix.length()))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int colon = canonical.indexOf(':');
|
|
|
|
if (colon <= domainPrefix.length())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
String containerName =
|
|
canonical.substring(
|
|
domainPrefix.length(),
|
|
colon);
|
|
|
|
if (isBlank(containerName))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
System.out.println(
|
|
"CONTAINER="
|
|
+ containerName.trim());
|
|
|
|
count++;
|
|
}
|
|
|
|
System.out.println(
|
|
"OK:ContainerListEnd count="
|
|
+ count
|
|
+ " domain="
|
|
+ domain
|
|
+ " tool="
|
|
+ TOOL_VERSION);
|
|
|
|
System.out.flush();
|
|
}
|
|
|
|
private static Object connect(
|
|
String url,
|
|
String user,
|
|
String password,
|
|
long timeoutMilliseconds)
|
|
throws Exception
|
|
{
|
|
Hashtable environment = new Hashtable();
|
|
|
|
environment.put("ConnectionURLs", url);
|
|
environment.put("DefaultUser", user);
|
|
environment.put("DefaultPassword", password);
|
|
|
|
Class addressClass = Class.forName(
|
|
"com.sonicsw.mf.jmx.client.JMSConnectorAddress");
|
|
|
|
Object address = addressClass
|
|
.getConstructor(
|
|
new Class[]
|
|
{
|
|
Hashtable.class
|
|
})
|
|
.newInstance(
|
|
new Object[]
|
|
{
|
|
environment
|
|
});
|
|
|
|
Class clientClass = Class.forName(
|
|
"com.sonicsw.mf.jmx.client.JMSConnectorClient");
|
|
|
|
Object connector = clientClass
|
|
.getConstructor(new Class[] {})
|
|
.newInstance(new Object[] {});
|
|
|
|
trySetTimeout(connector, timeoutMilliseconds);
|
|
|
|
Method connectMethod = findConnect(clientClass);
|
|
|
|
if (connectMethod == null)
|
|
{
|
|
throw new IllegalStateException(
|
|
"JMSConnectorClient.connect(...) wurde nicht gefunden.");
|
|
}
|
|
|
|
Class[] parameterTypes =
|
|
connectMethod.getParameterTypes();
|
|
|
|
if (parameterTypes.length == 2)
|
|
{
|
|
connectMethod.invoke(
|
|
connector,
|
|
new Object[]
|
|
{
|
|
address,
|
|
boxTimeout(
|
|
parameterTypes[1],
|
|
timeoutMilliseconds)
|
|
});
|
|
}
|
|
else
|
|
{
|
|
connectMethod.invoke(
|
|
connector,
|
|
new Object[]
|
|
{
|
|
address
|
|
});
|
|
}
|
|
|
|
return connector;
|
|
}
|
|
|
|
private static void validateConnection(
|
|
Object connector,
|
|
String domain,
|
|
String container)
|
|
throws Exception
|
|
{
|
|
String shortName = shortContainer(container);
|
|
|
|
ObjectName objectName = new ObjectName(
|
|
domain + "." + shortName + ":ID=AGENT");
|
|
|
|
info("ValidatingObjectName=" + objectName);
|
|
|
|
Method getMBeanInfoMethod =
|
|
findMethod(
|
|
connector.getClass(),
|
|
"getMBeanInfo",
|
|
new Class[]
|
|
{
|
|
ObjectName.class
|
|
});
|
|
|
|
if (getMBeanInfoMethod == null)
|
|
{
|
|
throw new IllegalStateException(
|
|
"getMBeanInfo(ObjectName) wurde nicht gefunden.");
|
|
}
|
|
|
|
Object result = getMBeanInfoMethod.invoke(
|
|
connector,
|
|
new Object[]
|
|
{
|
|
objectName
|
|
});
|
|
|
|
if (result == null)
|
|
{
|
|
throw new IllegalStateException(
|
|
"Die Container-MBean konnte nicht gelesen werden.");
|
|
}
|
|
|
|
System.out.println(
|
|
"OK:ConnectionValidated"
|
|
+ " container="
|
|
+ shortName
|
|
+ " domain="
|
|
+ domain
|
|
+ " tool="
|
|
+ TOOL_VERSION);
|
|
|
|
System.out.flush();
|
|
}
|
|
|
|
private static void restart(
|
|
Object connector,
|
|
String domain,
|
|
String container)
|
|
throws Exception
|
|
{
|
|
String shortName = shortContainer(container);
|
|
|
|
ObjectName objectName = new ObjectName(
|
|
domain + "." + shortName + ":ID=AGENT");
|
|
|
|
info("ObjectName=" + objectName);
|
|
|
|
StringBuffer attempts = new StringBuffer();
|
|
String[] operations = new String[]
|
|
{
|
|
"stop",
|
|
"restart"
|
|
};
|
|
|
|
for (int index = 0; index < operations.length; index++)
|
|
{
|
|
String operation = operations[index];
|
|
|
|
try
|
|
{
|
|
info("Trying MBean.invoke(" + operation + ")");
|
|
invokeNoArgs(connector, objectName, operation);
|
|
okRestart("MBean." + operation, shortName, domain);
|
|
return;
|
|
}
|
|
catch (Throwable throwable)
|
|
{
|
|
Throwable root = rootOf(throwable);
|
|
String line =
|
|
"MBean."
|
|
+ operation
|
|
+ " => "
|
|
+ root.getClass().getName()
|
|
+ ": "
|
|
+ root.getMessage();
|
|
|
|
warn(line);
|
|
attempts.append(line).append('\n');
|
|
}
|
|
}
|
|
|
|
throw new IllegalStateException(
|
|
"Neustart fehlgeschlagen:\n" + attempts.toString());
|
|
}
|
|
|
|
private static void invokeNoArgs(
|
|
Object connector,
|
|
ObjectName objectName,
|
|
String operation)
|
|
throws Exception
|
|
{
|
|
Method invokeMethod =
|
|
findMethod(
|
|
connector.getClass(),
|
|
"invoke",
|
|
new Class[]
|
|
{
|
|
ObjectName.class,
|
|
String.class,
|
|
Object[].class,
|
|
String[].class
|
|
});
|
|
|
|
if (invokeMethod == null)
|
|
{
|
|
throw new IllegalStateException(
|
|
"invoke(...) wurde nicht gefunden.");
|
|
}
|
|
|
|
invokeMethod.invoke(
|
|
connector,
|
|
new Object[]
|
|
{
|
|
objectName,
|
|
operation,
|
|
null,
|
|
null
|
|
});
|
|
}
|
|
|
|
private static void okRestart(
|
|
String path,
|
|
String container,
|
|
String domain)
|
|
{
|
|
System.out.println(
|
|
"OK:RestartInvoked"
|
|
+ " path="
|
|
+ path
|
|
+ " container="
|
|
+ container
|
|
+ " domain="
|
|
+ domain
|
|
+ " tool="
|
|
+ TOOL_VERSION);
|
|
|
|
System.out.flush();
|
|
}
|
|
|
|
private static void disconnect(Object connector)
|
|
{
|
|
try
|
|
{
|
|
Method method =
|
|
findMethod(
|
|
connector.getClass(),
|
|
"disconnect",
|
|
new Class[] {});
|
|
|
|
if (method != null)
|
|
{
|
|
method.invoke(connector, new Object[] {});
|
|
}
|
|
}
|
|
catch (Throwable ignored)
|
|
{
|
|
}
|
|
}
|
|
|
|
private static void trySetTimeout(
|
|
Object connector,
|
|
long timeoutMilliseconds)
|
|
{
|
|
try
|
|
{
|
|
Method method =
|
|
findMethod(
|
|
connector.getClass(),
|
|
"setTimeout",
|
|
new Class[]
|
|
{
|
|
Long.TYPE
|
|
});
|
|
|
|
if (method != null)
|
|
{
|
|
method.invoke(
|
|
connector,
|
|
new Object[]
|
|
{
|
|
Long.valueOf(timeoutMilliseconds)
|
|
});
|
|
}
|
|
}
|
|
catch (Throwable ignored)
|
|
{
|
|
}
|
|
}
|
|
|
|
private static Method findConnect(Class clientClass)
|
|
{
|
|
Method[] methods = clientClass.getMethods();
|
|
|
|
for (int index = 0; index < methods.length; index++)
|
|
{
|
|
Method method = methods[index];
|
|
|
|
if (!"connect".equals(method.getName()))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Class[] types = method.getParameterTypes();
|
|
|
|
if (types.length == 1 || types.length == 2)
|
|
{
|
|
return method;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static Method findMethod(
|
|
Class type,
|
|
String name,
|
|
Class[] parameterTypes)
|
|
{
|
|
try
|
|
{
|
|
return type.getMethod(name, parameterTypes);
|
|
}
|
|
catch (NoSuchMethodException exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static Object boxTimeout(
|
|
Class parameterType,
|
|
long timeoutMilliseconds)
|
|
{
|
|
if (parameterType == Integer.TYPE
|
|
|| parameterType == Integer.class)
|
|
{
|
|
long seconds =
|
|
Math.max(1L, timeoutMilliseconds / 1000L);
|
|
|
|
if (seconds > Integer.MAX_VALUE)
|
|
{
|
|
seconds = Integer.MAX_VALUE;
|
|
}
|
|
|
|
return Integer.valueOf((int) seconds);
|
|
}
|
|
|
|
return Long.valueOf(timeoutMilliseconds);
|
|
}
|
|
|
|
private static String shortContainer(String container)
|
|
{
|
|
String value = container.trim();
|
|
int colon = value.indexOf(':');
|
|
|
|
if (colon > 0)
|
|
{
|
|
value = value.substring(0, colon);
|
|
}
|
|
|
|
int dot = value.lastIndexOf('.');
|
|
|
|
if (dot >= 0 && dot < value.length() - 1)
|
|
{
|
|
value = value.substring(dot + 1);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
private static Throwable rootOf(Throwable throwable)
|
|
{
|
|
Throwable current = throwable;
|
|
|
|
while (current.getCause() != null
|
|
&& current.getCause() != current)
|
|
{
|
|
current = current.getCause();
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
private static boolean isBlank(String value)
|
|
{
|
|
return value == null || value.trim().length() == 0;
|
|
}
|
|
|
|
private static void info(String message)
|
|
{
|
|
System.err.println("INFO: " + message);
|
|
}
|
|
|
|
private static void warn(String message)
|
|
{
|
|
System.err.println("WARN: " + message);
|
|
}
|
|
|
|
private static void fail(String message)
|
|
{
|
|
System.err.println("ERROR: " + message);
|
|
System.exit(1);
|
|
}
|
|
|
|
private static final class Args
|
|
{
|
|
private String command;
|
|
private String domain;
|
|
private String url;
|
|
private String user;
|
|
private String password;
|
|
private String container;
|
|
private int timeoutSec = 60;
|
|
|
|
private static Args parse(String[] args)
|
|
{
|
|
Args result = new Args();
|
|
|
|
if (args == null || args.length == 0)
|
|
{
|
|
fail("Kein Befehl angegeben.");
|
|
}
|
|
|
|
result.command = args[0];
|
|
result.password =
|
|
System.getenv("ESB_SONIC_PASSWORD");
|
|
|
|
for (int index = 1; index < args.length; index++)
|
|
{
|
|
String token = args[index];
|
|
|
|
if ("--domain".equals(token) && index + 1 < args.length)
|
|
{
|
|
result.domain = args[++index];
|
|
}
|
|
else if ("--url".equals(token) && index + 1 < args.length)
|
|
{
|
|
result.url = args[++index];
|
|
}
|
|
else if ("--user".equals(token) && index + 1 < args.length)
|
|
{
|
|
result.user = args[++index];
|
|
}
|
|
else if ("--container".equals(token)
|
|
&& index + 1 < args.length)
|
|
{
|
|
result.container = args[++index];
|
|
}
|
|
else if ("--timeout".equals(token)
|
|
&& index + 1 < args.length)
|
|
{
|
|
result.timeoutSec =
|
|
Integer.parseInt(args[++index]);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|