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

org.gridkit.jvmtool.stacktrace.analytics.AbstractClassificatorParser Maven / Gradle / Ivy

There is a newer version: 0.23
Show newest version
package org.gridkit.jvmtool.stacktrace.analytics;

import static org.gridkit.jvmtool.stacktrace.analytics.ClassificatorAST.conjunction;
import static org.gridkit.jvmtool.stacktrace.analytics.ClassificatorAST.disjunction;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.gridkit.jvmtool.stacktrace.analytics.ClassificatorAST.AnyOfFrameMatcher;
import org.gridkit.jvmtool.stacktrace.analytics.ClassificatorAST.Filter;
import org.gridkit.jvmtool.stacktrace.analytics.ClassificatorAST.FrameMatcher;
import org.gridkit.jvmtool.stacktrace.analytics.ClassificatorAST.LastFollowedFilter;
import org.gridkit.jvmtool.stacktrace.analytics.ClassificatorAST.LastNotFollowedFilter;
import org.gridkit.jvmtool.stacktrace.util.IndentParser;

public abstract class AbstractClassificatorParser extends IndentParser {

    private static boolean diag = false;
    
    private static final String CAT_NAME = "\\[(.*)\\]";
    private static final String SUBCLASS_NAME = "\\+(.*)";
    private static final String FRAME_PATTERN = "([^!]+)";
    
    private Matcher tokenMatcher;
    private ARoot result;
    
    protected ARoot getRoot() {
        return result;
    }
    
    @Override
    protected void initialState() {
        RootSS root = new RootSS();
        this.result = root.root;
        pushState(root);
    }

    private void pushState(SyntaticState ss) {
        if (!(ss instanceof RootSS)) {
            pushParseState();
        }
        ss.initState();
        pushValue(ss);
        if (diag) {
            System.err.println(">> " + ss.getClass().getSimpleName());
        }
    }

    protected void replaceState(SyntaticState ss) {
        Object prev = popValue();
        unexpectAll();
        if (diag) {
            System.err.println("<< " + prev.getClass().getSimpleName() + " >> " + ss.getClass().getSimpleName());
        }
        ss.initState();
        pushValue(ss);        
    }

    @Override
    protected void onToken(String tokenType, String token) throws ParseException {
        dispatchTokenByValue(tokenType, token);
    }

    private void matchToken(String tokenType, String token, String pattern) {
        Pattern ptr = Pattern.compile(pattern);
        tokenMatcher = ptr.matcher(token);
        if (!tokenMatcher.matches()) {
            throw new IllegalArgumentException("Token doesn't match pattern: " + token);
        }
    }

