Package org.gridkit.jvmtool.heapdump

Source Code of org.gridkit.jvmtool.heapdump.HeapWalker$InstanceConverter

/**
* Copyright 2014 Alexey Ragozin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gridkit.jvmtool.heapdump;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import org.gridkit.jvmtool.heapdump.PathStep.Move;
import org.netbeans.lib.profiler.heap.Field;
import org.netbeans.lib.profiler.heap.FieldValue;
import org.netbeans.lib.profiler.heap.Instance;
import org.netbeans.lib.profiler.heap.JavaClass;
import org.netbeans.lib.profiler.heap.ObjectFieldValue;
import org.netbeans.lib.profiler.heap.PrimitiveArrayInstance;

public class HeapWalker {

    private static final Set<String> BOX_TYPES = new HashSet<String>();

    static {
        BOX_TYPES.add(Boolean.class.getName());
        BOX_TYPES.add(Byte.class.getName());
        BOX_TYPES.add(Short.class.getName());
        BOX_TYPES.add(Character.class.getName());
        BOX_TYPES.add(Integer.class.getName());
        BOX_TYPES.add(Long.class.getName());
        BOX_TYPES.add(Float.class.getName());
        BOX_TYPES.add(Double.class.getName());
    }

    private static final Map<String, InstanceConverter> CONVERTERS = new HashMap<String, InstanceConverter>();

    static {
        CONVERTERS.put(String.class.getName(), new InstanceConverter() {
            @Override
            public Object convert(Instance instance) {
                return stringValue(instance);
            }
        });
        InstanceConverter primitiveConverter = new InstanceConverter() {
            @Override
            public Object convert(Instance instance) {
                return primitiveValue(instance);
            }
        };
        InstanceConverter primitiveArrayConverter = new InstanceConverter() {
            @Override
            public Object convert(Instance instance) {
                return primitiveArrayValue(instance);
            }
        };
        for(String ptype: BOX_TYPES) {
            CONVERTERS.put(ptype, primitiveConverter);
        }
        CONVERTERS.put("boolean[]", primitiveArrayConverter);
        CONVERTERS.put("byte[]", primitiveArrayConverter);
        CONVERTERS.put("char[]", primitiveArrayConverter);
        CONVERTERS.put("short[]", primitiveArrayConverter);
        CONVERTERS.put("int[]", primitiveArrayConverter);
        CONVERTERS.put("long[]", primitiveArrayConverter);
        CONVERTERS.put("float[]", primitiveArrayConverter);
        CONVERTERS.put("double[]", primitiveArrayConverter);
    }

    /**
     * Converts instances of few well know Java classes from
     * dump to normal java objects.
     * <br/>
     * Following are supported classes
     * <li>{@link String}</li>
     * <li>{@link Boolean}</li>
     * <li>{@link Byte}</li>
     * <li>{@link Short}</li>
     * <li>{@link Character}</li>
     * <li>{@link Integer}</li>
     * <li>{@link Long}</li>
     * <li>{@link Float}</li>
     * <li>{@link Double}</li>
     * <li>primitive arrays</li>
     * <li>object arrays</li>
     */
     /* TBD
     * <li>{@link Arrays#asList(Object...)}</li>
     * <li>{@link ArrayList} (subclasses would be reduced to {@link ArrayList})</li>
     * <li>{@link HashMap} (subclasses including {@link LinkedHashMap} would be reduced to {@link ArrayList})</li>
     * <li>{@link HashSet} (subclasses including {@link LinkedHashSet} would be reduced to {@link ArrayList})</li>
     */
    @SuppressWarnings("unchecked")
    public static <T> T valueOf(Instance obj) {
        if (obj == null) {
            return null;
        }
        JavaClass t = obj.getJavaClass();
        InstanceConverter c = CONVERTERS.get(obj.getJavaClass().getName());
        while(c == null && t.getSuperClass() != null) {
            t = t.getSuperClass();
            c = CONVERTERS.get(obj.getJavaClass().getName());
        }
        if (c == null) {
            // return instance as is
            return (T) obj;
        }
        else {
        return (T)c.convert(obj);
    }
    }

    /**
     * Converts value referenced for path from dump to normal java objects.
     * Few well known Java classes as long as primitive types are supported.
     * <br/>
     * Following are supported classes
     * <li>{@link String}</li>
     * <li>{@link Boolean}</li>
     * <li>{@link Byte}</li>
     * <li>{@link Short}</li>
     * <li>{@link Character}</li>
     * <li>{@link Integer}</li>
     * <li>{@link Long}</li>
     * <li>{@link Float}</li>
     * <li>{@link Double}</li>
     * <li>primitive arrays</li>
     * <li>object arrays</li>
     */
     /* TBD
     * <li>{@link Arrays#asList(Object...)}</li>
     * <li>{@link ArrayList} (subclasses would be reduced to {@link ArrayList})</li>
     * <li>{@link HashMap} (subclasses including {@link LinkedHashMap} would be reduced to {@link ArrayList})</li>
     * <li>{@link HashSet} (subclasses including {@link LinkedHashSet} would be reduced to {@link ArrayList})</li>
     */
    @SuppressWarnings("unchecked")
    public static <T> T valueOf(Instance obj, String pathSpec) {
        PathStep[] steps = HeapPath.parsePath(pathSpec, true);
        if (steps.length > 0 && steps[steps.length - 1] instanceof FieldStep) {
            PathStep[] shortPath = Arrays.copyOf(steps, steps.length - 1);
            FieldStep lastStep = (FieldStep) steps[steps.length - 1];
            String fieldName = lastStep.getFieldName();
            for(Instance i: HeapPath.collect(obj, shortPath)) {
                for(FieldValue fv: i.getFieldValues()) {
                    if ((fieldName == null && fv.getField().isStatic())
                            || (fieldName.equals(fv.getField().getName()))) {
                        if (fv instanceof ObjectFieldValue) {
                            return valueOf(((ObjectFieldValue) fv).getInstance());
                        }
                        else {
                            // have to use this as private package API is used behind scene
                            return (T) i.getValueOfField(fv.getField().getName());
                        }
                    }
                }
            }
            return null;
        }
        else {
            for(Instance i: HeapPath.collect(obj, steps)) {
                return valueOf(i);
            }
            return null;
        }
    }

    public static String stringValue(Instance obj) {
        if (obj == null) {
            return null;
        }
        if (!"java.lang.String".equals(obj.getJavaClass().getName())) {
            throw new IllegalArgumentException("Is not a string: " + obj.getInstanceId() + " (" + obj.getJavaClass().getName() + ")");
        }
        char[] text = null;
        int offset = 0;
        int len = -1;
        for(FieldValue f: obj.getFieldValues()) {
            Field ff = f.getField();
            if ("value".equals(ff.getName())) {
                PrimitiveArrayInstance chars = (PrimitiveArrayInstance) ((ObjectFieldValue)f).getInstance();
                text = new char[chars.getLength()];
                for(int i = 0; i != text.length; ++i) {
                    text[i] = ((String)chars.getValues().get(i)).charAt(0);
                }
            }
            // fields below were removed in Java 7
            else if ("offset".equals(ff.getName())) {
                offset = Integer.valueOf(f.getValue());
            }
            else if ("count".equals(ff.getName())) {
                len = Integer.valueOf(f.getValue());
            }
        }

        if (len < 0) {
            len = text.length;
        }

        return new String(text, offset, len);
    }

    @SuppressWarnings("unchecked")
    public static <T> T primitiveValue(Instance obj) {
        if (obj == null) {
            return null;
        }
        String className = obj.getJavaClass().getName();
        if (BOX_TYPES.contains(className)) {
            return (T)obj.getValueOfField("value");
        }
        else {
            throw new IllegalArgumentException("Is not a primitive wrapper: " + obj.getInstanceId() + " (" + obj.getJavaClass().getName() + ")");
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T primitiveArrayValue(Instance obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof PrimitiveArrayInstance) {
            PrimitiveArrayInstance pa = (PrimitiveArrayInstance) obj;
            String type = pa.getJavaClass().getName();
            Object array;
            int len = pa.getLength();
            if ("boolean[]".equals(type)) {
                array = new boolean[len];
            }
            else if ("byte[]".equals(type)) {
                array = new byte[len];
            }
            else if ("char[]".equals(type)) {
                array = new char[len];
            }
            else if ("short[]".equals(type)) {
                array = new short[len];
            }
            else if ("int[]".equals(type)) {
                array = new int[len];
            }
            else if ("long[]".equals(type)) {
                array = new long[len];
            }
            else if ("float[]".equals(type)) {
                array = new float[len];
            }
            else if ("double[]".equals(type)) {
                array = new double[len];
            }
            else {
                throw new IllegalArgumentException("Is not a primitive array: " + obj.getInstanceId() + " (" + obj.getJavaClass().getName() + ")");
            }

            List<Object> values = pa.getValues();
            for(int i = 0; i != values.size(); ++i) {
                Object val = values.get(i);
                if (val instanceof String) {
                    val = Character.valueOf(((String)val).charAt(0));
                }
                Array.set(array, i, val);
            }

            return (T)array;
        }
        else {
            throw new IllegalArgumentException("Is not a primitive array: " + obj.getInstanceId() + " (" + obj.getJavaClass().getName() + ")");
        }
    }

    public static Iterable<Instance> walk(Instance root, String path) {
        return HeapPath.collect(root, HeapPath.parsePath(path, true));
    }

    public static Instance walkFirst(Instance root, String path) {
        Iterator<Instance> it = walk(root, path).iterator();
        if (it.hasNext()) {
            return it.next();
        }
        else {
            return null;
        }
    }
   
    public static String explainPath(Instance root, String path) {
        PathStep[] chain = HeapPath.parsePath(path, true);
        StringBuilder sb = new StringBuilder();
        Instance o = root;
        for(int i = 0; i != chain.length; ++i) {
            if (chain[i] instanceof TypeFilterStep) {
                continue;
            }
            sb.append("(" + shortName(o.getJavaClass().getName()) + ")");
            try {
                Move m = chain[i].track(o).next();
                sb.append(m.pathSpec);
                o = m.instance;
            }
            catch(NoSuchElementException e) {
                sb.append("{failed: " + chain[i] + "}");
            }
        }
        return sb.toString();
    }
   
    private static final String shortName(String name) {
        int c = name.lastIndexOf('.');
        if (c >= 0) {
            return "**." + name.substring(c + 1);
        }
        else {
            return name;
        }
    }   

    private interface InstanceConverter {

        public Object convert(Instance instance);
    }
}
TOP

Related Classes of org.gridkit.jvmtool.heapdump.HeapWalker$InstanceConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.