big changes

This commit is contained in:
Mike Gisler
2026-07-28 08:03:12 +02:00
parent c73f53d740
commit 4d19873776
179 changed files with 14953 additions and 494 deletions
@@ -4,243 +4,644 @@ import java.util.Hashtable;
import javax.management.ObjectName;
/**
* Minimaler Sonic-Restart (wie SMC): JMSConnectorClient + MBean stop/restart.
* Compile: javac --release 8 SonicMfContainerTool.java
* Sonic-MfApi-Hilfsprogramm.
*
* Unterstützte Befehle:
*
* validate
* Prüft Anmeldung und lesenden Zugriff auf den Container.
* Es wird kein Neustart ausgeführt.
*
* restart
* Startet den angegebenen Container neu.
*
* Kompilierung mit Java 8:
*
* javac -source 8 -target 8 SonicMfContainerTool.java
*/
public final class SonicMfContainerTool
public final class SonicMfConta*nerTool
{
public static final String TOOL_VERSION = "2026-07-24d-restart-only";
public static final *tring TOOL_VERSION =
"2026*07-27-validate-and-restart";
public static void main(String[] args)
*ublic static void main(String[] ar*s)
{
info("ToolVersion=" + TOOL_VERSION);
info("ToolVersion*" + TOOL_VERSION);
try
{
Args a = Args.parse(args);
if (!"restart".equals(a.command))
* {
Args parsedArgu*ents = Args.parse(args);
* if (!"validate".equals(parsedAr*uments.command)
&&*!"restart".equals(parsedArguments.*ommand))
{
fail("Usage: SonicMfContainerTool restart --domain D --url U --user U --container C [--timeout SEC]");
* fail(
"Usa*e: SonicMfContainerTool "
* + "<validate|restart> "* + "--domain D *
+ "--url U "
* + "--user U "
* + "--container C*"
+ "[--timeout SEC]");
return;
}
if (isBlank(a.domain) || isBlank(a.url) || isBlank(a.user) || isBlank(a.container))
* }
if (isBl*nk(parsedArguments.domain)
* || isBlank(parsedArguments*url)
|| isBlank(pa*sedArguments.user)
*|| isBlank(parsedArguments.contain*r))
{
fail("domain, url, user und container sind Pflicht.");
*ail(
"domain, *rl, user und container sind Pflich*.");
return;
* }
if (isBlank(*arsedArguments.password))
* {
fail(
* "Das Sonic-Kennwort wurde nicht über "
+ "ESB_SONIC_PASSWORD bereitgestellt.");
return;
}
long timeoutMs = Math.max(5_000L, a.timeoutSec * 1000L);
Object connector = connect(a.url, a.user, a.password, timeoutMs);
long timeoutMilliseconds = Math.max(
5_000L,
parsedArguments.timeoutSec * 1000L);
Object connector = connect(
parsedArguments.url,
parsedArguments.user,
parsedArguments.password,
timeoutMilliseconds);
try
{
restart(connector, a.domain, a.container);
if ("validate".equals(
parsedArguments.command))
{
validateConnection(
connector,
parsedArguments.domain,
parsedArguments.container);
}
else
{
restart(
connector,
parsedArguments.domain,
parsedArguments.container);
}
}
finally
{
try
{
connector.getClass().getMethod("disconnect").invoke(connector);
}
catch (Exception ignore)
{
/* ignore */
}
disconnect(connector);
}
}
catch (Throwable t)
catch (Throwable throwable)
{
fail(rootOf(t).getClass().getName() + ": " + rootOf(t).getMessage());
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 timeoutMs) throws Exception
private static Object connect(
String url,
String user,
String password,
long timeoutMilliseconds)
throws Exception
{
Hashtable env = new Hashtable();
env.put("ConnectionURLs", url);
env.put("DefaultUser", user);
env.put("DefaultPassword", password == null ? "" : password);
Hashtable environment = new Hashtable();
Class addressCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorAddress");
Object address = addressCl.getConstructor(new Class[] { Hashtable.class }).newInstance(new Object[] { env });
environment.put(
"ConnectionURLs",
url);
Class clientCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorClient");
Object connector = clientCl.getConstructor(new Class[] {}).newInstance(new Object[] {});
trySetTimeout(connector, timeoutMs);
environment.put(
"DefaultUser",
user);
Method connect = findConnect(clientCl);
if (connect == null)
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)
{
fail("JMSConnectorClient.connect(...) nicht gefunden.");
return null;
throw new IllegalStateException(
"JMSConnectorClient.connect(...) "
+ "wurde nicht gefunden.");
}
Class[] pts = connect.getParameterTypes();
if (pts.length == 2)
Class[] parameterTypes =
connectMethod.getParameterTypes();
if (parameterTypes.length == 2)
{
connect.invoke(connector, new Object[] { address, boxTimeout(pts[1], timeoutMs) });
connectMethod.invoke(
connector,
new Object[]
{
address,
boxTimeout(
parameterTypes[1],
timeoutMilliseconds)
});
}
else
{
connect.invoke(connector, new Object[] { address });
connectMethod.invoke(
connector,
new Object[]
{
address
});
}
return connector;
}
private static void restart(Object connector, String domain, String container) throws Exception
/**
* Führt ausschließlich eine lesende Prüfung aus.
*
* Die erfolgreiche Verbindung bestätigt bereits die Anmeldung.
* Zusätzlich wird versucht, die MBean-Information des Containers
* zu lesen. Es wird keine stop-, start- oder restart-Operation
* aufgerufen.
*/
private static void validateConnection(
Object connector,
String domain,
String container)
throws Exception
{
String shortName = shortContainer(container);
ObjectName on = new ObjectName(domain + "." + shortName + ":ID=AGENT");
info("ObjectName=" + on);
String shortName =
shortContainer(container);
StringBuffer attempts = new StringBuffer();
String[] ops = new String[] { "stop", "restart" };
for (int i = 0; i < ops.length; i++)
ObjectName objectName =
new ObjectName(
domain
+ "."
+ shortName
+ ":ID=AGENT");
info(
"ValidatingObjectName="
+ objectName);
Method getMBeanInfoMethod =
findMethod(
connector.getClass(),
"getMBeanInfo",
new Class[]
{
ObjectName.class
});
if (getMBeanInfoMethod == null)
{
String op = ops[i];
throw new IllegalStateException(
"Die lesende MfApi-Methode "
+ "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(" + op + ")");
invokeNoArgs(connector, on, op);
okRestart("MBean." + op, shortName, domain);
info(
"Trying MBean.invoke("
+ operation
+ ")");
invokeNoArgs(
connector,
objectName,
operation);
okRestart(
"MBean." + operation,
shortName,
domain);
return;
}
catch (Throwable t)
catch (Throwable throwable)
{
Throwable root = rootOf(t);
String line = "MBean." + op + " => " + root.getClass().getName() + ": " + root.getMessage();
Throwable root =
rootOf(throwable);
String line =
"MBean."
+ operation
+ " => "
+ root.getClass().getName()
+ ": "
+ root.getMessage();
warn(line);
attempts.append(line).append('\n');
if ("stop".equals(op) && looksLikeStopSideEffect(root))
attempts
.append(line)
.append('\n');
if ("stop".equals(operation)
&& looksLikeStopSideEffect(root))
{
okRestart("MBean.stop(side-effect)", shortName, domain);
okRestart(
"MBean.stop(side-effect)",
shortName,
domain);
return;
}
}
}
fail("Neustart fehlgeschlagen. ToolVersion=" + TOOL_VERSION + "\nAttempts:\n" + attempts.toString());
throw new IllegalStateException(
"Neustart fehlgeschlagen. "
+ "ToolVersion="
+ TOOL_VERSION
+ "\nAttempts:\n"
+ attempts.toString());
}
private static void invokeNoArgs(Object connector, ObjectName on, String op) throws Exception
private static void invokeNoArgs(
Object connector,
ObjectName objectName,
String operation)
throws Exception
{
Method invoke = connector.getClass().getMethod("invoke", new Class[] {
ObjectName.class, String.class, Object[].class, String[].class
});
invoke.invoke(connector, new Object[] { on, op, new Object[0], new String[0] });
}
private static boolean looksLikeStopSideEffect(Throwable root)
{
if (root == null || root.getMessage() == null)
{
return false;
}
String m = root.getMessage().toLowerCase();
return m.indexOf("disconnect") >= 0
|| m.indexOf("closed") >= 0
|| m.indexOf("not connected") >= 0
|| m.indexOf("connection lost") >= 0;
}
private static void okRestart(String method, String shortName, String domain)
{
System.out.println("OK:RestartInvoked method=" + method
+ " container=" + shortName + " domain=" + domain
+ " tool=" + TOOL_VERSION);
System.out.flush();
}
private static Method findConnect(Class clientCl)
{
Method[] methods = clientCl.getMethods();
Method best = null;
for (int i = 0; i < methods.length; i++)
{
Method m = methods[i];
if (!"connect".equals(m.getName()))
{
continue;
}
Class[] pts = m.getParameterTypes();
if (pts.length == 1 || pts.length == 2)
{
best = m;
if (pts.length == 2)
Method invokeMethod =
connector.getClass().getMethod(
"invoke",
new Class[]
{
return m;
}
}
}
return best;
ObjectName.class,
String.class,
Object[].class,
String[].class
});
invokeMethod.invoke(
connector,
new Object[]
{
objectName,
operation,
new Object[0],
new String[0]
});
}
private static void trySetTimeout(Object connector, long timeoutMs)
private static void disconnect(
Object connector)
{
if (connector == null)
{
return;
}
try
{
connector
.getClass()
.getMethod("disconnect")
.invoke(connector);
}
catch (Exception ignored)
{
// Die eigentliche Prüfung oder der Neustart
// darf durch einen Disconnect-Fehler nicht
// überschrieben werden.
}
}
private static Method findMethod(
Class targetClass,
String methodName,
Class[] parameterTypes)
{
try
{
connector.getClass().getMethod("setTimeout", new Class[] { Long.TYPE })
.invoke(connector, new Object[] { Long.valueOf(timeoutMs) });
return targetClass.getMethod(
methodName,
parameterTypes);
}
catch (Exception ignore)
catch (Exception ignored)
{
return null;
}
}
private static boolean looksLikeStopSideEffect(
Throwable root)
{
if (root == null
|| root.getMessage() == null)
{
return false;
}
String message =
root.getMessage().toLowerCase();
return message.indexOf("disconnect") >= 0
|| message.indexOf("closed") >= 0
|| message.indexOf("not connected") >= 0
|| message.indexOf("connection lost") >= 0;
}
private static void okRestart(
String method,
String shortName,
String domain)
{
System.out.println(
"OK:RestartInvoked"
+ " method="
+ method
+ " container="
+ shortName
+ " domain="
+ domain
+ " tool="
+ TOOL_VERSION);
System.out.flush();
}
private static Method findConnect(
Class clientClass)
{
Method[] methods =
clientClass.getMethods();
Method bestMethod = null;
for (int index = 0;
index < methods.length;
index++)
{
Method method =
methods[index];
if (!"connect".equals(
method.getName()))
{
continue;
}
Class[] parameterTypes =
method.getParameterTypes();
if (parameterTypes.length == 1
|| parameterTypes.length == 2)
{
bestMethod = method;
if (parameterTypes.length == 2)
{
return method;
}
}
}
return bestMethod;
}
private static void trySetTimeout(
Object connector,
long timeoutMilliseconds)
{
try
{
connector
.getClass()
.getMethod(
"setTimeout",
new Class[]
{
Long.TYPE
})
.invoke(
connector,
new Object[]
{
Long.valueOf(
timeoutMilliseconds)
});
}
catch (Exception ignored)
{
try
{
connector.getClass().getMethod("setRequestTimeout", new Class[] { Long.TYPE })
.invoke(connector, new Object[] { Long.valueOf(timeoutMs) });
connector
.getClass()
.getMethod(
"setRequestTimeout",
new Class[]
{
Long.TYPE
})
.invoke(
connector,
new Object[]
{
Long.valueOf(
timeoutMilliseconds)
});
}
catch (Exception ignore2)
catch (Exception ignoredSecond)
{
/* optional */
// Optional, nicht jede Sonic-Version
// besitzt diese Methode.
}
}
}
private static Object boxTimeout(Class type, long timeoutMs)
private static Object boxTimeout(
Class type,
long timeoutMilliseconds)
{
if (type == Integer.TYPE || type == Integer.class)
if (type == Integer.TYPE
|| type == Integer.class)
{
return Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs));
return Integer.valueOf(
(int) Math.min(
Integer.MAX_VALUE,
timeoutMilliseconds));
}
return Long.valueOf(timeoutMs);
return Long.valueOf(
timeoutMilliseconds);
}
private static String shortContainer(String container)
private static String shortContainer(
String container)
{
String c = container.trim();
int dot = c.lastIndexOf('.');
return dot >= 0 ? c.substring(dot + 1) : c;
String value =
container.trim();
int dotIndex =
value.lastIndexOf('.');
return dotIndex >= 0
? value.substring(dotIndex + 1)
: value;
}
private static Throwable rootOf(Throwable t)
private static Throwable rootOf(
Throwable throwable)
{
Throwable cur = t;
while (cur.getCause() != null && cur.getCause() != cur)
Throwable current =
throwable;
while (current.getCause() != null
&& current.getCause() != current)
{
cur = cur.getCause();
current =
current.getCause();
}
return cur;
return current;
}
private static boolean isBlank(String s)
private static boolean isBlank(
String value)
{
return s == null || s.trim().length() == 0;
return value == null
|| value.trim().length() == 0;
}
private static void info(String msg)
private static void info(
String message)
{
System.out.println("INFO:" + msg);
System.out.println(
"INFO:" + message);
System.out.flush();
}
private static void warn(String msg)
private static void warn(
String message)
{
System.out.println("WARN:" + msg);
System.out.println(
"WARN:" + message);
System.out.flush();
}
private static void fail(String msg)
private static void fail(
String message)
{
System.err.println("ERROR:" + msg);
System.err.println(
"ERROR:" + message);
System.err.flush();
System.exit(1);
}
@@ -252,44 +653,103 @@ public final class SonicMfContainerTool
String user;
String password;
String container;
int timeoutSec = 120;
static Args parse(String[] args)
static Args parse(
String[] arguments)
{
Args a = new Args();
if (args == null || args.length == 0)
Args parsedArguments =
new Args();
if (arguments == null
|| arguments.length == 0)
{
return a;
return parsedArguments;
}
a.command = args[0];
for (int i = 1; i < args.length; i++)
parsedArguments.command =
arguments[0];
for (int index = 1;
index < arguments.length;
index++)
{
String k = args[i];
String v = (i + 1 < args.length) ? args[i + 1] : null;
if ("--domain".equals(k) && v != null) { a.domain = v; i++; }
else if ("--url".equals(k) && v != null) { a.url = v; i++; }
else if ("--user".equals(k) && v != null) { a.user = v; i++; }
else if ("--password".equals(k) && v != null) { a.password = v; i++; }
else if ("--container".equals(k) && v != null) { a.container = v; i++; }
else if ("--timeout".equals(k) && v != null)
String key =
arguments[index];
String value =
index + 1 < arguments.length
? arguments[index + 1]
: null;
if ("--domain".equals(key)
&& value != null)
{
try { a.timeoutSec = Integer.parseInt(v); } catch (Exception ignore) { /* keep default */ }
i++;
parsedArguments.domain = value;
index++;
}
else if ("--url".equals(key)
&& value != null)
{
parsedArguments.url = value;
index++;
}
else if ("--user".equals(key)
&& value != null)
{
parsedArguments.user = value;
index++;
}
else if ("--password".equals(key)
&& value != null)
{
parsedArguments.password = value;
index++;
}
else if ("--container".equals(key)
&& value != null)
{
parsedArguments.container = value;
index++;
}
else if ("--timeout".equals(key)
&& value != null)
{
try
{
parsedArguments.timeoutSec =
Integer.parseInt(value);
}
catch (Exception ignored)
{
// Standardwert beibehalten.
}
index++;
}
}
if (isBlank(a.password))
if (isBlank(
parsedArguments.password))
{
String env = System.getenv("ESB_SONIC_PASSWORD");
if (!isBlank(env))
String environmentPassword =
System.getenv(
"ESB_SONIC_PASSWORD");
if (!isBlank(
environmentPassword))
{
a.password = env;
parsedArguments.password =
environmentPassword;
}
}
return a;
return parsedArguments;
}
}
private SonicMfContainerTool()
{
}
}
}