597 lines
15 KiB
Java
597 lines
15 KiB
Java
import java.lang.reflect.Method;
|
|
import java.util.Hashtable;
|
|
|
|
import javax.management.ObjectName;
|
|
|
|
/**
|
|
* Sonic-MfApi-Hilfsprogramm.
|
|
*
|
|
* Befehle:
|
|
* validate - Anmeldung + lesender Container-Zugriff
|
|
* restart - Container neu starten (stop/restart)
|
|
*
|
|
* javac -source 8 -target 8 SonicMfContainerTool.java
|
|
*/
|
|
public final class SonicMfContainerTool
|
|
{
|
|
public static final String TOOL_VERSION =
|
|
"2026-07-29-restart-empty-params";
|
|
|
|
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))
|
|
{
|
|
fail(
|
|
"Usage: SonicMfContainerTool "
|
|
+ "<validate|restart> "
|
|
+ "--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;
|
|
}
|
|
|
|
if (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 ("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 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();
|
|
|
|
// 1) restart (bevorzugt)
|
|
// 2) stop + start (Fallback; manche Agenten haben kein restart)
|
|
String[][] plans = new String[][]
|
|
{
|
|
{ "restart" },
|
|
{ "stop", "start" }
|
|
};
|
|
|
|
for (int planIndex = 0; planIndex < plans.length; planIndex++)
|
|
{
|
|
String[] operations = plans[planIndex];
|
|
|
|
try
|
|
{
|
|
for (int index = 0; index < operations.length; index++)
|
|
{
|
|
String operation = operations[index];
|
|
info("Trying MBean.invoke(" + operation + ")");
|
|
invokeNoArgs(connector, objectName, operation);
|
|
}
|
|
|
|
okRestart(
|
|
"MBean." + joinOps(operations),
|
|
shortName,
|
|
domain);
|
|
return;
|
|
}
|
|
catch (Throwable throwable)
|
|
{
|
|
Throwable root = rootOf(throwable);
|
|
String line =
|
|
"MBean."
|
|
+ joinOps(operations)
|
|
+ " => "
|
|
+ root.getClass().getName()
|
|
+ ": "
|
|
+ root.getMessage();
|
|
|
|
warn(line);
|
|
attempts.append(line).append('\n');
|
|
}
|
|
}
|
|
|
|
throw new IllegalStateException(
|
|
"Neustart fehlgeschlagen:\n" + attempts.toString());
|
|
}
|
|
|
|
private static String joinOps(String[] operations)
|
|
{
|
|
StringBuffer buffer = new StringBuffer();
|
|
|
|
for (int index = 0; index < operations.length; index++)
|
|
{
|
|
if (index > 0)
|
|
{
|
|
buffer.append('+');
|
|
}
|
|
|
|
buffer.append(operations[index]);
|
|
}
|
|
|
|
return buffer.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.");
|
|
}
|
|
|
|
// Sonic JMSConnectorClient verlangt leere Arrays, nicht null.
|
|
Object[] params = new Object[0];
|
|
String[] signature = new String[0];
|
|
|
|
invokeMethod.invoke(
|
|
connector,
|
|
new Object[]
|
|
{
|
|
objectName,
|
|
operation,
|
|
params,
|
|
signature
|
|
});
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|