All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graalvm.visualvm.modules.mbeans.Utils Maven / Gradle / Ivy

There is a newer version: 2.1.9
Show newest version
/*
 * Copyright (c) 2007, 2018, 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 org.graalvm.visualvm.modules.mbeans;

import java.awt.event.*;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ExecutionException;
import javax.management.*;
import javax.management.openmbean.*;
import javax.swing.*;
import javax.swing.text.*;

class Utils {
    
    private Utils() {
    }
    
    private static Set tableNavigationKeys =
            new HashSet(Arrays.asList(new Integer[] {
        KeyEvent.VK_TAB, KeyEvent.VK_ENTER,
        KeyEvent.VK_HOME, KeyEvent.VK_END,
        KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT,
        KeyEvent.VK_UP, KeyEvent.VK_DOWN,
        KeyEvent.VK_PAGE_UP, KeyEvent.VK_PAGE_DOWN}));
    
    private static final Set> primitiveWrappers =
            new HashSet>(Arrays.asList(new Class[] {
        Byte.class, Short.class, Integer.class, Long.class,
        Float.class, Double.class, Character.class, Boolean.class}));
    
    private static final Set> primitives = new HashSet>();
    
    private static final Map> primitiveMap =
            new HashMap>();
    
    private static final Map> primitiveToWrapper =
            new HashMap>();
    
    private static final Set editableTypes = new HashSet();
    
    private static final Set> extraEditableClasses =
            new HashSet>(Arrays.asList(new Class[] {
        BigDecimal.class, BigInteger.class, Number.class,
        String.class, String[].class, ObjectName.class}));
    
    private static final Set numericalTypes = new HashSet();
    
    private static final Set extraNumericalTypes =
            new HashSet(Arrays.asList(new String[] {
        BigDecimal.class.getName(), BigInteger.class.getName(),
        Number.class.getName()}));
    
    private static final Set booleanTypes =
            new HashSet(Arrays.asList(new String[] {
        Boolean.TYPE.getName(), Boolean.class.getName()}));
    
    static {
        // compute primitives/primitiveMap/primitiveToWrapper
        for (Class c : primitiveWrappers) {
            try {
                Field f = c.getField("TYPE"); // NOI18N
                Class p = (Class) f.get(null);
                primitives.add(p);
                primitiveMap.put(p.getName(), p);
                primitiveToWrapper.put(p.getName(), c);
            } catch (Exception e) {
                throw new AssertionError(e);
            }
        }
        // compute editableTypes
        for (Class c : primitives) {
            editableTypes.add(c.getName());
        }
        for (Class c : primitiveWrappers) {
            editableTypes.add(c.getName());
        }
        for (Class c : extraEditableClasses) {
            editableTypes.add(c.getName());
        }
        // compute numericalTypes
        for (Class c : primitives) {
            String name = c.getName();
            if (!name.equals(Boolean.TYPE.getName())) {
                numericalTypes.add(name);
            }
        }
        for (Class c : primitiveWrappers) {
            String name = c.getName();
            if (!name.equals(Boolean.class.getName())) {
                numericalTypes.add(name);
            }
        }
    }
    
    /**
     * This method returns the class matching the name className.
     * It's used to cater for the primitive types.
     */
    public static Class getClass(String className)
    throws ClassNotFoundException {
        Class c;
        if ((c = primitiveMap.get(className)) != null)
            return c;
        return Class.forName(className);
    }
    
    /**
     * Check if the given collection is a uniform collection of the given type.
     */
    public static boolean isUniformCollection(Collection c, Class e) {
        if (e == null) {
            throw new IllegalArgumentException("Null reference type"); // NOI18N
        }
        if (c == null) {
            throw new IllegalArgumentException("Null collection"); // NOI18N
        }
        if (c.isEmpty()) {
            return false;
        }
        for (Object o : c) {
            if (o == null || !e.isAssignableFrom(o.getClass())) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Check if the given element denotes a supported array-friendly data
     * structure, i.e. a data structure jconsole can render as an array.
     */
    public static boolean canBeRenderedAsArray(Object elem) {
        if (isSupportedArray(elem)) return true;
        if (elem instanceof Collection) {
            Collection c = (Collection) elem;
            if (c.isEmpty()) {
                // Empty collections of any Java type are not handled as arrays
                //
                return false;
            } else {
                // - Collections of CompositeData/TabularData are not handled
                //   as arrays
                // - Collections of other Java types are handled as arrays
                //
                return !isUniformCollection(c, CompositeData.class) &&
                       !isUniformCollection(c, TabularData.class);
            }
        }
        if (elem instanceof Map) {
            return !(elem instanceof TabularData);
        }
        return false;
    }
    
    /**
     * Check if the given element is an array.
     *
     * Multidimensional arrays are not supported.
     *
     * Non-empty 1-dimensional arrays of CompositeData
     * and TabularData are not handled as arrays but as
     * tabular data.
     */
    public static boolean isSupportedArray(Object elem) {
        if (elem == null || !elem.getClass().isArray()) {
            return false;
        }
        Class ct = elem.getClass().getComponentType();
        if (ct.isArray()) {
            return false;
        }
        if (Array.getLength(elem) > 0 &&
                (CompositeData.class.isAssignableFrom(ct) ||
                TabularData.class.isAssignableFrom(ct))) {
            return false;
        }
        return true;
    }
    
    /**
     * This method provides a readable classname if it's an array,
     * i.e. either the classname of the component type for arrays
     * of java reference types or the name of the primitive type
     * for arrays of java primitive types. Otherwise, it returns null.
     */
    public static String getArrayClassName(String name) {
        String className = null;
        if (name.startsWith("[")) { // NOI18N
            int index = name.lastIndexOf("["); // NOI18N
            className = name.substring(index, name.length());
            if (className.startsWith("[L")) { // NOI18N
                className = className.substring(2, className.length() - 1);
            } else {
                try {
                    Class c = Class.forName(className);
                    className = c.getComponentType().getName();
                } catch (ClassNotFoundException e) {
                    // Should not happen
                    throw new IllegalArgumentException(
                            "Bad class name " + name, e); // NOI18N
                }
            }
        }
        return className;
    }
    
    /**
     * This methods provides a readable classname. If the supplied name
     * parameter denotes an array this method returns either the classname
     * of the component type for arrays of java reference types or the name
     * of the primitive type for arrays of java primitive types followed by
     * n-times "[]" where 'n' denotes the arity of the array. Otherwise, if
     * the supplied name doesn't denote an array it returns the same classname.
     */
    public static String getReadableClassName(String name) {
        String className = getArrayClassName(name);
        if (className == null) return name;
        int index = name.lastIndexOf("["); // NOI18N
        StringBuilder brackets = new StringBuilder(className);
        for (int i = 0; i <= index; i++) {
            brackets.append("[]"); // NOI18N
        }
        return brackets.toString();
    }
    
    /**
     * This method tells whether the type is editable
     * (means can be created with a String or not)
     */
    public static boolean isEditableType(String type) {
        return editableTypes.contains(type);
    }
    
    /**
     * This method inserts a default value for the standard java types,
     * else it inserts the text name of the expected class type.
     * It acts to give a clue as to the input type.
     */
    public static String getDefaultValue(String type) {
        if (numericalTypes.contains(type) ||
                extraNumericalTypes.contains(type)) {
            return "0"; // NOI18N
        }
        if (booleanTypes.contains(type)) {
            return "true"; // NOI18N
        }
        type = getReadableClassName(type);
        int i = type.lastIndexOf('.');
        if (i > 0) {
            return type.substring(i + 1, type.length());
        } else {
            return type;
        }
    }
    
    /**
     * Try to create a Java object using a one-string-param constructor.
     */
    public static Object newStringConstructor(String type, String param)
    throws Exception {
        Constructor c = Utils.getClass(type).getConstructor(String.class);
        try {
            return c.newInstance(param);
        } catch (InvocationTargetException e) {
            Throwable t = e.getTargetException();
            if (t instanceof Exception) {
                throw (Exception) t;
            } else {
                throw e;
            }
        }
    }
    
    /**
     * Try to convert a string value into a numerical value.
     */
    private static Number createNumberFromStringValue(String type, String value)
    throws NumberFormatException {
        final String suffix = value.substring(value.length() - 1);
        if ("L".equalsIgnoreCase(suffix)) { // NOI18N
            return Long.valueOf(value.substring(0, value.length() - 1));
        }
        if ("F".equalsIgnoreCase(suffix)) { // NOI18N
            return Float.valueOf(value.substring(0, value.length() - 1));
        }
        if ("D".equalsIgnoreCase(suffix)) { // NOI18N
            return Double.valueOf(value.substring(0, value.length() - 1));
        }
        try {
            return (Number) newStringConstructor(type, value);
        } catch (Exception ex) {
            // OK: Ignore exception...
        }
        try {
            return Integer.valueOf(value);
        } catch (NumberFormatException e) {
            // OK: Ignore exception...
        }
        try {
            return Long.valueOf(value);
        } catch (NumberFormatException e1) {
            // OK: Ignore exception...
        }
        try {
            return Double.valueOf(value);
        } catch (NumberFormatException e2) {
            // OK: Ignore exception...
        }
        throw new NumberFormatException("Cannot convert string value '" + // NOI18N
                value + "' into a numerical value"); // NOI18N
    }
    
    /**
     * This method attempts to create an object of the given "type"
     * using the "value" parameter.
     * e.g. calling createObjectFromString("java.lang.Integer", "10")
     * will return an Integer object initialized to 10.
     */
    public static Object createObjectFromString(String type, String value)
    throws Exception {
        Object result;
        if (primitiveToWrapper.containsKey(type)) {
            if (type.equals(Character.TYPE.getName())) {
                result = new Character(value.charAt(0));
            } else {
                result = newStringConstructor(
                        ((Class) primitiveToWrapper.get(type)).getName(),
                        value);
            }
        } else if (type.equals(Character.class.getName())) {
            result = new Character(value.charAt(0));
        } else if (Number.class.isAssignableFrom(Utils.getClass(type))) {
            result = createNumberFromStringValue(type, value);
        } else if (String[].class.isAssignableFrom(Utils.getClass(type))) {
            String[] args = value.split(",");       // NOI18N
            for (int i = 0; i < args.length; i++) {
                args[i] = args[i].trim();
            }
            result = args;
        } else if (value == null || value.toString().equals("null")) { // NOI18N
            // hack for null value
            result = null;
        } else {
            // try to create a Java object using
            // the one-string-param constructor
            result = newStringConstructor(type, value);
        }
        return result;
    }
    
    /**
     * This method is responsible for converting the inputs given by the user
     * into a useful object array for passing into a parameter array.
     */
    public static Object[] getParameters(XTextField[] inputs, String[] params)
    throws Exception {
        Object result[] = new Object[inputs.length];
        Object userInput;
        for (int i = 0; i < inputs.length; i++) {
            userInput = inputs[i].getValue();
            // if it's already a complex object, use the value
            // else try to instantiate with string constructor
            if (userInput instanceof XObject) {
                result[i] = ((XObject) userInput).getObject();
            } else {
                result[i] = createObjectFromString(params[i].toString(),
                        (String) userInput);
            }
        }
        return result;
    }
    
    /**
     * If the exception is wrapped, unwrap it.
     */
    public static Throwable getActualException(Throwable e) {
        if (e instanceof ExecutionException)
            e = e.getCause();
        if (e instanceof MBeanException ||
                e instanceof RuntimeMBeanException ||
                e instanceof RuntimeOperationsException ||
                e instanceof ReflectionException) {
            Throwable t = e.getCause();
            if (t != null) return t;
        }
        return e;
    }
    
    @SuppressWarnings("serial")
    public static class ReadOnlyTableCellEditor
            extends DefaultCellEditor {
        public ReadOnlyTableCellEditor(JTextField tf) {
            super(tf);
            tf.addFocusListener(new Utils.EditFocusAdapter(this));
            tf.addKeyListener(new Utils.CopyKeyAdapter());
        }
    }
    
    public static class EditFocusAdapter extends FocusAdapter {
        private CellEditor editor;
        public EditFocusAdapter(CellEditor editor) {
            this.editor = editor;
        }
        @Override
        public void focusLost(FocusEvent e) {
            editor.stopCellEditing();
        }
    };
    
    public static class CopyKeyAdapter extends KeyAdapter {
        private static final String defaultEditorKitCopyActionName =
                DefaultEditorKit.copyAction;
        private static final String transferHandlerCopyActionName =
                (String) TransferHandler.getCopyAction().getValue(Action.NAME);
        @Override
        public void keyPressed(KeyEvent e) {
            // Accept "copy" key strokes
            KeyStroke ks = KeyStroke.getKeyStroke(
                    e.getKeyCode(), e.getModifiers());
            JComponent comp = (JComponent) e.getSource();
            for (int i = 0; i < 3; i++) {
                InputMap im = comp.getInputMap(i);
                Object key = im.get(ks);
                if (defaultEditorKitCopyActionName.equals(key) ||
                        transferHandlerCopyActionName.equals(key)) {
                    return;
                }
            }
            // Accept JTable navigation key strokes
            if (!tableNavigationKeys.contains(e.getKeyCode())) {
                e.consume();
            }
        }
        @Override
        public void keyTyped(KeyEvent e) {
            e.consume();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy