Package dk.brics.jwig.analysis.graph

Source Code of dk.brics.jwig.analysis.graph.StateMachine$MethodStatementContainer

package dk.brics.jwig.analysis.graph;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import soot.SootMethod;
import soot.jimple.InvokeExpr;
import soot.jimple.Stmt;
import dk.brics.jwig.analysis.jaive.Plugging;

/**
* A state machine for a #WebSite: a call graph with makeURLs as edges too.
*/
public class StateMachine implements Cloneable {

    /**
     * Container class.
     */
    public static class MethodStatementContainer {

        private final SootMethod method;
        private final Stmt st;

        public MethodStatementContainer(SootMethod method, Stmt st) {
            this.method = method;
            this.st = st;
        }

        /**
         * @return the method
         */
        public SootMethod getMethod() {
            return method;
        }

        /**
         * @return the st
         */
        public Stmt getStatement() {
            return st;
        }

    }

    public class StateFlattener {
        private final Set<State> allStates = new HashSet<State>();

        public StateFlattener() {
            for (State s : initialsStates) {
                findSubStates(s);
            }
            // add any isolated filterStates
            allStates.addAll(filterStates);
        }

        private void findSubStates(State s) {
            allStates.add(s);
            if (s != null) {
                for (Transition sub : s.getTransitions()) {
                    State target = sub.getTarget();
                    if (target != null && !allStates.contains(target)) {
                        findSubStates(target);
                    }
                }
            }
        }

        public Set<State> getAllStates() {
            return allStates;
        }
    }

    public static int getHash(State o1) {
        if (o1 == null) {
            return "ANY".hashCode();
        }
        return o1.getMethod().getDeclaringClass().hashCode();
    }

    private final Set<WebMethodState> initialsStates = new HashSet<WebMethodState>();
    private final Map<SootMethod, State> methodStateMap = new HashMap<SootMethod, State>();
    private final Map<InvokeExpr, MethodStatementContainer> makeURLLocations = new HashMap<InvokeExpr, MethodStatementContainer>();
    private final Map<InvokeExpr, Plugging> plugLocations = new HashMap<InvokeExpr, Plugging>();
    private final Set<FilterState> filterStates = new HashSet<FilterState>();

    public void addFilterState(FilterState state) {
        filterStates.add(state);
    }

    public void addInitialState(WebMethodState state) {
        initialsStates.add(state);
    }

    public void addMakeURLLocation(InvokeExpr expr, SootMethod method, Stmt st) {
        makeURLLocations.put(expr, new MethodStatementContainer(method, st));
    }

    private void addState(State state) {
        if (!methodStateMap.containsKey(state.getMethod()))
            methodStateMap.put(state.getMethod(), state);
    }

    /**
     * Clones the state machine. All states and their transitions are cloned
     * too. Soot-classes aren't cloned.
     */
    @Override
    public StateMachine clone() {
        final StateMachine clone = new StateMachine();
        cloneInitialStates(clone);
        cloneFilterStates(clone);
        cloneStates(clone);
        cloneTransitions(clone);
        cloneMakeURLLocations(clone);
        // TODO clone submitHandlerPluggings
        return clone;
    }

    /**
     * Clones the {@link FilterState}s of this {@link StateMachine}.
     *
     * @param clone
     *            as the clone to add the {@link FilterState}s to
     */
    private void cloneFilterStates(StateMachine clone) {
        for (FilterState filter : getFilterStates()) {
            clone.addFilterState(clone.createFilterState(filter.getMethod()));
        }
    }

    /**
     * Clones the initial states of this {@link StateMachine}.
     *
     * @param clone
     *            as the clone to add the initial states to
     */
    private void cloneInitialStates(final StateMachine clone) {
        for (WebMethodState initial : getInitialStates()) {
            clone.addInitialState(clone.createWebMethodState(initial
                    .getMethod()));
        }
    }

