|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.tools.jconsole.inspector; |
|
|
|
import java.io.IOException; |
|
import java.util.*; |
|
import javax.management.*; |
|
import javax.swing.*; |
|
import javax.swing.tree.*; |
|
import sun.tools.jconsole.JConsole; |
|
import sun.tools.jconsole.MBeansTab; |
|
import sun.tools.jconsole.Messages; |
|
import sun.tools.jconsole.inspector.XNodeInfo; |
|
import static sun.tools.jconsole.inspector.XNodeInfo.Type; |
|
|
|
@SuppressWarnings("serial") |
|
public class XTree extends JTree { |
|
|
|
private static final List<String> orderedKeyPropertyList = |
|
new ArrayList<String>(); |
|
|
|
static { |
|
String keyPropertyList = |
|
System.getProperty("com.sun.tools.jconsole.mbeans.keyPropertyList"); |
|
if (keyPropertyList == null) { |
|
orderedKeyPropertyList.add("type"); |
|
orderedKeyPropertyList.add("j2eeType"); |
|
} else { |
|
StringTokenizer st = new StringTokenizer(keyPropertyList, ","); |
|
while (st.hasMoreTokens()) { |
|
orderedKeyPropertyList.add(st.nextToken()); |
|
} |
|
} |
|
} |
|
private MBeansTab mbeansTab; |
|
private Map<String, DefaultMutableTreeNode> nodes = |
|
new HashMap<String, DefaultMutableTreeNode>(); |
|
|
|
public XTree(MBeansTab mbeansTab) { |
|
this(new DefaultMutableTreeNode("MBeanTreeRootNode"), mbeansTab); |
|
} |
|
|
|
public XTree(TreeNode root, MBeansTab mbeansTab) { |
|
super(root, true); |
|
this.mbeansTab = mbeansTab; |
|
setRootVisible(false); |
|
setShowsRootHandles(true); |
|
ToolTipManager.sharedInstance().registerComponent(this); |
|
} |
|
|
|
/** |
|
* This method removes the node from its parent |
|
*/ |
|
|
|
private synchronized void removeChildNode(DefaultMutableTreeNode child) { |
|
DefaultTreeModel model = (DefaultTreeModel) getModel(); |
|
model.removeNodeFromParent(child); |
|
} |
|
|
|
/** |
|
* This method adds the child to the specified parent node |
|
* at specific index. |
|
*/ |
|
|
|
private synchronized void addChildNode( |
|
DefaultMutableTreeNode parent, |
|
DefaultMutableTreeNode child, |
|
int index) { |
|
DefaultTreeModel model = (DefaultTreeModel) getModel(); |
|
model.insertNodeInto(child, parent, index); |
|
} |
|
|
|
/** |
|
* This method adds the child to the specified parent node. |
|
* The index where the child is to be added depends on the |
|
* child node being Comparable or not. If the child node is |
|
* not Comparable then it is added at the end, i.e. right |
|
* after the current parent's children. |
|
*/ |
|
|
|
private synchronized void addChildNode( |
|
DefaultMutableTreeNode parent, DefaultMutableTreeNode child) { |
|
int childCount = parent.getChildCount(); |
|
if (childCount == 0) { |
|
addChildNode(parent, child, 0); |
|
return; |
|
} |
|
if (child instanceof ComparableDefaultMutableTreeNode) { |
|
ComparableDefaultMutableTreeNode comparableChild = |
|
(ComparableDefaultMutableTreeNode) child; |
|
for (int i = childCount - 1; i >= 0; i--) { |
|
DefaultMutableTreeNode brother = |
|
(DefaultMutableTreeNode) parent.getChildAt(i); |
|
// expr1: child node must be inserted after metadata nodes |
|
// - OR - |
|
|
|
if ((i <= 2 && isMetadataNode(brother)) || |
|
comparableChild.compareTo(brother) >= 0) { |
|
addChildNode(parent, child, i + 1); |
|
return; |
|
} |
|
} |
|
|
|
addChildNode(parent, child, 0); |
|
return; |
|
} |
|
|
|
addChildNode(parent, child, childCount); |
|
} |
|
|
|
/** |
|
* This method removes all the displayed nodes from the tree, |
|
* but does not affect actual MBeanServer contents. |
|
*/ |
|
|
|
@Override |
|
public synchronized void removeAll() { |
|
DefaultTreeModel model = (DefaultTreeModel) getModel(); |
|
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); |
|
root.removeAllChildren(); |
|
model.nodeStructureChanged(root); |
|
nodes.clear(); |
|
} |
|
|
|
|
|
public synchronized void removeMBeanFromView(ObjectName mbean) { |
|
// We assume here that MBeans are removed one by one (on MBean |
|
// unregistered notification). Deletes the tree node associated |
|
// with the given MBean and recursively all the node parents |
|
// which are leaves and non XMBean. |
|
|
|
DefaultMutableTreeNode node = null; |
|
Dn dn = new Dn(mbean); |
|
if (dn.getTokenCount() > 0) { |
|
DefaultTreeModel model = (DefaultTreeModel) getModel(); |
|
Token token = dn.getToken(0); |
|
String hashKey = dn.getHashKey(token); |
|
node = nodes.get(hashKey); |
|
if ((node != null) && (!node.isRoot())) { |
|
if (hasNonMetadataNodes(node)) { |
|
removeMetadataNodes(node); |
|
String label = token.getValue(); |
|
XNodeInfo userObject = new XNodeInfo( |
|
Type.NONMBEAN, label, |
|
label, token.getTokenValue()); |
|
changeNodeValue(node, userObject); |
|
} else { |
|
DefaultMutableTreeNode parent = |
|
(DefaultMutableTreeNode) node.getParent(); |
|
model.removeNodeFromParent(node); |
|
nodes.remove(hashKey); |
|
removeParentFromView(dn, 1, parent); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private boolean hasNonMetadataNodes(DefaultMutableTreeNode node) { |
|
for (Enumeration<?> e = node.children(); e.hasMoreElements();) { |
|
DefaultMutableTreeNode n = (DefaultMutableTreeNode) e.nextElement(); |
|
Object uo = n.getUserObject(); |
|
if (uo instanceof XNodeInfo) { |
|
switch (((XNodeInfo) uo).getType()) { |
|
case ATTRIBUTES: |
|
case NOTIFICATIONS: |
|
case OPERATIONS: |
|
break; |
|
default: |
|
return true; |
|
} |
|
} else { |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public boolean hasMetadataNodes(DefaultMutableTreeNode node) { |
|
for (Enumeration<?> e = node.children(); e.hasMoreElements();) { |
|
DefaultMutableTreeNode n = (DefaultMutableTreeNode) e.nextElement(); |
|
Object uo = n.getUserObject(); |
|
if (uo instanceof XNodeInfo) { |
|
switch (((XNodeInfo) uo).getType()) { |
|
case ATTRIBUTES: |
|
case NOTIFICATIONS: |
|
case OPERATIONS: |
|
return true; |
|
default: |
|
break; |
|
} |
|
} else { |
|
return false; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public boolean isMetadataNode(DefaultMutableTreeNode node) { |
|
Object uo = node.getUserObject(); |
|
if (uo instanceof XNodeInfo) { |
|
switch (((XNodeInfo) uo).getType()) { |
|
case ATTRIBUTES: |
|
case NOTIFICATIONS: |
|
case OPERATIONS: |
|
return true; |
|
default: |
|
return false; |
|
} |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** |
|
* Remove the metadata nodes associated with a given MBean node. |
|
*/ |
|
|
|
private void removeMetadataNodes(DefaultMutableTreeNode node) { |
|
Set<DefaultMutableTreeNode> metadataNodes = |
|
new HashSet<DefaultMutableTreeNode>(); |
|
DefaultTreeModel model = (DefaultTreeModel) getModel(); |
|
for (Enumeration<?> e = node.children(); e.hasMoreElements();) { |
|
DefaultMutableTreeNode n = (DefaultMutableTreeNode) e.nextElement(); |
|
Object uo = n.getUserObject(); |
|
if (uo instanceof XNodeInfo) { |
|
switch (((XNodeInfo) uo).getType()) { |
|
case ATTRIBUTES: |
|
case NOTIFICATIONS: |
|
case OPERATIONS: |
|
metadataNodes.add(n); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
} |
|
for (DefaultMutableTreeNode n : metadataNodes) { |
|
model.removeNodeFromParent(n); |
|
} |
|
} |
|
|
|
/** |
|
* Removes only the parent nodes which are non MBean and leaf. |
|
* This method assumes the child nodes have been removed before. |
|
*/ |
|
|
|
private DefaultMutableTreeNode removeParentFromView( |
|
Dn dn, int index, DefaultMutableTreeNode node) { |
|
if ((!node.isRoot()) && node.isLeaf() && |
|
(!(((XNodeInfo) node.getUserObject()).getType().equals(Type.MBEAN)))) { |
|
DefaultMutableTreeNode parent = |
|
(DefaultMutableTreeNode) node.getParent(); |
|
removeChildNode(node); |
|
String hashKey = dn.getHashKey(dn.getToken(index)); |
|
nodes.remove(hashKey); |
|
removeParentFromView(dn, index + 1, parent); |
|
} |
|
return node; |
|
} |
|
|
|
|
|
public synchronized void addMBeansToView(Set<ObjectName> mbeans) { |
|
Set<Dn> dns = new TreeSet<Dn>(); |
|
for (ObjectName mbean : mbeans) { |
|
Dn dn = new Dn(mbean); |
|
dns.add(dn); |
|
} |
|
for (Dn dn : dns) { |
|
ObjectName mbean = dn.getObjectName(); |
|
XMBean xmbean = new XMBean(mbean, mbeansTab); |
|
addMBeanToView(mbean, xmbean, dn); |
|
} |
|
} |
|
|
|
|
|
public synchronized void addMBeanToView(ObjectName mbean) { |
|
// Build XMBean for the given MBean |
|
|
|
XMBean xmbean = new XMBean(mbean, mbeansTab); |
|
// Build Dn for the given MBean |
|
|
|
Dn dn = new Dn(mbean); |
|
// Add the new nodes to the MBean tree from leaf to root |
|
|
|
addMBeanToView(mbean, xmbean, dn); |
|
} |
|
|
|
|
|
private synchronized void addMBeanToView( |
|
ObjectName mbean, XMBean xmbean, Dn dn) { |
|
|
|
DefaultMutableTreeNode childNode = null; |
|
DefaultMutableTreeNode parentNode = null; |
|
|
|
// Add the node or replace its user object if already added |
|
|
|
Token token = dn.getToken(0); |
|
String hashKey = dn.getHashKey(token); |
|
if (nodes.containsKey(hashKey)) { |
|
// Found existing node previously created when adding another node |
|
|
|
childNode = nodes.get(hashKey); |
|
// Replace user object to reflect that this node is an MBean |
|
|
|
Object data = createNodeValue(xmbean, token); |
|
String label = data.toString(); |
|
XNodeInfo userObject = |
|
new XNodeInfo(Type.MBEAN, data, label, mbean.toString()); |
|
changeNodeValue(childNode, userObject); |
|
return; |
|
} |
|
|
|
// Create new leaf node |
|
|
|
childNode = createDnNode(dn, token, xmbean); |
|
nodes.put(hashKey, childNode); |
|
|
|
// Add intermediate non MBean nodes |
|
|
|
for (int i = 1; i < dn.getTokenCount(); i++) { |
|
token = dn.getToken(i); |
|
hashKey = dn.getHashKey(token); |
|
if (nodes.containsKey(hashKey)) { |
|
// Intermediate node already present, add new node as child |
|
|
|
parentNode = nodes.get(hashKey); |
|
addChildNode(parentNode, childNode); |
|
return; |
|
} else { |
|
// Create new intermediate node |
|
|
|
if ("domain".equals(token.getTokenType())) { |
|
parentNode = createDomainNode(dn, token); |
|
DefaultMutableTreeNode root = |
|
(DefaultMutableTreeNode) getModel().getRoot(); |
|
addChildNode(root, parentNode); |
|
} else { |
|
parentNode = createSubDnNode(dn, token); |
|
} |
|
nodes.put(hashKey, parentNode); |
|
addChildNode(parentNode, childNode); |
|
} |
|
childNode = parentNode; |
|
} |
|
} |
|
|
|
|
|
private synchronized void changeNodeValue( |
|
DefaultMutableTreeNode node, XNodeInfo nodeValue) { |
|
if (node instanceof ComparableDefaultMutableTreeNode) { |
|
|
|
DefaultMutableTreeNode clone = |
|
(DefaultMutableTreeNode) node.clone(); |
|
clone.setUserObject(nodeValue); |
|
if (((ComparableDefaultMutableTreeNode) node).compareTo(clone) == 0) { |
|
|
|
node.setUserObject(nodeValue); |
|
DefaultTreeModel model = (DefaultTreeModel) getModel(); |
|
model.nodeChanged(node); |
|
} else { |
|
// delete the node and re-order it in case the |
|
|
|
DefaultMutableTreeNode parent = |
|
(DefaultMutableTreeNode) node.getParent(); |
|
removeChildNode(node); |
|
node.setUserObject(nodeValue); |
|
addChildNode(parent, node); |
|
} |
|
} else { |
|
|
|
node.setUserObject(nodeValue); |
|
DefaultTreeModel model = (DefaultTreeModel) getModel(); |
|
model.nodeChanged(node); |
|
} |
|
|
|
if (nodeValue.getType().equals(Type.MBEAN)) { |
|
removeMetadataNodes(node); |
|
TreeNode[] treeNodes = node.getPath(); |
|
TreePath path = new TreePath(treeNodes); |
|
if (isExpanded(path)) { |
|
addMetadataNodes(node); |
|
} |
|
} |
|
// Clear the current selection and set it |
|
|
|
if (node == getLastSelectedPathComponent()) { |
|
TreePath selectionPath = getSelectionPath(); |
|
clearSelection(); |
|
setSelectionPath(selectionPath); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private DefaultMutableTreeNode createDomainNode(Dn dn, Token token) { |
|
DefaultMutableTreeNode node = new ComparableDefaultMutableTreeNode(); |
|
String label = dn.getDomain(); |
|
XNodeInfo userObject = |
|
new XNodeInfo(Type.NONMBEAN, label, label, label); |
|
node.setUserObject(userObject); |
|
return node; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private DefaultMutableTreeNode createDnNode( |
|
Dn dn, Token token, XMBean xmbean) { |
|
DefaultMutableTreeNode node = new ComparableDefaultMutableTreeNode(); |
|
Object data = createNodeValue(xmbean, token); |
|
String label = data.toString(); |
|
XNodeInfo userObject = new XNodeInfo(Type.MBEAN, data, label, |
|
xmbean.getObjectName().toString()); |
|
node.setUserObject(userObject); |
|
return node; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private DefaultMutableTreeNode createSubDnNode(Dn dn, Token token) { |
|
DefaultMutableTreeNode node = new ComparableDefaultMutableTreeNode(); |
|
String label = isKeyValueView() ? token.getTokenValue() : token.getValue(); |
|
XNodeInfo userObject = |
|
new XNodeInfo(Type.NONMBEAN, label, label, token.getTokenValue()); |
|
node.setUserObject(userObject); |
|
return node; |
|
} |
|
|
|
private Object createNodeValue(XMBean xmbean, Token token) { |
|
String label = isKeyValueView() ? token.getTokenValue() : token.getValue(); |
|
xmbean.setText(label); |
|
return xmbean; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static Map<String, String> extractKeyValuePairs( |
|
String props, ObjectName mbean) { |
|
Map<String, String> map = new LinkedHashMap<String, String>(); |
|
int eq = props.indexOf("="); |
|
while (eq != -1) { |
|
String key = props.substring(0, eq); |
|
String value = mbean.getKeyProperty(key); |
|
map.put(key, value); |
|
props = props.substring(key.length() + 1 + value.length()); |
|
if (props.startsWith(",")) { |
|
props = props.substring(1); |
|
} |
|
eq = props.indexOf("="); |
|
} |
|
return map; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static String getKeyPropertyListString(ObjectName mbean) { |
|
String props = mbean.getKeyPropertyListString(); |
|
Map<String, String> map = extractKeyValuePairs(props, mbean); |
|
StringBuilder sb = new StringBuilder(); |
|
// Add the key/value pairs to the buffer following the |
|
|
|
for (String key : orderedKeyPropertyList) { |
|
if (map.containsKey(key)) { |
|
sb.append(key + "=" + map.get(key) + ","); |
|
map.remove(key); |
|
} |
|
} |
|
|
|
for (Map.Entry<String, String> entry : map.entrySet()) { |
|
sb.append(entry.getKey() + "=" + entry.getValue() + ","); |
|
} |
|
String orderedKeyPropertyListString = sb.toString(); |
|
orderedKeyPropertyListString = orderedKeyPropertyListString.substring( |
|
0, orderedKeyPropertyListString.length() - 1); |
|
return orderedKeyPropertyListString; |
|
} |
|
|
|
|
|
public void addMetadataNodes(DefaultMutableTreeNode node) { |
|
XMBean mbean = (XMBean) ((XNodeInfo) node.getUserObject()).getData(); |
|
DefaultTreeModel model = (DefaultTreeModel) getModel(); |
|
MBeanInfoNodesSwingWorker sw = |
|
new MBeanInfoNodesSwingWorker(model, node, mbean); |
|
if (sw != null) { |
|
sw.execute(); |
|
} |
|
} |
|
|
|
private static class MBeanInfoNodesSwingWorker |
|
extends SwingWorker<Object[], Void> { |
|
|
|
private final DefaultTreeModel model; |
|
private final DefaultMutableTreeNode node; |
|
private final XMBean mbean; |
|
|
|
public MBeanInfoNodesSwingWorker( |
|
DefaultTreeModel model, |
|
DefaultMutableTreeNode node, |
|
XMBean mbean) { |
|
this.model = model; |
|
this.node = node; |
|
this.mbean = mbean; |
|
} |
|
|
|
@Override |
|
public Object[] doInBackground() throws InstanceNotFoundException, |
|
IntrospectionException, ReflectionException, IOException { |
|
Object result[] = new Object[2]; |
|
|
|
result[0] = mbean.getMBeanInfo(); |
|
|
|
result[1] = mbean.isBroadcaster(); |
|
return result; |
|
} |
|
|
|
@Override |
|
protected void done() { |
|
try { |
|
Object result[] = get(); |
|
MBeanInfo mbeanInfo = (MBeanInfo) result[0]; |
|
Boolean isBroadcaster = (Boolean) result[1]; |
|
if (mbeanInfo != null) { |
|
addMBeanInfoNodes(model, node, mbean, mbeanInfo, isBroadcaster); |
|
} |
|
} catch (Exception e) { |
|
Throwable t = Utils.getActualException(e); |
|
if (JConsole.isDebug()) { |
|
t.printStackTrace(); |
|
} |
|
} |
|
} |
|
|
|
|
|
private void addMBeanInfoNodes( |
|
DefaultTreeModel tree, DefaultMutableTreeNode node, |
|
XMBean mbean, MBeanInfo mbeanInfo, Boolean isBroadcaster) { |
|
MBeanAttributeInfo[] ai = mbeanInfo.getAttributes(); |
|
MBeanOperationInfo[] oi = mbeanInfo.getOperations(); |
|
MBeanNotificationInfo[] ni = mbeanInfo.getNotifications(); |
|
|
|
// Insert the Attributes/Operations/Notifications metadata nodes as |
|
// the three first children of this MBean node. This is only useful |
|
// when this MBean node denotes an MBean but it's not a leaf in the |
|
// MBean tree |
|
|
|
int childIndex = 0; |
|
|
|
// MBeanAttributeInfo node |
|
|
|
if (ai != null && ai.length > 0) { |
|
DefaultMutableTreeNode attributes = new DefaultMutableTreeNode(); |
|
XNodeInfo attributesUO = new XNodeInfo(Type.ATTRIBUTES, mbean, |
|
Messages.ATTRIBUTES, null); |
|
attributes.setUserObject(attributesUO); |
|
node.insert(attributes, childIndex++); |
|
for (MBeanAttributeInfo mbai : ai) { |
|
DefaultMutableTreeNode attribute = new DefaultMutableTreeNode(); |
|
XNodeInfo attributeUO = new XNodeInfo(Type.ATTRIBUTE, |
|
new Object[]{mbean, mbai}, mbai.getName(), null); |
|
attribute.setUserObject(attributeUO); |
|
attribute.setAllowsChildren(false); |
|
attributes.add(attribute); |
|
} |
|
} |
|
// MBeanOperationInfo node |
|
|
|
if (oi != null && oi.length > 0) { |
|
DefaultMutableTreeNode operations = new DefaultMutableTreeNode(); |
|
XNodeInfo operationsUO = new XNodeInfo(Type.OPERATIONS, mbean, |
|
Messages.OPERATIONS, null); |
|
operations.setUserObject(operationsUO); |
|
node.insert(operations, childIndex++); |
|
for (MBeanOperationInfo mboi : oi) { |
|
// Compute the operation's tool tip text: |
|
// "operationname(param1type,param2type,...)" |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
for (MBeanParameterInfo mbpi : mboi.getSignature()) { |
|
sb.append(mbpi.getType() + ","); |
|
} |
|
String signature = sb.toString(); |
|
if (signature.length() > 0) { |
|
// Remove the trailing ',' |
|
|
|
signature = signature.substring(0, signature.length() - 1); |
|
} |
|
String toolTipText = mboi.getName() + "(" + signature + ")"; |
|
// Create operation node |
|
|
|
DefaultMutableTreeNode operation = new DefaultMutableTreeNode(); |
|
XNodeInfo operationUO = new XNodeInfo(Type.OPERATION, |
|
new Object[]{mbean, mboi}, mboi.getName(), toolTipText); |
|
operation.setUserObject(operationUO); |
|
operation.setAllowsChildren(false); |
|
operations.add(operation); |
|
} |
|
} |
|
// MBeanNotificationInfo node |
|
|
|
if (isBroadcaster != null && isBroadcaster.booleanValue()) { |
|
DefaultMutableTreeNode notifications = new DefaultMutableTreeNode(); |
|
XNodeInfo notificationsUO = new XNodeInfo(Type.NOTIFICATIONS, mbean, |
|
Messages.NOTIFICATIONS, null); |
|
notifications.setUserObject(notificationsUO); |
|
node.insert(notifications, childIndex++); |
|
if (ni != null && ni.length > 0) { |
|
for (MBeanNotificationInfo mbni : ni) { |
|
DefaultMutableTreeNode notification = |
|
new DefaultMutableTreeNode(); |
|
XNodeInfo notificationUO = new XNodeInfo(Type.NOTIFICATION, |
|
mbni, mbni.getName(), null); |
|
notification.setUserObject(notificationUO); |
|
notification.setAllowsChildren(false); |
|
notifications.add(notification); |
|
} |
|
} |
|
} |
|
// Update tree model |
|
|
|
model.reload(node); |
|
} |
|
} |
|
// |
|
// Tree preferences |
|
|
|
private static boolean treeView; |
|
private static boolean treeViewInit = false; |
|
|
|
private static boolean isTreeView() { |
|
if (!treeViewInit) { |
|
treeView = getTreeViewValue(); |
|
treeViewInit = true; |
|
} |
|
return treeView; |
|
} |
|
|
|
private static boolean getTreeViewValue() { |
|
String tv = System.getProperty("treeView"); |
|
return ((tv == null) ? true : !(tv.equals("false"))); |
|
} |
|
// |
|
// MBean key-value preferences |
|
|
|
private boolean keyValueView = Boolean.getBoolean("keyValueView"); |
|
|
|
private boolean isKeyValueView() { |
|
return keyValueView; |
|
} |
|
|
|
// |
|
// Utility classes |
|
|
|
private static class ComparableDefaultMutableTreeNode |
|
extends DefaultMutableTreeNode |
|
implements Comparable<DefaultMutableTreeNode> { |
|
|
|
public int compareTo(DefaultMutableTreeNode node) { |
|
return (this.toString().compareTo(node.toString())); |
|
} |
|
} |
|
|
|
private static class Dn implements Comparable<Dn> { |
|
|
|
private ObjectName mbean; |
|
private String domain; |
|
private String keyPropertyList; |
|
private String hashDn; |
|
private List<Token> tokens = new ArrayList<Token>(); |
|
|
|
public Dn(ObjectName mbean) { |
|
this.mbean = mbean; |
|
this.domain = mbean.getDomain(); |
|
this.keyPropertyList = getKeyPropertyListString(mbean); |
|
|
|
if (isTreeView()) { |
|
|
|
Map<String, String> map = |
|
extractKeyValuePairs(keyPropertyList, mbean); |
|
for (Map.Entry<String, String> entry : map.entrySet()) { |
|
tokens.add(new Token("key", entry.getKey() + "=" + entry.getValue())); |
|
} |
|
} else { |
|
|
|
tokens.add(new Token("key", "properties=" + keyPropertyList)); |
|
} |
|
|
|
|
|
tokens.add(0, new Token("domain", "domain=" + domain)); |
|
|
|
|
|
Collections.reverse(tokens); |
|
|
|
|
|
computeHashDn(); |
|
} |
|
|
|
public ObjectName getObjectName() { |
|
return mbean; |
|
} |
|
|
|
public String getDomain() { |
|
return domain; |
|
} |
|
|
|
public String getKeyPropertyList() { |
|
return keyPropertyList; |
|
} |
|
|
|
public Token getToken(int index) { |
|
return tokens.get(index); |
|
} |
|
|
|
public int getTokenCount() { |
|
return tokens.size(); |
|
} |
|
|
|
public String getHashDn() { |
|
return hashDn; |
|
} |
|
|
|
public String getHashKey(Token token) { |
|
final int begin = hashDn.indexOf(token.getTokenValue()); |
|
return hashDn.substring(begin, hashDn.length()); |
|
} |
|
|
|
private void computeHashDn() { |
|
if (tokens.isEmpty()) { |
|
return; |
|
} |
|
final StringBuilder hdn = new StringBuilder(); |
|
for (int i = 0; i < tokens.size(); i++) { |
|
hdn.append(tokens.get(i).getTokenValue()); |
|
hdn.append(","); |
|
} |
|
hashDn = hdn.substring(0, hdn.length() - 1); |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
return domain + ":" + keyPropertyList; |
|
} |
|
|
|
public int compareTo(Dn dn) { |
|
return this.toString().compareTo(dn.toString()); |
|
} |
|
} |
|
|
|
private static class Token { |
|
|
|
private String tokenType; |
|
private String tokenValue; |
|
private String key; |
|
private String value; |
|
|
|
public Token(String tokenType, String tokenValue) { |
|
this.tokenType = tokenType; |
|
this.tokenValue = tokenValue; |
|
buildKeyValue(); |
|
} |
|
|
|
public String getTokenType() { |
|
return tokenType; |
|
} |
|
|
|
public String getTokenValue() { |
|
return tokenValue; |
|
} |
|
|
|
public String getKey() { |
|
return key; |
|
} |
|
|
|
public String getValue() { |
|
return value; |
|
} |
|
|
|
private void buildKeyValue() { |
|
int index = tokenValue.indexOf("="); |
|
if (index < 0) { |
|
key = tokenValue; |
|
value = tokenValue; |
|
} else { |
|
key = tokenValue.substring(0, index); |
|
value = tokenValue.substring(index + 1, tokenValue.length()); |
|
} |
|
} |
|
} |
|
} |