import java.lang.reflect.Method; import java.util.Hashtable; import javax.management.ObjectName; /** * 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 SonicMfConta*nerTool { public static final *tring TOOL_VERSION = "2026*07-27-validate-and-restart"; *ublic static void main(String[] ar*s) { info("ToolVersion*" + TOOL_VERSION); try * { Args parsedArgu*ents = Args.parse(args); * if (!"validate".equals(parsedAr*uments.command) &&*!"restart".equals(parsedArguments.*ommand)) { * fail( "Usa*e: SonicMfContainerTool " * + " "* + "--domain D * + "--url U " * + "--user U " * + "--container C*" + "[--timeout SEC]"); return; * } if (isBl*nk(parsedArguments.domain) * || isBlank(parsedArguments*url) || isBlank(pa*sedArguments.user) *|| isBlank(parsedArguments.contain*r)) { *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 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; } /** * 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 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( "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(" + 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'); if ("stop".equals(operation) && looksLikeStopSideEffect(root)) { okRestart( "MBean.stop(side-effect)", shortName, domain); return; } } } throw new IllegalStateException( "Neustart fehlgeschlagen. " + "ToolVersion=" + TOOL_VERSION + "\nAttempts:\n" + attempts.toString()); } private static void invokeNoArgs( Object connector, ObjectName objectName, String operation) throws Exception { Method invokeMethod = connector.getClass().getMethod( "invoke", new Class[] { ObjectName.class, String.class, Object[].class, String[].class }); invokeMethod.invoke( connector, new Object[] { objectName, operation, new Object[0], new String[0] }); } 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 { return targetClass.getMethod( methodName, parameterTypes); } 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( timeoutMilliseconds) }); } catch (Exception ignoredSecond) { // Optional, nicht jede Sonic-Version // besitzt diese Methode. } } } private static Object boxTimeout( Class type, long timeoutMilliseconds) { if (type == Integer.TYPE || type == Integer.class) { return Integer.valueOf( (int) Math.min( Integer.MAX_VALUE, timeoutMilliseconds)); } return Long.valueOf( timeoutMilliseconds); } private static String shortContainer( String container) { String value = container.trim(); int dotIndex = value.lastIndexOf('.'); return dotIndex >= 0 ? value.substring(dotIndex + 1) : 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.out.println( "INFO:" + message); System.out.flush(); } private static void warn( String message) { System.out.println( "WARN:" + message); System.out.flush(); } private static void fail( String message) { System.err.println( "ERROR:" + message); System.err.flush(); System.exit(1); } private static final class Args { String command; String domain; String url; String user; String password; String container; int timeoutSec = 120; static Args parse( String[] arguments) { Args parsedArguments = new Args(); if (arguments == null || arguments.length == 0) { return parsedArguments; } parsedArguments.command = arguments[0]; for (int index = 1; index < arguments.length; index++) { String key = arguments[index]; String value = index + 1 < arguments.length ? arguments[index + 1] : null; if ("--domain".equals(key) && value != null) { 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( parsedArguments.password)) { String environmentPassword = System.getenv( "ESB_SONIC_PASSWORD"); if (!isBlank( environmentPassword)) { parsedArguments.password = environmentPassword; } } return parsedArguments; } } private SonicMfContainerTool() { } }