    /**
     * Clones the {@link #makeURLLocations} of this {@link StateMachine}.
     *
     * @param clone
     *            as the clone to add the {@link #makeURLLocations} to
     */
    private void cloneMakeURLLocations(StateMachine clone) {
        for (Entry<InvokeExpr, MethodStatementContainer> entry : makeURLLocations
                .entrySet()) {
            final MethodStatementContainer container = entry.getValue();
            clone.addMakeURLLocation(entry.getKey(), container.getMethod(),
                    container.getStatement());
        }
    }

    /**
     * Clones the {@link State}s of this {@link StateMachine}.
     *
     * @param clone
     *            as the clone to add the states to
     */
    private void cloneStates(final StateMachine clone) {
        StateVisitor<State> stateCloner = new StateVisitor<State>() {

            @Override
            public FilterState visit(FilterState state) {
                return clone.createFilterState(state.getMethod());
            }

            @Override
            public HandlerState visit(HandlerState state) {
                return clone.createHandlerState(state.getMethod());
            }

            @Override
            public State visit(State state) {
                throw new RuntimeException("Unknown state: " + state);
            }

            @Override
            public WebMethodState visit(WebMethodState state) {
                return clone.createWebMethodState(state.getMethod());
            }

            @Override
            public State visit(RegularMethodState state) {
                return clone.createReqularMethodState(state.getMethod());
            }
        };

        for (State state : getAllStates()) {
            clone.addState(state.accept(stateCloner));
        }
    }

    /**
     * Clones the {@link Transition}s of this {@link StateMachine}.
     *
     * @param clone
     *            as the clone containing the {@link State}s to link
     */
    private void cloneTransitions(final StateMachine clone) {
        for (Entry<SootMethod, State> entry : methodStateMap.entrySet()) {
            SootMethod method = entry.getKey();
            State state = entry.getValue();
            final State clonedState = clone.getState(method);
            TransitionVisitor<Transition> transitionCloner = new TransitionVisitor<Transition>() {

                private State getClonedTarget(Transition transition) {
                    final State target = transition.getTarget();
                    if (target == null)
                        return null;
                    return clone.getState(target.getMethod());
                }

                private void setTransitions(Transition clone,
                        final Transition transition) {
                    transition.setOrigin(clonedState);
                    transition.setTarget(getClonedTarget(clone));
                }

                @Override
                public AnyTransition visit(AnyTransition transition) {
                    final AnyTransition clone = new AnyTransition();
                    setTransitions(transition, clone);
                    return clone;
                }

                @Override
                public FilterTransition visit(FilterTransition transition) {
                    final FilterTransition clone = new FilterTransition();
                    setTransitions(transition, clone);
                    return clone;
                }

                @Override
                public HandlerTransition visit(HandlerTransition transition) {
                    final HandlerTransition clone = new HandlerTransition();
                    setTransitions(transition, clone);
                    return clone;
                }

                @Override
                public LambdaTransition visit(LambdaTransition transition) {
                    final LambdaTransition clone = new LambdaTransition();
                    setTransitions(transition, clone);
                    return clone;
                }

                @Override
                public WebMethodTransition visit(WebMethodTransition transition) {
                    final WebMethodTransition clone = new WebMethodTransition(
                            transition.getExpr());
                    setTransitions(transition, clone);
                    return clone;
                }
            };
            for (Transition t : state.getTransitions()) {
                clonedState.addSuccessor(t.accept(transitionCloner));
            }
        }
    }

    public FilterState createFilterState(SootMethod method) {
        FilterState state = (FilterState) getState(method);
        if (state == null) {
            state = new FilterState(method);
            addState(state);
        }
        return state;
    }

    public RegularMethodState createReqularMethodState(SootMethod method) {
        RegularMethodState state = (RegularMethodState) getState(method);
        if (state == null) {
            state = new RegularMethodState(method);
            addState(state);
        }
        return state;
    }

    public HandlerState createHandlerState(SootMethod method) {
        HandlerState state = (HandlerState) getState(method);
        if (state == null) {
            state = new HandlerState(method);
            addState(state);
        }
        return state;
    }

    public WebMethodState createWebMethodState(SootMethod method) {
        WebMethodState state = (WebMethodState) getState(method);
        if (state == null) {
            state = new WebMethodState(method);
            addState(state);
        }
        return state;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (o == null || !(o instanceof StateMachine))
            return false;
        StateMachine m = (StateMachine) o;
        final boolean equalTransitions = equalTransitions(this, m);
        final boolean equalInitials = initialsStates.equals(m.initialsStates);
        final boolean equalFilters = filterStates.equals(m.filterStates);
        final boolean equalMethodStateMaps = methodStateMap
                .equals(m.methodStateMap);
        final boolean equalMakeURLLocations = makeURLLocations
                .equals(makeURLLocations);
        return equalTransitions && equalInitials && equalFilters
                && equalMethodStateMaps && equalMakeURLLocations;
    }

    boolean equalTransitions(StateMachine m1, StateMachine m2) {
        return m1.getTransitions().equals(m2.getTransitions());

    }

    public Set<State> getAllStates() {
        return new StateFlattener().getAllStates();
    }

    public Set<FilterState> getFilterStates() {
        return filterStates;
    }

    public Collection<WebMethodState> getInitialStates() {
        return initialsStates;
    }

    public Set<InvokeExpr> getMakeURLExpressions() {
        return makeURLLocations.keySet();
    }

    public MethodStatementContainer getMakeURLLocation(InvokeExpr expr) {
        final MethodStatementContainer methodStatementContainer = makeURLLocations
                .get(expr);
        if (methodStatementContainer == null)
            throw new IllegalArgumentException("Unknown expression:" + expr);
        return methodStatementContainer;
    }

    public Collection<Plugging> getPluggings() {
        return plugLocations.values();
    }

    public MethodStatementContainer getPlugLocation(InvokeExpr expr) {
        final Plugging plugging = plugLocations.get(expr);
        if (plugging == null)
            throw new IllegalArgumentException("Unknown expression:" + expr);
        final MethodStatementContainer methodStatementContainer = plugging
                .getContainer();
        return methodStatementContainer;
    }

    public Collection<MethodStatementContainer> getMakeURLLocations() {
        return makeURLLocations.values();
    }

    public State getState(SootMethod method) {
        return methodStateMap.get(method);
    }

    public StateFlattener getStateFlattener() {
        return new StateFlattener();
    }

    /**
     * Finds all {@link Transition}s between the {@link State}s of this
     * {@link StateMachine}.
     *
     * @return the {@link Transition}s
     */
    Set<Transition> getTransitions() {
        Set<Transition> transitions = new HashSet<Transition>();
        for (State s : getAllStates()) {
            for (Transition t : s.getTransitions())
                transitions.add(t);
        }
        return transitions;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((filterStates == null) ? 0 : filterStates.hashCode());
        result = prime * result
                + ((initialsStates == null) ? 0 : initialsStates.hashCode());
        result = prime
                * result
                + ((makeURLLocations == null) ? 0 : makeURLLocations.hashCode());
        result = prime * result
                + ((methodStateMap == null) ? 0 : methodStateMap.hashCode());
        return result;
    }

    public void removeLambdas() {
        boolean more = true;
        while (more) {
            more = false;
            for (State s : getAllStates()) {
                if (s != null) {
                    for (Transition t : s.getTransitions()) {
                        if (t instanceof LambdaTransition) {
                            LambdaTransition lambdaTransition = (LambdaTransition) t;
                            State target = lambdaTransition.getTarget();
                            if (target != null && !target.equals(s)) {
                                for (Transition tt : target.getTransitions()) {
                                    s.addSuccessor(tt.clone());
                                }
                            }
                            s.removeSuccessor(t);
                            more = true;
                        }
                    }
                }
            }
        }
    }

    public void addPlugging(Plugging plugging) {
        plugLocations.put(plugging.getContainer().getStatement()
                .getInvokeExpr(), plugging);
    }

    public Set<MethodStatementContainer> getPlugLocations() {
        Collection<Plugging> values = plugLocations.values();
        Set<MethodStatementContainer> locations = new HashSet<StateMachine.MethodStatementContainer>();
        for (Plugging plugging : values) {
            locations.add(plugging.getContainer());
        }
        return locations;
    }
}
TOP

Related Classes of dk.brics.jwig.analysis.graph.StateMachine$MethodStatementContainer

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.