Force new MfApi tool build and MBean stop restart path.

Reject stale SonicMfContainerTool.class, print ToolVersion, prefer tool on classpath.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-24 10:22:39 +02:00
co-authored by Cursor
parent ada6b6ca83
commit 7a9cdb6ecf
6 changed files with 276 additions and 164 deletions
@@ -186,7 +186,32 @@ public sealed class SonicMfApiExecutor
"Hinweis: Container-Kurzname laut SMC ist 'ct-ZADBService' (nicht der Verbindungs-Alias DE-Test)."; "Hinweis: Container-Kurzname laut SMC ist 'ct-ZADBService' (nicht der Verbindungs-Alias DE-Test).";
} }
return (false, combined.Length > 0 ? combined : null, err); if (!combined.Contains("ToolVersion=", StringComparison.OrdinalIgnoreCase))
{
err +=
"\n\nWARN: Ausgabe enthält kein INFO:ToolVersion=… vermutlich alte SonicMfContainerTool.class.\n" +
"App neu bauen (Debug+Release), Tools-Ordner im Output prüfen, Temp esb-sonic-mf* löschen.";
}
// Volle Ausgabe mitliefern (INFO/WARN), nicht nur die ERROR-Zeile
string detail = string.IsNullOrWhiteSpace(combined) ? err : err + "\n\n--- Tool-Output ---\n" + combined;
return (false, combined.Length > 0 ? combined : null, detail);
}
private static void TryDeleteTempToolCache()
{
try
{
string dir = Path.Combine(Path.GetTempPath(), "esb-sonic-mf-j8");
if (Directory.Exists(dir))
{
Directory.Delete(dir, recursive: true);
}
}
catch
{
/* ignore */
}
} }
private async Task<(bool Ok, string? JavaExe, string? ClassDir, string? Classpath, string? Error)> private async Task<(bool Ok, string? JavaExe, string? ClassDir, string? Classpath, string? Error)>
@@ -246,11 +271,14 @@ public sealed class SonicMfApiExecutor
return (false, null, null, null, libError); return (false, null, null, null, libError);
} }
// Vorcompilierte .class/.jar nur nutzen, wenn Class-Version zur Runtime passt. // Vorcompilierte .class nur nutzen, wenn Class-Version passt.
// Tool-Verzeichnis ZUERST im Classpath, damit keine alte Klasse aus Temp/JAR gewinnt.
if (TryResolvePrebuiltTool(runtimeMajor, out string? prebuiltDir, out string? prebuiltEntry, out string? prebuiltError) if (TryResolvePrebuiltTool(runtimeMajor, out string? prebuiltDir, out string? prebuiltEntry, out string? prebuiltError)
&& prebuiltDir is not null && prebuiltEntry is not null) && prebuiltDir is not null && prebuiltEntry is not null)
{ {
string classpath = libClasspath + Path.PathSeparator + prebuiltEntry; // Veraltete Temp-Kopien entfernen (früheres Compile-Cache).
TryDeleteTempToolCache();
string classpath = prebuiltEntry + Path.PathSeparator + libClasspath;
return (true, javaExe, prebuiltDir, classpath, null); return (true, javaExe, prebuiltDir, classpath, null);
} }
@@ -264,6 +292,7 @@ public sealed class SonicMfApiExecutor
$"Runtime-Java: {javaExe} (class major max={runtimeMajor})."); $"Runtime-Java: {javaExe} (class major max={runtimeMajor}).");
} }
TryDeleteTempToolCache();
string workDir = Path.Combine(Path.GetTempPath(), "esb-sonic-mf-j8"); string workDir = Path.Combine(Path.GetTempPath(), "esb-sonic-mf-j8");
Directory.CreateDirectory(workDir); Directory.CreateDirectory(workDir);
@@ -273,7 +302,8 @@ public sealed class SonicMfApiExecutor
File.Copy(sourcePath, javaTarget, overwrite: true); File.Copy(sourcePath, javaTarget, overwrite: true);
string compileClasspath = libClasspath; string compileClasspath = libClasspath;
string runtimeClasspath = libClasspath + Path.PathSeparator + workDir; // workDir zuerst
string runtimeClasspath = workDir + Path.PathSeparator + libClasspath;
bool classOk = File.Exists(classFile) bool classOk = File.Exists(classFile)
&& ReadClassFileMajorVersion(classFile) is int existingMajor && ReadClassFileMajorVersion(classFile) is int existingMajor
@@ -375,13 +405,22 @@ public sealed class SonicMfApiExecutor
if (File.Exists(classFile)) if (File.Exists(classFile))
{ {
int? major = ReadClassFileMajorVersion(classFile); int? major = ReadClassFileMajorVersion(classFile);
if (major is not null && major <= runtimeMajor) // Alte Builds waren ~7KB; MBean-Stop-Tool ist >10KB.
long len = new FileInfo(classFile).Length;
if (major is not null && major <= runtimeMajor && len >= 10_000)
{ {
workDir = dir; workDir = dir;
classpathEntry = dir; classpathEntry = dir;
return true; return true;
} }
if (major is not null && major <= runtimeMajor && len < 10_000)
{
error =
$"Tools\\SonicMfContainerTool.class ist veraltet ({len} Bytes). Bitte neu bauen/pullen (erwartet >=10000).";
continue;
}
error = error =
$"Tools\\SonicMfContainerTool.class ist zu neu (major={major}, braucht <={runtimeMajor} / Java 8)."; $"Tools\\SonicMfContainerTool.class ist zu neu (major={major}, braucht <={runtimeMajor} / Java 8).";
continue; continue;
@@ -8,31 +8,24 @@ import javax.management.MBeanInfo;
import javax.management.ObjectName; import javax.management.ObjectName;
/** /**
* Sonic Management Application API helper (same restart as SMC). * Sonic Management Application API helper (same restart intent as SMC).
* *
* Uses reflection so this file compiles with Java 8 without Sonic jars on the * TOOL_VERSION is printed first so we can verify the deployed build.
* compile classpath. At runtime SonicHome\\lib must provide:
* mgmt_client / mfcontext / sonic_Client (etc.)
* *
* Flow: * Remote JMSConnectorClient is "unbounded". IAgentProxy.restart() often throws
* Hashtable ConnectionURLs/DefaultUser/DefaultPassword * "Operation unsupported for unbounded client connector". SMC Restart typically
* -> JMSConnectorAddress / JMSConnectorClient.connect * stops the agent via JMX; Launch Daemon brings it back.
* -> ObjectName {domain}.{container}:ID=AGENT
* -> restart via (in order):
* 1) MBean invoke("restart") / invoke("stop") [remote / unbounded OK]
* 2) IAgentProxy.restart / stop via MFProxyFactory
*
* Note: IAgentProxy.restart() often throws
* "Operation unsupported for unbounded client connector"
* on remote JMSConnectorClient. SMC Restart typically stops the agent; the
* Launch Daemon / container host brings it back up.
* *
* Compile: javac --release 8 SonicMfContainerTool.java * Compile: javac --release 8 SonicMfContainerTool.java
*/ */
public final class SonicMfContainerTool public final class SonicMfContainerTool
{ {
/** Bump when restart logic changes must appear in app output. */
public static final String TOOL_VERSION = "2026-07-24c-mbean-stop";
public static void main(String[] args) public static void main(String[] args)
{ {
info("ToolVersion=" + TOOL_VERSION);
try try
{ {
Args a = Args.parse(args); Args a = Args.parse(args);
@@ -89,12 +82,7 @@ public final class SonicMfContainerTool
} }
catch (Throwable t) catch (Throwable t)
{ {
Throwable root = t; fail(rootOf(t).getClass().getName() + ": " + rootOf(t).getMessage());
while (root.getCause() != null && root.getCause() != root)
{
root = root.getCause();
}
fail(root.getClass().getName() + ": " + root.getMessage());
} }
} }
@@ -112,43 +100,105 @@ public final class SonicMfContainerTool
Class clientCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorClient"); Class clientCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorClient");
Object connector = clientCl.getConstructor(new Class[] {}).newInstance(new Object[] {}); Object connector = clientCl.getConstructor(new Class[] {}).newInstance(new Object[] {});
Method connect = null; // Optional: Request-Timeout setzen (falls vorhanden)
Method[] methods = clientCl.getMethods(); trySetTimeout(connector, timeoutMs);
for (int i = 0; i < methods.length; i++)
{ Method connect = findConnect(clientCl);
Method m = methods[i];
if ("connect".equals(m.getName()) && m.getParameterTypes().length == 2)
{
connect = m;
break;
}
}
if (connect == null) if (connect == null)
{ {
fail("JMSConnectorClient.connect(address, timeout) nicht gefunden."); fail("JMSConnectorClient.connect(...) nicht gefunden.");
return null; return null;
} }
Class[] pts = connect.getParameterTypes(); Class[] pts = connect.getParameterTypes();
Object timeoutArg; Object[] callArgs;
if (pts[1] == Long.TYPE || pts[1] == Long.class) if (pts.length == 2)
{ {
timeoutArg = Long.valueOf(timeoutMs); callArgs = new Object[] { address, boxTimeout(pts[1], timeoutMs) };
} }
else if (pts[1] == Integer.TYPE || pts[1] == Integer.class) else if (pts.length == 1)
{ {
timeoutArg = Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs)); callArgs = new Object[] { address };
} }
else else
{ {
timeoutArg = Long.valueOf(timeoutMs); callArgs = new Object[] { address, boxTimeout(pts[1], timeoutMs) };
} }
connect.invoke(connector, new Object[] { address, timeoutArg }); connect.invoke(connector, callArgs);
info("Connected url=" + url + " user=" + user); info("Connected url=" + url + " user=" + user);
return connector; return connector;
} }
private static Method findConnect(Class clientCl)
{
Method best = null;
Method[] methods = clientCl.getMethods();
for (int i = 0; i < methods.length; i++)
{
Method m = methods[i];
if (!"connect".equals(m.getName()))
{
continue;
}
if (m.getParameterTypes().length == 2)
{
return m;
}
if (m.getParameterTypes().length == 1)
{
best = m;
}
}
return best;
}
private static void trySetTimeout(Object connector, long timeoutMs)
{
String[] names = new String[] { "setTimeout", "setRequestTimeout", "setDefaultTimeout" };
for (int i = 0; i < names.length; i++)
{
try
{
Method m = connector.getClass().getMethod(names[i], new Class[] { Long.TYPE });
m.invoke(connector, new Object[] { Long.valueOf(timeoutMs) });
info("Set " + names[i] + "=" + timeoutMs);
return;
}
catch (NoSuchMethodException ignore)
{
try
{
Method m = connector.getClass().getMethod(names[i], new Class[] { Integer.TYPE });
m.invoke(connector, new Object[] { Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs)) });
info("Set " + names[i] + "=" + timeoutMs);
return;
}
catch (Exception ignore2)
{
/* next */
}
}
catch (Exception ignore)
{
/* next */
}
}
}
private static Object boxTimeout(Class type, long timeoutMs)
{
if (type == Long.TYPE || type == Long.class)
{
return Long.valueOf(timeoutMs);
}
if (type == Integer.TYPE || type == Integer.class)
{
return Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs));
}
return Long.valueOf(timeoutMs);
}
private static void ping(Object connector, String domain) throws Exception private static void ping(Object connector, String domain) throws Exception
{ {
Set names = queryAgents(connector); Set names = queryAgents(connector);
@@ -196,36 +246,54 @@ public final class SonicMfContainerTool
private static void restart(Object connector, String domain, String container) throws Exception private static void restart(Object connector, String domain, String container) throws Exception
{ {
String shortName = shortContainer(container); String shortName = shortContainer(container);
ObjectName on = resolveAgentObjectName(connector, domain, shortName); // Zuerst Preferred-ObjectName OHNE queryNames query kann schon scheitern/irreführen
ObjectName preferred = new ObjectName(domain + "." + shortName + ":ID=AGENT");
info("PreferredObjectName=" + preferred);
ObjectName on = preferred;
try
{
ObjectName resolved = resolveAgentObjectName(connector, domain, shortName);
if (resolved != null)
{
on = resolved;
}
}
catch (Throwable t)
{
warn("resolveAgentObjectName: " + rootOf(t).getClass().getName() + ": " + rootOf(t).getMessage()
+ " nutze PreferredObjectName");
}
info("ObjectName=" + on); info("ObjectName=" + on);
dumpOps(connector, on); dumpOpsSafe(connector, on);
// 1) Remote-JMX invoke (funktioniert mit unbounded client) StringBuffer attempts = new StringBuffer();
if (tryMBeanLifecycle(connector, on, shortName, domain))
// 1) JMX invoke stop/restart/shutdown (remote / wie SMC)
if (tryMBeanLifecycle(connector, on, shortName, domain, attempts))
{ {
return; return;
} }
// 2) Typisierte Proxies (kann unbounded-Fehler werfen) // 2) IAgentProxy stop/restart
if (tryAgentProxyLifecycle(connector, on, shortName, domain)) if (tryAgentProxyLifecycle(connector, on, shortName, domain, attempts))
{ {
return; return;
} }
// 3) DomainManager / Collector Fallback // 3) Manager-MBeans mit Container-Namen
if (tryDomainManagerRestart(connector, domain, shortName)) if (tryManagerContainerOps(connector, domain, shortName, attempts))
{ {
return; return;
} }
fail("Kein Neustart-Weg funktioniert (MBean invoke / IAgentProxy / DomainManager). " fail("Kein Neustart-Weg erfolgreich. ToolVersion=" + TOOL_VERSION + "\nAttempts:\n" + attempts.toString());
+ "Siehe INFO:Ops und unbounded-Hinweise oben.");
} }
private static boolean tryMBeanLifecycle(Object connector, ObjectName on, String shortName, String domain) private static boolean tryMBeanLifecycle(
Object connector, ObjectName on, String shortName, String domain, StringBuffer attempts)
{ {
// Reihenfolge: stop zuerst (SMC-Restart = Stop + Auto-Relaunch), dann restart
String[] ops = new String[] { "stop", "restart", "shutdown" }; String[] ops = new String[] { "stop", "restart", "shutdown" };
for (int i = 0; i < ops.length; i++) for (int i = 0; i < ops.length; i++)
{ {
@@ -234,25 +302,30 @@ public final class SonicMfContainerTool
{ {
info("Trying MBean.invoke(" + op + ") on " + on); info("Trying MBean.invoke(" + op + ") on " + on);
invokeNoArgs(connector, on, op); invokeNoArgs(connector, on, op);
System.out.println("OK:RestartInvoked method=MBean." + op okRestart("MBean." + op, shortName, domain);
+ " container=" + shortName + " domain=" + domain);
System.out.flush();
return true; return true;
} }
catch (Throwable t) catch (Throwable t)
{ {
Throwable root = rootOf(t); Throwable root = rootOf(t);
warn("MBean." + op + " failed: " + root.getClass().getName() + ": " + root.getMessage()); String line = "MBean." + op + " => " + root.getClass().getName() + ": " + root.getMessage();
if (!isUnbounded(root) && !"stop".equals(op) && !"restart".equals(op) && !"shutdown".equals(op)) warn(line);
attempts.append(line).append('\n');
// stop kann die Verbindung reissen wenn Message darauf hindeutet, als Erfolg werten
if ("stop".equals(op) && looksLikeStopSideEffect(root))
{ {
// continue trying other ops warn("Treat stop side-effect as success (agent going down)");
okRestart("MBean.stop(side-effect)", shortName, domain);
return true;
} }
} }
} }
return false; return false;
} }
private static boolean tryAgentProxyLifecycle(Object connector, ObjectName on, String shortName, String domain) private static boolean tryAgentProxyLifecycle(
Object connector, ObjectName on, String shortName, String domain, StringBuffer attempts)
{ {
try try
{ {
@@ -272,150 +345,150 @@ public final class SonicMfContainerTool
{ {
info("Trying IAgentProxy." + mName); info("Trying IAgentProxy." + mName);
agent.getClass().getMethod(mName).invoke(agent); agent.getClass().getMethod(mName).invoke(agent);
System.out.println("OK:RestartInvoked method=IAgentProxy." + mName okRestart("IAgentProxy." + mName, shortName, domain);
+ " container=" + shortName + " domain=" + domain);
System.out.flush();
return true; return true;
} }
catch (Throwable t) catch (Throwable t)
{ {
Throwable root = rootOf(t); Throwable root = rootOf(t);
warn("IAgentProxy." + mName + " failed: " + root.getClass().getName() + ": " + root.getMessage()); String line = "IAgentProxy." + mName + " => " + root.getClass().getName() + ": " + root.getMessage();
warn(line);
attempts.append(line).append('\n');
if ("stop".equals(mName) && looksLikeStopSideEffect(root))
{
okRestart("IAgentProxy.stop(side-effect)", shortName, domain);
return true;
}
} }
} }
} }
catch (Throwable t) catch (Throwable t)
{ {
Throwable root = rootOf(t); Throwable root = rootOf(t);
warn("IAgentProxy path failed: " + root.getClass().getName() + ": " + root.getMessage()); String line = "IAgentProxy path => " + root.getClass().getName() + ": " + root.getMessage();
warn(line);
attempts.append(line).append('\n');
} }
return false; return false;
} }
private static boolean tryDomainManagerRestart(Object connector, String domain, String shortName) private static boolean tryManagerContainerOps(
Object connector, String domain, String shortName, StringBuffer attempts)
{ {
// Häufige ObjectNames für Domain Manager / Collector
String[] candidates = new String[] { String[] candidates = new String[] {
domain + ".DomainManager:ID=DomainManager", domain + ".DomainManager:ID=DomainManager",
domain + ".DomainManager:ID=AGENT", domain + ".DomainManager:ID=AGENT",
domain + ".dm:ID=AGENT", domain + ".dm:ID=AGENT"
domain + ".DOMAIN_MANAGER:ID=AGENT",
domain + ".ManagementFramework:ID=AGENT"
}; };
for (int i = 0; i < candidates.length; i++) for (int i = 0; i < candidates.length; i++)
{ {
try try
{ {
ObjectName dm = new ObjectName(candidates[i]); ObjectName pattern = new ObjectName(candidates[i]);
Set found = (Set) connector.getClass() Set found = queryNames(connector, pattern);
.getMethod("queryNames", new Class[] { ObjectName.class, javax.management.QueryExp.class })
.invoke(connector, new Object[] { dm, null });
if (found == null || found.isEmpty()) if (found == null || found.isEmpty())
{ {
continue; continue;
} }
ObjectName real = (ObjectName) found.iterator().next(); ObjectName real = (ObjectName) found.iterator().next();
info("DomainManager candidate=" + real); info("Manager=" + real);
dumpOps(connector, real); dumpOpsSafe(connector, real);
String[] ops = new String[] { String[] ops = new String[] { "restartContainer", "stopContainer", "startContainer" };
"restartContainer", "stopContainer", "startContainer",
"restart", "stop", "shutdown"
};
for (int o = 0; o < ops.length; o++) for (int o = 0; o < ops.length; o++)
{ {
String op = ops[o];
try try
{ {
if (op.endsWith("Container")) info("Trying " + ops[o] + "(\"" + shortName + "\") on " + real);
{ invokeStringArg(connector, real, ops[o], shortName);
info("Trying DomainManager." + op + "(\"" + shortName + "\")"); okRestart("Manager." + ops[o], shortName, domain);
invokeStringArg(connector, real, op, shortName);
}
else
{
// nur wenn es der Ziel-Container selbst ist
continue;
}
System.out.println("OK:RestartInvoked method=DomainManager." + op
+ " container=" + shortName + " domain=" + domain);
System.out.flush();
return true; return true;
} }
catch (Throwable t) catch (Throwable t)
{ {
Throwable root = rootOf(t); Throwable root = rootOf(t);
warn("DomainManager." + op + " failed: " + root.getClass().getName() + ": " + root.getMessage()); String line = ops[o] + " => " + root.getClass().getName() + ": " + root.getMessage();
warn(line);
attempts.append(line).append('\n');
} }
} }
} }
catch (Throwable ignore) catch (Throwable t)
{ {
/* try next */ warn("Manager candidate " + candidates[i] + ": " + rootOf(t).getMessage());
} }
} }
// Alle AGENT-MBeans scannen nach *Container* Ops // Scan AGENT-MBeans nach Container-Ops
try try
{ {
Set agents = queryAgents(connector); Set agents = queryAgents(connector);
if (agents != null) if (agents == null)
{ {
for (Iterator it = agents.iterator(); it.hasNext(); ) return false;
}
for (Iterator it = agents.iterator(); it.hasNext(); )
{
ObjectName on = (ObjectName) it.next();
String jmxDomain = on.getDomain();
if (jmxDomain == null)
{ {
ObjectName on = (ObjectName) it.next(); continue;
String jmxDomain = on.getDomain(); }
if (jmxDomain == null) String lower = jmxDomain.toLowerCase();
{ if (!(lower.contains("domainmanager") || lower.contains(".dm")
continue; || lower.contains("collector") || lower.contains("host")
} || lower.contains("launch")))
String lower = jmxDomain.toLowerCase(); {
boolean interesting = lower.contains("domainmanager") continue;
|| lower.contains(".dm") }
|| lower.contains("collector") info("Scan manager agent " + on);
|| lower.contains("host") dumpOpsSafe(connector, on);
|| lower.contains("launch"); String[] ops = new String[] { "restartContainer", "stopContainer" };
if (!interesting) for (int i = 0; i < ops.length; i++)
{ {
continue; try
}
info("Scanning manager agent " + on);
if (tryInvokeContainerOp(connector, on, shortName, domain))
{ {
invokeStringArg(connector, on, ops[i], shortName);
okRestart(ops[i] + "@" + on, shortName, domain);
return true; return true;
} }
catch (Throwable t)
{
attempts.append(ops[i]).append('@').append(on).append(" => ")
.append(rootOf(t).getMessage()).append('\n');
}
} }
} }
} }
catch (Throwable t) catch (Throwable t)
{ {
warn("Manager scan failed: " + rootOf(t).getMessage()); warn("Manager scan: " + rootOf(t).getMessage());
} }
return false; return false;
} }
private static boolean tryInvokeContainerOp(Object connector, ObjectName on, String shortName, String domain) private static boolean looksLikeStopSideEffect(Throwable root)
{ {
String[] ops = new String[] { "restartContainer", "stopContainer" }; if (root == null || root.getMessage() == null)
for (int i = 0; i < ops.length; i++)
{ {
try return false;
{
info("Trying " + on + "." + ops[i] + "(\"" + shortName + "\")");
invokeStringArg(connector, on, ops[i], shortName);
System.out.println("OK:RestartInvoked method=" + ops[i]
+ " on=" + on + " container=" + shortName + " domain=" + domain);
System.out.flush();
return true;
}
catch (Throwable t)
{
warn(ops[i] + " on " + on + " failed: " + rootOf(t).getMessage());
}
} }
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
|| m.indexOf("broker") >= 0 && m.indexOf("down") >= 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 void invokeNoArgs(Object connector, ObjectName on, String op) throws Exception private static void invokeNoArgs(Object connector, ObjectName on, String op) throws Exception
@@ -436,26 +509,31 @@ public final class SonicMfContainerTool
}); });
} }
private static void dumpOps(Object connector, ObjectName on) private static void dumpOpsSafe(Object connector, ObjectName on)
{ {
try try
{ {
Method getInfo = connector.getClass().getMethod("getMBeanInfo", new Class[] { ObjectName.class }); Method getInfo = connector.getClass().getMethod("getMBeanInfo", new Class[] { ObjectName.class });
MBeanInfo info = (MBeanInfo) getInfo.invoke(connector, new Object[] { on }); MBeanInfo infoBean = (MBeanInfo) getInfo.invoke(connector, new Object[] { on });
if (info == null || info.getOperations() == null) if (infoBean == null || infoBean.getOperations() == null)
{ {
info("Ops(" + on + ")=(null)");
return; return;
} }
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
MBeanOperationInfo[] ops = info.getOperations(); MBeanOperationInfo[] ops = infoBean.getOperations();
for (int i = 0; i < ops.length; i++) for (int i = 0; i < ops.length; i++)
{ {
String name = ops[i].getName(); String name = ops[i].getName();
String lower = name.toLowerCase(); String lower = name.toLowerCase();
if (lower.contains("restart") || lower.contains("stop") || lower.contains("start") if (lower.indexOf("restart") >= 0 || lower.indexOf("stop") >= 0
|| lower.contains("shutdown") || lower.contains("container")) || lower.indexOf("start") >= 0 || lower.indexOf("shutdown") >= 0
|| lower.indexOf("container") >= 0)
{ {
if (sb.length() > 0) sb.append(','); if (sb.length() > 0)
{
sb.append(',');
}
sb.append(name); sb.append(name);
} }
} }
@@ -463,26 +541,28 @@ public final class SonicMfContainerTool
} }
catch (Throwable t) catch (Throwable t)
{ {
warn("getMBeanInfo failed: " + rootOf(t).getMessage()); warn("getMBeanInfo(" + on + "): " + rootOf(t).getClass().getName() + ": " + rootOf(t).getMessage());
} }
} }
private static Set queryAgents(Object connector) throws Exception private static Set queryAgents(Object connector) throws Exception
{
return queryNames(connector, new ObjectName("*:ID=AGENT"));
}
private static Set queryNames(Object connector, ObjectName pattern) throws Exception
{ {
Method query = connector.getClass().getMethod("queryNames", new Class[] { Method query = connector.getClass().getMethod("queryNames", new Class[] {
ObjectName.class, javax.management.QueryExp.class ObjectName.class, javax.management.QueryExp.class
}); });
return (Set) query.invoke(connector, new Object[] { new ObjectName("*:ID=AGENT"), null }); return (Set) query.invoke(connector, new Object[] { pattern, null });
} }
private static ObjectName resolveAgentObjectName(Object connector, String domain, String container) private static ObjectName resolveAgentObjectName(Object connector, String domain, String container)
throws Exception throws Exception
{ {
ObjectName preferred = new ObjectName(domain + "." + container + ":ID=AGENT"); ObjectName preferred = new ObjectName(domain + "." + container + ":ID=AGENT");
Method query = connector.getClass().getMethod("queryNames", new Class[] { Set exact = queryNames(connector, preferred);
ObjectName.class, javax.management.QueryExp.class
});
Set exact = (Set) query.invoke(connector, new Object[] { preferred, null });
if (exact != null && !exact.isEmpty()) if (exact != null && !exact.isEmpty())
{ {
return (ObjectName) exact.iterator().next(); return (ObjectName) exact.iterator().next();
@@ -501,7 +581,6 @@ public final class SonicMfContainerTool
} }
} }
} }
return preferred; return preferred;
} }
@@ -551,16 +630,10 @@ public final class SonicMfContainerTool
} }
} }
private static boolean isUnbounded(Throwable t)
{
String msg = t == null || t.getMessage() == null ? "" : t.getMessage();
return msg.toLowerCase().indexOf("unbounded") >= 0;
}
private static Throwable rootOf(Throwable t) private static Throwable rootOf(Throwable t)
{ {
Throwable root = t; Throwable root = t;
while (root.getCause() != null && root.getCause() != root) while (root != null && root.getCause() != null && root.getCause() != root)
{ {
root = root.getCause(); root = root.getCause();
} }
@@ -31,7 +31,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="Tools\**\*"> <None Update="Tools\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>