    private void dispatchTokenByValue(String tokenType, String token) throws ParseException {
        try {
            SyntaticState state = (SyntaticState) value();
            String name = "onToken" + tokenType;
            Method m = state.getClass().getMethod(name);
            String pattern = m.getAnnotation(Token.class).value();
            matchToken(tokenType, token, pattern);
            m.setAccessible(true);
            m.invoke(state);
        } catch (InvocationTargetException e) {
            if (e.getCause() instanceof ParseException) {
                throw ((ParseException)e.getCause());
            }
            else {
                throw new RuntimeException(e.getTargetException());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void onPopup() throws ParseException {
        try {
            SyntaticState state = (SyntaticState) value();
            popValue();
            popParseState();
            if (diag) {
                System.err.println("<< " + state.getClass().getSimpleName());
            }
            String name = "onPopup";
            Method m = state.getClass().getMethod(name);
            m.setAccessible(true);
            m.invoke(state);
        } catch (InvocationTargetException e) {
            if (e.getCause() instanceof ParseException) {
                throw ((ParseException)e.getCause());
            }
            else {
                throw new RuntimeException(e.getTargetException());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    protected abstract ARoot newRootNode();
    
    protected abstract AClassification newClassificationNode(String name);
    
    protected abstract void addToRoot(ARoot root, AClassification classification);

    protected abstract void addSubclass(AClassification classification, String name, Filter filter);
    
    abstract class SyntaticState {
        
        public void initState() {
            for(Method m: getClass().getMethods()) {
                if (m.getName().startsWith("onToken")) {
                    String tn = m.getName().substring("onToken".length());
                    String pattern = m.getAnnotation(Token.class).value();
                    expectToken(tn, pattern);
                }
                else if (m.getName().startsWith("onPopup")) {
                    expectPopup();
                }
            }
        }        

        public void initClassState(Class c) {
            for(Method m: c.getDeclaredMethods()) {
                if (m.getName().startsWith("onToken")) {
                    String tn = m.getName().substring("onToken".length());
                    String pattern = m.getAnnotation(Token.class).value();
                    expectToken(tn, pattern);
                }
                else if (m.getName().startsWith("onPopup")) {
                    expectPopup();
                }
            }
        }       
        
        public void popupState() throws ParseException {
            AbstractClassificatorParser.this.onPopup();
        }
    }
    
    class RootSS extends SyntaticState {

        ARoot root = newRootNode();
     
        @Token(CAT_NAME)
        public void onTokenCategory() {
            String name = tokenMatcher.group(1);
            ClassificationSS cat = new ClassificationSS(name);
            cat.root = this;
            replaceState(cat);
            pushState(new RootFilterSS(cat));
        }
        
        public void onPopup() {
            result = root;
        }
    }

    class ClassificationSS extends SyntaticState {
        
        RootSS root;
        AClassification classification;
        List filters = new ArrayList();
        int line;
        int pos;
        
        public ClassificationSS(String name) {
            line = getLineNumber();
            pos = getIndent();
            classification = newClassificationNode(name);
        }

        @Token(CAT_NAME)
        public void onTokenCategory() throws ParseException {
            onPopup();
            root.onTokenCategory();
        }

        @Token(SUBCLASS_NAME)
        public void onTokenSubclass() {
            SubclassSS ss = new SubclassSS(tokenMatcher.group(1), this);
            pushState(ss);
        }
        
        public void onPopup() throws ParseException {
            try {
                addToRoot(root.root, classification);
            }
            catch(IllegalArgumentException e) {
                throw new ParseException(e.getMessage(), line, pos);
            }
            Filter rootFilter = conjunction(filters);
            if (rootFilter != null) {
                classification.setRootFilter(rootFilter);
            }
        }
    }

    class RootFilterSS extends FilterSS {
        
        ClassificationSS parent;

        public RootFilterSS(ClassificationSS parent) {
            super();
            this.parent = parent;
        }

        @Override
        protected void push(Filter filter) throws ParseException {
            parent.filters.add(filter);
        }
        
        public void onPopup() {
        }
    }
    
    abstract class FilterSS extends SyntaticState {
        
        @Token(FRAME_PATTERN)
        public void onTokenPattern() throws ParseException {
            String p = tokenMatcher.group(1);
            ClassificatorAST.PatternFilter f = new ClassificatorAST.PatternFilter();
            f.patterns.add(p);
            pushState(new PopupOnlySS());
            push(f);
        }
        
        @Token("!(REQUIRE\\s+)?ALL")
        public void onTokenAnd() {
            FilterSS ss = new AndCombinatorSS(this);
            pushState(ss);
        }

        @Token("!(REQUIRE\\s+)?ANY")
        public void onTokenAny() {
            FilterSS ss = new OrCombinatorSS(this);
            pushState(ss);
        }

        @Token("!LAST\\s+FRAME")
        public void onTokenLastFrame() {
            LastFrameSS ss = new LastFrameSS(this);
            pushState(ss);
        }
        
        protected abstract void push(ClassificatorAST.Filter filter) throws ParseException;
    }
    
    class AndCombinatorSS extends FilterSS {

        FilterSS parent;
        List filters = new ArrayList();
        
        public AndCombinatorSS(FilterSS parent) {
            this.parent = parent;
        }

        @Override
        protected void push(Filter filter) throws ParseException {
            filters.add(filter);
        }
        
        public void onPopup() throws ParseException {
            if (filters.isEmpty()) {
                error("Empty !ALL group");
                return;
            }
            parent.push(disjunction(filters));            
        }
    }

    class OrCombinatorSS extends FilterSS {

        FilterSS parent;
        List filters = new ArrayList();
        
        public OrCombinatorSS(FilterSS parent) {
            this.parent = parent;
        }

        @Override
        protected void push(Filter filter) throws ParseException {
            filters.add(filter);
        }
        
        public void onPopup() throws ParseException {
            if (filters.isEmpty()) {
                error("Empty !ANY group");
                return;
            }
            parent.push(conjunction(filters));            
        }
    }
    
    class PopupOnlySS extends SyntaticState {

        public void onPopup() throws ParseException {
        }
    }
    
    class SubclassSS extends FilterSS {

        ClassificationSS parent;
        String name;        
        List filters = new ArrayList();
        int line;
        int pos;
        
        public SubclassSS(String name, ClassificationSS parent) {
            this.name = name;
            this.parent = parent;
            line = getLineNumber();
            pos = getIndent();
        }

        @Token(CAT_NAME)
        public void onTokenCategory() throws ParseException {
            popupState();
            parent.onTokenCategory();
        }

        @Token(SUBCLASS_NAME)
        public void onTokenSubclass() throws ParseException {
            popupState();
            parent.onTokenSubclass();
        }
        
        @Override
        protected void push(Filter filter) {
            this.filters.add(filter);
        }
        
        public void onPopup() throws ParseException {
            AClassification cls = parent.classification;
            Filter filter = ClassificatorAST.conjunction(filters);
            try {
                addSubclass(cls, name, filter);
            }
            catch(IllegalArgumentException e) {
                throw new ParseException(e.getMessage(), line, pos);
            }
        }
    }

    interface PositionedPredicate {
        
        public void finish(Filter filter) throws ParseException;
        
    }
    
    class LastFrameSS extends SyntaticState implements PositionedPredicate {
        
        FilterSS parent;
        List frames = new ArrayList();
        boolean followed;
        boolean done;
        
        public LastFrameSS(FilterSS parent) {
            this.parent = parent;
        }
                
        @Override
        public void initState() {
            super.initState();
        }

        @Token(FRAME_PATTERN)
        public void onTokenPattern() throws ParseException {
            String p = tokenMatcher.group(1);
            ClassificatorAST.PatternFilter f = new ClassificatorAST.PatternFilter();
            f.patterns.add(p);
            pushState(new PopupOnlySS());
            frames.add(f);
        }

        @Token("!FOLLOWED")
        public void onTokenFollowed() throws ParseException {
            followed = true;
            if (frames.isEmpty()) {
                error("No frames to match");
            }
            PositionedFilterSS ss = new PositionedFilterSS(this);
            replaceState(ss);
        }

        @Token("!NOT\\s+FOLLOWED")
        public void onTokenNotFollowed() throws ParseException {
            followed = false;
            if (frames.isEmpty()) {
                error("No frames to match");
            }
            PositionedFilterSS ss = new PositionedFilterSS(this);
            replaceState(ss);
        }
        
        @Override
        public void finish(Filter filter) throws ParseException {
            done = true;
            if (followed) {
                LastFollowedFilter lff = new LastFollowedFilter();
                if (frames.size() == 1) {
                    lff.snippet = frames.get(0);
                }
                else {
                    lff.snippet = new AnyOfFrameMatcher(frames);
                }
                lff.followFilter = filter;
                parent.push(lff);
            }            
            else {
                LastNotFollowedFilter lff = new LastNotFollowedFilter();
                if (frames.size() == 1) {
                    lff.snippet = frames.get(0);
                }
                else {
                    lff.snippet = new AnyOfFrameMatcher(frames);
                }
                lff.followFilter = filter;                
                parent.push(lff);
            }            
        }
    }
    
    class PositionedFilterSS extends FilterSS {

        PositionedPredicate pred;
        List filters = new ArrayList();
        
        
        public PositionedFilterSS(PositionedPredicate pred) {
            this.pred = pred;
        }

        @Override
        protected void push(Filter filter) throws ParseException {
            filters.add(filter);
        }
        
        public void onPopup() throws ParseException {
            if (filters.isEmpty()) {
                error("Empty condition");
                return;
            }
            pred.finish(disjunction(filters));
        }
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @interface Token {
        String value();
    }
    
    protected interface ARoot {
        
    }
    
    protected interface AClassification {

        void setRootFilter(Filter conjunction);
        
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy