1077 lines · 38.5 KB · Java
RawDownload
/* * 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

Lines 1–500 of 1077.