/* * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.jconsole.inspector; import java.awt.Component;import java.awt.EventQueue;import java.awt.Dimension;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.io.IOException; import java.lang.reflect.Array; import java.util.EventObject;import java.util.HashMap;import java.util.WeakHashMap; import java.util.concurrent.ExecutionException;import java.util.logging.Level;import java.util.logging.Logger;import javax.management.JMException;import javax.management.MBeanInfo;import javax.management.MBeanAttributeInfo;import javax.management.AttributeList;import javax.management.Attribute;import javax.management.openmbean.CompositeData;import javax.management.openmbean.TabularData; import javax.swing.JComponent;import javax.swing.JOptionPane;import javax.swing.JTable;import javax.swing.JTextField;import javax.swing.SwingWorker;import javax.swing.event.ChangeEvent;import javax.swing.event.TableModelEvent;import javax.swing.event.TableModelListener;import javax.swing.table.DefaultTableCellRenderer;import javax.swing.table.DefaultTableModel;import javax.swing.table.TableCellEditor;import javax.swing.table.TableCellRenderer;import javax.swing.table.TableColumn;import javax.swing.table.TableColumnModel;import javax.swing.table.TableModel; import sun.tools.jconsole.Resources;import sun.tools.jconsole.MBeansTab;import sun.tools.jconsole.JConsole;import sun.tools.jconsole.ProxyClient.SnapshotMBeanServerConnection; /*IMPORTANT : There is a deadlock issue there if we don't synchronize well loadAttributes, refresh attributes and empty table methods since a UI thread can call loadAttributes and at the same time a JMX notification can raise an emptyTable. Since there are synchronization in the JMX world it's COMPULSORY to not call the JMX world in synchronized blocks */@SuppressWarnings("serial")public class XMBeanAttributes extends XTable { final Logger LOGGER = Logger.getLogger(XMBeanAttributes.class.getPackage().getName()); private final static String[] columnNames = {Resources.getText("Name"), Resources.getText("Value")}; private XMBean mbean; private MBeanInfo mbeanInfo; private MBeanAttributeInfo[] attributesInfo; private HashMap<String, Object> attributes; private HashMap<String, Object> unavailableAttributes; private HashMap<String, Object> viewableAttributes; private WeakHashMap<XMBean, HashMap<String, ZoomedCell>> viewersCache = new WeakHashMap<XMBean, HashMap<String, ZoomedCell>>(); private final TableModelListener attributesListener; private MBeansTab mbeansTab; private TableCellEditor valueCellEditor = new ValueCellEditor(); private int rowMinHeight = -1; private AttributesMouseListener mouseListener = new AttributesMouseListener(); private static TableCellEditor editor = new Utils.ReadOnlyTableCellEditor(new JTextField()); public XMBeanAttributes(MBeansTab mbeansTab) { super(); this.mbeansTab = mbeansTab; ((DefaultTableModel)getModel()).setColumnIdentifiers(columnNames); attributesListener = new AttributesListener(this); getModel().addTableModelListener(attributesListener); getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(40); addMouseListener(mouseListener); getTableHeader().setReorderingAllowed(false); setColumnEditors(); addKeyListener(new Utils.CopyKeyAdapter()); } @Override public synchronized Component prepareRenderer(TableCellRenderer renderer, int row, int column) { //In case we have a repaint thread that is in the process of //repainting an obsolete table, just ignore the call. //It can happen when MBean selection is switched at a very quick rate if(row >= getRowCount()) return null; else return super.prepareRenderer(renderer, row, column); } void updateRowHeight(Object obj, int row) { ZoomedCell cell = null; if(obj instanceof ZoomedCell) { cell = (ZoomedCell) obj; if(cell.isInited()) setRowHeight(row, cell.getHeight()); else if(rowMinHeight != - 1) setRowHeight(row, rowMinHeight); } else if(rowMinHeight != - 1) setRowHeight(row, rowMinHeight); } @Override public synchronized TableCellRenderer getCellRenderer(int row, int column) { //In case we have a repaint thread that is in the process of //repainting an obsolete table, just ignore the call. //It can happen when MBean selection is switched at a very quick rate if (row >= getRowCount()) { return null; } else { if (column == VALUE_COLUMN) { Object obj = getModel().getValueAt(row, column); if (obj instanceof ZoomedCell) { ZoomedCell cell = (ZoomedCell) obj; if (cell.isInited()) { DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) cell.getRenderer(); renderer.setToolTipText(getToolTip(row,column)); return renderer; } } } DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getCellRenderer(row, column); if (!isCellError(row, column)) { if (!(isColumnEditable(column) && isWritable(row) && Utils.isEditableType(getClassName(row)))) { renderer.setForeground(getDefaultColor()); } } return renderer; } } private void setColumnEditors() { TableColumnModel tcm = getColumnModel(); for (int i = 0; i < columnNames.length; i++) { TableColumn tc = tcm.getColumn(i); if (isColumnEditable(i)) { tc.setCellEditor(valueCellEditor); } else { tc.setCellEditor(editor); } } } public void cancelCellEditing() { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("Cancel Editing Row: "+getEditingRow()); } final TableCellEditor tableCellEditor = getCellEditor(); if (tableCellEditor != null) { tableCellEditor.cancelCellEditing(); } } public void stopCellEditing() { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("Stop Editing Row: "+getEditingRow()); } final TableCellEditor tableCellEditor = getCellEditor(); if (tableCellEditor != null) { tableCellEditor.stopCellEditing(); } } @Override public final boolean editCellAt(final int row, final int column, EventObject e) { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("editCellAt(row="+row+", col="+column+ ", e="+e+")"); } if (JConsole.isDebug()) { System.err.println("edit: "+getValueName(row)+"="+getValue(row)); } boolean retVal = super.editCellAt(row, column, e); if (retVal) { final TableCellEditor tableCellEditor = getColumnModel().getColumn(column).getCellEditor(); if (tableCellEditor == valueCellEditor) { ((JComponent) tableCellEditor).requestFocus(); } } return retVal; } @Override public boolean isCellEditable(int row, int col) { // All the cells in non-editable columns are editable if (!isColumnEditable(col)) { return true; } // Maximized zoomed cells are editable Object obj = getModel().getValueAt(row, col); if (obj instanceof ZoomedCell) { ZoomedCell cell = (ZoomedCell) obj; return cell.isMaximized(); } return true; } @Override public void setValueAt(Object value, int row, int column) { if (!isCellError(row, column) && isColumnEditable(column) && isWritable(row) && Utils.isEditableType(getClassName(row))) { if (JConsole.isDebug()) { System.err.println("validating [row="+row+", column="+column+ "]: "+getValueName(row)+"="+value); } super.setValueAt(value, row, column); } } //Table methods public boolean isTableEditable() { return true; } public void setTableValue(Object value, int row) { } public boolean isColumnEditable(int column) { if (column < getColumnCount()) { return getColumnName(column).equals(Resources.getText("Value")); } else { return false; } } public String getClassName(int row) { int index = convertRowToIndex(row); if (index != -1) { return attributesInfo[index].getType(); } else { return null; } } public String getValueName(int row) { int index = convertRowToIndex(row); if (index != -1) { return attributesInfo[index].getName(); } else { return null; } } public Object getValue(int row) { final Object val = ((DefaultTableModel) getModel()) .getValueAt(row, VALUE_COLUMN); return val; } //tool tip only for editable column @Override public String getToolTip(int row, int column) { if (isCellError(row, column)) { return (String) unavailableAttributes.get(getValueName(row)); } if (isColumnEditable(column)) { Object value = getValue(row); String tip = null; if (value != null) { tip = value.toString(); if(isAttributeViewable(row, VALUE_COLUMN)) tip = Resources.getText("Double click to expand/collapse")+ ". " + tip; } return tip; } if(column == NAME_COLUMN) { int index = convertRowToIndex(row); if (index != -1) { return attributesInfo[index].getDescription(); } } return null; } public synchronized boolean isWritable(int row) { int index = convertRowToIndex(row); if (index != -1) { return (attributesInfo[index].isWritable()); } else { return false; } } /** * Override JTable method in order to make any call to this method * atomic with TableModel elements. */ @Override public synchronized int getRowCount() { return super.getRowCount(); } public synchronized boolean isReadable(int row) { int index = convertRowToIndex(row); if (index != -1) { return (attributesInfo[index].isReadable()); } else { return false; } } public synchronized boolean isCellError(int row, int col) { return (isColumnEditable(col) && (unavailableAttributes.containsKey(getValueName(row)))); } public synchronized boolean isAttributeViewable(int row, int col) { boolean isViewable = false; if(col == VALUE_COLUMN) { Object obj = getModel().getValueAt(row, col); if(obj instanceof ZoomedCell) isViewable = true; } return isViewable; } // Call this in EDT public void loadAttributes(final XMBean mbean, final MBeanInfo mbeanInfo) { final SwingWorker<Runnable,Void> load = new SwingWorker<Runnable,Void>() { @Override protected Runnable doInBackground() throws Exception { return doLoadAttributes(mbean,mbeanInfo); } @Override protected void done() { try { final Runnable updateUI = get(); if (updateUI != null) updateUI.run(); } catch (RuntimeException x) { throw x; } catch (ExecutionException x) { if(JConsole.isDebug()) { System.err.println( "Exception raised while loading attributes: " +x.getCause()); x.printStackTrace(); } } catch (InterruptedException x) { if(JConsole.isDebug()) { System.err.println( "Interrupted while loading attributes: "+x); x.printStackTrace(); } } } }; mbeansTab.workerAdd(load); } // Don't call this in EDT, but execute returned Runnable inside // EDT - typically in the done() method of a SwingWorker // This method can return null. private Runnable doLoadAttributes(final XMBean mbean, MBeanInfo infoOrNull) throws JMException, IOException { // To avoid deadlock with events coming from the JMX side, // we retrieve all JMX stuff in a non synchronized block. if(mbean == null) return null; final MBeanInfo curMBeanInfo = (infoOrNull==null)?mbean.getMBeanInfo():infoOrNull; final MBeanAttributeInfo[] attrsInfo = curMBeanInfo.getAttributes(); final HashMap<String, Object> attrs = new HashMap<String, Object>(attrsInfo.length); final HashMap<String, Object> unavailableAttrs = new HashMap<String, Object>(attrsInfo.length); final HashMap<String, Object> viewableAttrs = new HashMap<String, Object>(attrsInfo.length); AttributeList list = null; try { list = mbean.getAttributes(attrsInfo); }catch(Exception e) { if (JConsole.isDebug()) { System.err.println("Error calling getAttributes() on MBean \"" + mbean.getObjectName() + "\". JConsole will " + "try to get them individually calling " + "getAttribute() instead. Exception:"); e.printStackTrace(System.err); } list = new AttributeList(); //Can't load all attributes, do it one after each other. for(int i = 0; i < attrsInfo.length; i++) { String name = null; try { name = attrsInfo[i].getName(); Object value = mbean.getMBeanServerConnection(). getAttribute(mbean.getObjectName(), name); list.add(new Attribute(name, value)); }catch(Exception ex) { if(attrsInfo[i].isReadable()) { unavailableAttrs.put(name, Utils.getActualException(ex).toString()); } } } } try { int att_length = list.size(); for (int i=0;i<att_length;i++) { Attribute attribute = (Attribute) list.get(i); if(isViewable(attribute)) { viewableAttrs.put(attribute.getName(), attribute.getValue()); } else attrs.put(attribute.getName(),attribute.getValue()); } // if not all attributes are accessible, // check them one after the other. if (att_length < attrsInfo.length) { for (int i=0;i<attrsInfo.length;i++) { MBeanAttributeInfo attributeInfo = attrsInfo[i]; if (!attrs.containsKey(attributeInfo.getName()) && !viewableAttrs.containsKey(attributeInfo. getName()) && !unavailableAttrs.containsKey(attributeInfo. getName())) { if (attributeInfo.isReadable()) { // getAttributes didn't help resolving the // exception. // We must call it again to understand what // went wrong. try { Object v = mbean.getMBeanServerConnection().getAttribute( mbean.getObjectName(), attributeInfo.getName()); //What happens if now it is ok? // Be pragmatic, add it to readable... attrs.put(attributeInfo.getName(), v); }catch(Exception e) { //Put the exception that will be displayed // in tooltipLines 1–500 of 1077. Load more
/* * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.jconsole.inspector; import java.awt.Component; import java.awt.EventQueue; import java.awt.Dimension; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; import java.lang.reflect.Array; import java.util.EventObject; import java.util.HashMap; import java.util.WeakHashMap; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import javax.management.JMException; import javax.management.MBeanInfo; import javax.management.MBeanAttributeInfo; import javax.management.AttributeList; import javax.management.Attribute; import javax.management.openmbean.CompositeData; import javax.management.openmbean.TabularData; import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.SwingWorker; import javax.swing.event.ChangeEvent; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; import sun.tools.jconsole.Resources; import sun.tools.jconsole.MBeansTab; import sun.tools.jconsole.JConsole; import sun.tools.jconsole.ProxyClient.SnapshotMBeanServerConnection; /*IMPORTANT : There is a deadlock issue there if we don't synchronize well loadAttributes, refresh attributes and empty table methods since a UI thread can call loadAttributes and at the same time a JMX notification can raise an emptyTable. Since there are synchronization in the JMX world it's COMPULSORY to not call the JMX world in synchronized blocks */ @SuppressWarnings("serial") public class XMBeanAttributes extends XTable { final Logger LOGGER = Logger.getLogger(XMBeanAttributes.class.getPackage().getName()); private final static String[] columnNames = {Resources.getText("Name"), Resources.getText("Value")}; private XMBean mbean; private MBeanInfo mbeanInfo; private MBeanAttributeInfo[] attributesInfo; private HashMap<String, Object> attributes; private HashMap<String, Object> unavailableAttributes; private HashMap<String, Object> viewableAttributes; private WeakHashMap<XMBean, HashMap<String, ZoomedCell>> viewersCache = new WeakHashMap<XMBean, HashMap<String, ZoomedCell>>(); private final TableModelListener attributesListener; private MBeansTab mbeansTab; private TableCellEditor valueCellEditor = new ValueCellEditor(); private int rowMinHeight = -1; private AttributesMouseListener mouseListener = new AttributesMouseListener(); private static TableCellEditor editor = new Utils.ReadOnlyTableCellEditor(new JTextField()); public XMBeanAttributes(MBeansTab mbeansTab) { super(); this.mbeansTab = mbeansTab; ((DefaultTableModel)getModel()).setColumnIdentifiers(columnNames); attributesListener = new AttributesListener(this); getModel().addTableModelListener(attributesListener); getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(40); addMouseListener(mouseListener); getTableHeader().setReorderingAllowed(false); setColumnEditors(); addKeyListener(new Utils.CopyKeyAdapter()); } @Override public synchronized Component prepareRenderer(TableCellRenderer renderer, int row, int column) { //In case we have a repaint thread that is in the process of //repainting an obsolete table, just ignore the call. //It can happen when MBean selection is switched at a very quick rate if(row >= getRowCount()) return null; else return super.prepareRenderer(renderer, row, column); } void updateRowHeight(Object obj, int row) { ZoomedCell cell = null; if(obj instanceof ZoomedCell) { cell = (ZoomedCell) obj; if(cell.isInited()) setRowHeight(row, cell.getHeight()); else if(rowMinHeight != - 1) setRowHeight(row, rowMinHeight); } else if(rowMinHeight != - 1) setRowHeight(row, rowMinHeight); } @Override public synchronized TableCellRenderer getCellRenderer(int row, int column) { //In case we have a repaint thread that is in the process of //repainting an obsolete table, just ignore the call. //It can happen when MBean selection is switched at a very quick rate if (row >= getRowCount()) { return null; } else { if (column == VALUE_COLUMN) { Object obj = getModel().getValueAt(row, column); if (obj instanceof ZoomedCell) { ZoomedCell cell = (ZoomedCell) obj; if (cell.isInited()) { DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) cell.getRenderer(); renderer.setToolTipText(getToolTip(row,column)); return renderer; } } } DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getCellRenderer(row, column); if (!isCellError(row, column)) { if (!(isColumnEditable(column) && isWritable(row) && Utils.isEditableType(getClassName(row)))) { renderer.setForeground(getDefaultColor()); } } return renderer; } } private void setColumnEditors() { TableColumnModel tcm = getColumnModel(); for (int i = 0; i < columnNames.length; i++) { TableColumn tc = tcm.getColumn(i); if (isColumnEditable(i)) { tc.setCellEditor(valueCellEditor); } else { tc.setCellEditor(editor); } } } public void cancelCellEditing() { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("Cancel Editing Row: "+getEditingRow()); } final TableCellEditor tableCellEditor = getCellEditor(); if (tableCellEditor != null) { tableCellEditor.cancelCellEditing(); } } public void stopCellEditing() { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("Stop Editing Row: "+getEditingRow()); } final TableCellEditor tableCellEditor = getCellEditor(); if (tableCellEditor != null) { tableCellEditor.stopCellEditing(); } } @Override public final boolean editCellAt(final int row, final int column, EventObject e) { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("editCellAt(row="+row+", col="+column+ ", e="+e+")"); } if (JConsole.isDebug()) { System.err.println("edit: "+getValueName(row)+"="+getValue(row)); } boolean retVal = super.editCellAt(row, column, e); if (retVal) { final TableCellEditor tableCellEditor = getColumnModel().getColumn(column).getCellEditor(); if (tableCellEditor == valueCellEditor) { ((JComponent) tableCellEditor).requestFocus(); } } return retVal; } @Override public boolean isCellEditable(int row, int col) { // All the cells in non-editable columns are editable if (!isColumnEditable(col)) { return true; } // Maximized zoomed cells are editable Object obj = getModel().getValueAt(row, col); if (obj instanceof ZoomedCell) { ZoomedCell cell = (ZoomedCell) obj; return cell.isMaximized(); } return true; } @Override public void setValueAt(Object value, int row, int column) { if (!isCellError(row, column) && isColumnEditable(column) && isWritable(row) && Utils.isEditableType(getClassName(row))) { if (JConsole.isDebug()) { System.err.println("validating [row="+row+", column="+column+ "]: "+getValueName(row)+"="+value); } super.setValueAt(value, row, column); } } //Table methods public boolean isTableEditable() { return true; } public void setTableValue(Object value, int row) { } public boolean isColumnEditable(int column) { if (column < getColumnCount()) { return getColumnName(column).equals(Resources.getText("Value")); } else { return false; } } public String getClassName(int row) { int index = convertRowToIndex(row); if (index != -1) { return attributesInfo[index].getType(); } else { return null; } } public String getValueName(int row) { int index = convertRowToIndex(row); if (index != -1) { return attributesInfo[index].getName(); } else { return null; } } public Object getValue(int row) { final Object val = ((DefaultTableModel) getModel()) .getValueAt(row, VALUE_COLUMN); return val; } //tool tip only for editable column @Override public String getToolTip(int row, int column) { if (isCellError(row, column)) { return (String) unavailableAttributes.get(getValueName(row)); } if (isColumnEditable(column)) { Object value = getValue(row); String tip = null; if (value != null) { tip = value.toString(); if(isAttributeViewable(row, VALUE_COLUMN)) tip = Resources.getText("Double click to expand/collapse")+ ". " + tip; } return tip; } if(column == NAME_COLUMN) { int index = convertRowToIndex(row); if (index != -1) { return attributesInfo[index].getDescription(); } } return null; } public synchronized boolean isWritable(int row) { int index = convertRowToIndex(row); if (index != -1) { return (attributesInfo[index].isWritable()); } else { return false; } } /** * Override JTable method in order to make any call to this method * atomic with TableModel elements. */ @Override public synchronized int getRowCount() { return super.getRowCount(); } public synchronized boolean isReadable(int row) { int index = convertRowToIndex(row); if (index != -1) { return (attributesInfo[index].isReadable()); } else { return false; } } public synchronized boolean isCellError(int row, int col) { return (isColumnEditable(col) && (unavailableAttributes.containsKey(getValueName(row)))); } public synchronized boolean isAttributeViewable(int row, int col) { boolean isViewable = false; if(col == VALUE_COLUMN) { Object obj = getModel().getValueAt(row, col); if(obj instanceof ZoomedCell) isViewable = true; } return isViewable; } // Call this in EDT public void loadAttributes(final XMBean mbean, final MBeanInfo mbeanInfo) { final SwingWorker<Runnable,Void> load = new SwingWorker<Runnable,Void>() { @Override protected Runnable doInBackground() throws Exception { return doLoadAttributes(mbean,mbeanInfo); } @Override protected void done() { try { final Runnable updateUI = get(); if (updateUI != null) updateUI.run(); } catch (RuntimeException x) { throw x; } catch (ExecutionException x) { if(JConsole.isDebug()) { System.err.println( "Exception raised while loading attributes: " +x.getCause()); x.printStackTrace(); } } catch (InterruptedException x) { if(JConsole.isDebug()) { System.err.println( "Interrupted while loading attributes: "+x); x.printStackTrace(); } } } }; mbeansTab.workerAdd(load); } // Don't call this in EDT, but execute returned Runnable inside // EDT - typically in the done() method of a SwingWorker // This method can return null. private Runnable doLoadAttributes(final XMBean mbean, MBeanInfo infoOrNull) throws JMException, IOException { // To avoid deadlock with events coming from the JMX side, // we retrieve all JMX stuff in a non synchronized block. if(mbean == null) return null; final MBeanInfo curMBeanInfo = (infoOrNull==null)?mbean.getMBeanInfo():infoOrNull; final MBeanAttributeInfo[] attrsInfo = curMBeanInfo.getAttributes(); final HashMap<String, Object> attrs = new HashMap<String, Object>(attrsInfo.length); final HashMap<String, Object> unavailableAttrs = new HashMap<String, Object>(attrsInfo.length); final HashMap<String, Object> viewableAttrs = new HashMap<String, Object>(attrsInfo.length); AttributeList list = null; try { list = mbean.getAttributes(attrsInfo); }catch(Exception e) { if (JConsole.isDebug()) { System.err.println("Error calling getAttributes() on MBean \"" + mbean.getObjectName() + "\". JConsole will " + "try to get them individually calling " + "getAttribute() instead. Exception:"); e.printStackTrace(System.err); } list = new AttributeList(); //Can't load all attributes, do it one after each other. for(int i = 0; i < attrsInfo.length; i++) { String name = null; try { name = attrsInfo[i].getName(); Object value = mbean.getMBeanServerConnection(). getAttribute(mbean.getObjectName(), name); list.add(new Attribute(name, value)); }catch(Exception ex) { if(attrsInfo[i].isReadable()) { unavailableAttrs.put(name, Utils.getActualException(ex).toString()); } } } } try { int att_length = list.size(); for (int i=0;i<att_length;i++) { Attribute attribute = (Attribute) list.get(i); if(isViewable(attribute)) { viewableAttrs.put(attribute.getName(), attribute.getValue()); } else attrs.put(attribute.getName(),attribute.getValue()); } // if not all attributes are accessible, // check them one after the other. if (att_length < attrsInfo.length) { for (int i=0;i<attrsInfo.length;i++) { MBeanAttributeInfo attributeInfo = attrsInfo[i]; if (!attrs.containsKey(attributeInfo.getName()) && !viewableAttrs.containsKey(attributeInfo. getName()) && !unavailableAttrs.containsKey(attributeInfo. getName())) { if (attributeInfo.isReadable()) { // getAttributes didn't help resolving the // exception. // We must call it again to understand what // went wrong. try { Object v = mbean.getMBeanServerConnection().getAttribute( mbean.getObjectName(), attributeInfo.getName()); //What happens if now it is ok? // Be pragmatic, add it to readable... attrs.put(attributeInfo.getName(), v); }catch(Exception e) { //Put the exception that will be displayed // in tooltip