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

org.gridkit.jvmtool.heapdump.HeapPath Maven / Gradle / Ivy

There is a newer version: 0.16
Show newest version
/**
 * 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.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.gridkit.jvmtool.heapdump.PathStep.Move;
import org.netbeans.lib.profiler.heap.Instance;

class HeapPath {

    static PathStep[] parsePath(String path, boolean strictPath) {

        List result = new ArrayList();

        if (path.endsWith(".")) {
            throw new IllegalArgumentException("Invalid path spec: " + path);
        }

        boolean fieldRequired = false;
        boolean dotAllowed = false;
        int n = 0;
        while(n < path.length()) {
            String token = token(n, path);
            n += token.length();
            if (token.length() == 0) {
                throw new RuntimeException("Internal error parsing: " + path);
            }
            if (".".equals(token)) {
                if (dotAllowed) {
                    fieldRequired = true;
                    dotAllowed = false;
                }
                else {
                    throw new IllegalArgumentException("Invalid path spec: " + path);
                }
            }
            else if (token.charAt(0) == '(') {
                if (fieldRequired) {
                    throw new IllegalArgumentException("Invalid path spec: " + path);
                }
                String pattern = token.substring(1, token.length() - 1);
                try {
                    TypeFilterStep step = new TypeFilterStep(pattern);
                    result.add(step);
                }
                catch(RuntimeException e) {
                    throw new IllegalArgumentException("Invalid path spec: " + path, e);
                }

                dotAllowed = true;
                fieldRequired = false;
                continue;
            }
            else if (token.charAt(0) == '[') {
                if (fieldRequired) {
                    throw new IllegalArgumentException("Invalid path spec: " + path);
                }
                String index = token.substring(1, token.length() - 1).trim();
                if (index.equals("*")) {
                    result.add(new ArrayIndexStep(-1));
                }
                else {
                    try {
                        int ai = Integer.valueOf(index);
                        result.add(new ArrayIndexStep(ai));
                    }
                    catch(NumberFormatException e) {
                        // try to parse predicate
                        int c = index.lastIndexOf('=');
                        if (c > 0) {
                        	boolean inv = false;
                        	String subpath = index.substring(0, c);
                            if (subpath.endsWith("!")) {
                            	inv = true;
                            	subpath = subpath.substring(0, subpath.length() - 1);
                            }
                            String matcher = index.substring(c + 1, index.length());
                            PathStep[] steps = parsePath(subpath, true);
                            result.add(new PredicateStep(steps, matcher, inv));
                        }
                        else {
                            throw new IllegalArgumentException("Invalid path spec: " + path, e);
                        }
                    }
                }

                dotAllowed = true;
                fieldRequired = false;

                continue;
            }
            else {
                if (token.charAt(0) == '?') {
                    if ("?entrySet".equals(token)) {
                        result.add(new MapEntrySetStep());
                    }
                    else {
                        throw new IllegalArgumentException("Invalid path spec: " + path);
                    }
                }
                else if (dotAllowed && token.equals("*")) {
                    if (lastIsDoubleAsterisk(result)) {
                        throw new IllegalArgumentException("Invalid path spec: " + path);
                    }
                    else if (lastIsAsterisk(result)) {
                        if (strictPath) {
                            throw new IllegalArgumentException("Invalid path spec: " + path);
                        }
                        result.set(result.size() - 1, new AnyPathStep());
                    }
                    else {
                        result.add(new FieldStep(null));
                    }
                }
                else {
                    result.add(new FieldStep(token.equals("*") ? null : token));
                }

                dotAllowed = true;
                fieldRequired = false;
                continue;
            }
        }

        return result.toArray(new PathStep[result.size()]);
    }

    private static boolean lastIsAsterisk(List result) {
        if (result.isEmpty()) {
            return false;
        }
        else {
            PathStep step = result.get(result.size() - 1);
            if (step instanceof FieldStep && ((FieldStep)step).getFieldName() == null) {
                return true;
            }
        }
        return false;
    }

    private static boolean lastIsDoubleAsterisk(List result) {
        if (result.isEmpty()) {
            return false;
        }
        else {
            PathStep step = result.get(result.size() - 1);
            if (step instanceof AnyPathStep) {
                return true;
            }
        }
        return false;
    }

    private static String token(int n, String path) {
        StringBuilder sb = new StringBuilder();
        while(n < path.length()) {
            char ch = path.charAt(n);
            if (ch == '.') {
                if (sb.length() == 0) {
                    return ".";
                }
                else {
                    return sb.toString();
                }
            }
            if (ch == '*') {
                if (sb.length() == 0) {
                    return "*";
                }
                else {
                    throw new IllegalArgumentException("Invalid path spec: " + path);
                }
            }
            if (ch == '(') {
                if (sb.length() == 0) {
                    return group(n, path);
                }
                else {
                    return sb.toString();
                }
            }
            if (ch == '[') {
                if (sb.length() == 0) {
                    return group(n, path);
                }
                else {
                    return sb.toString();
                }
            }
            if (ch == '?') {
                if (sb.length() == 0) {
                    sb.append(ch);
                }
                else {
                    return sb.toString();
                }
            }
            else if (Character.isJavaIdentifierStart(ch)) {
                sb.append(ch);
            }
            else if (Character.isJavaIdentifierPart(ch)) {
                if (sb.length() == 0) {
                    throw new IllegalArgumentException("Invalid path spec: " + path);
                }
                sb.append(ch);
            }
            else {
                throw new IllegalArgumentException("Invalid path spec: " + path);
            }
            ++n;
        }
        return sb.toString();
    }

    private static String group(int n, String path) {
        char ch = path.charAt(n);
        if (ch == '[') {
            ch = ']';
        }
        else if (ch == '(') {
            ch = ')';
        }
        else {
            throw new IllegalArgumentException("Invalid path spec: " + path);
        }

        int m = n;
        ++n;
        while(n < path.length()) {
            if (path.charAt(n) == ch) {
                return path.substring(m, n + 1);
            }
            ++n;
        }
        throw new IllegalArgumentException("Invalid path spec: " + path);
    }

    static Set collect(Instance instance, PathStep[] steps) {

        Set active = new HashSet();
        Set next = new HashSet();
        active.add(instance);

        for(PathStep step: steps) {
            for(Instance i: active) {
                Iterator it = step.walk(i);
                while(it.hasNext()) {
                    Instance sub = it.next();
                    if (sub != null) {
                        next.add(sub);
                    }
                }
            }
            // swap buffers
            active.clear();
            Set s = active;
            active = next;
            next = s;
            if (active.isEmpty()) {
                return active;
            }
        }

        return active;
    }

    static Set track(Instance instance, PathStep[] steps) {

        Set active = new HashSet();
        Set next = new HashSet();
        active.add(new Move("", instance));

        for(PathStep step: steps) {
            for(Move i: active) {
                Iterator it = step.track(i.instance);
                while(it.hasNext()) {
                    Move sub = it.next();
                    if (sub.instance != null) {
                        next.add(new Move(i.pathSpec + sub.pathSpec, sub.instance));
                    }
                }
            }
            // swap buffers
            active.clear();
            Set s = active;
            active = next;
            next = s;
            if (active.isEmpty()) {
                return active;
            }
        }

        return active;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy