View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.statemachine;
19  
20  import java.io.BufferedReader;
21  import java.io.FileInputStream;
22  import java.io.IOException;
23  import java.io.InputStreamReader;
24  import java.nio.charset.Charset;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  import java.util.regex.Matcher;
32  import java.util.regex.Pattern;
33  
34  public class StateMachineLogParser {
35  
36      static Pattern fsmPattern = Pattern.compile("FSM-(\\d+):");
37  
38      static Map<String, List<String>> getFsmEventMap(BufferedReader f) throws IOException {
39          String s = f.readLine();
40          Map<String, List<String>> map = new HashMap<String, List<String>>();
41          while (s != null) {
42              Matcher m = fsmPattern.matcher(s);
43              if (m.find()) {
44                  String key = m.group(1);
45                  if (!map.containsKey(key)) {
46                      map.put(key, new ArrayList<String>());
47                  }
48                  map.get(key).add(s);
49              }
50              s = f.readLine();
51          }
52          return map;
53      }
54  
55      static class Tuple {
56          final String state1;
57          final String state2;
58          final String event;
59  
60          Tuple(String state1, String event, String state2) {
61              this.state1 = state1;
62              this.state2 = state2;
63              this.event = event;
64          }
65  
66          @Override
67          public boolean equals(Object o) {
68              if (o instanceof Tuple) {
69                  Tuple t = (Tuple) o;
70                  return state1.equals(t.state1)
71                          && state2.equals(t.state2)
72                          && event.equals(t.event);
73              }
74              return false;
75          }
76  
77          @Override
78          public int hashCode() {
79              return (state1 + event + state2).hashCode();
80          }
81  
82          @Override
83          public String toString() {
84              return state1 + " + " + event + " = " + state2;
85          }
86      }
87  
88      static Pattern hashcodePattern = Pattern.compile("(.+)@(.+)");
89      static Pattern subclassPattern = Pattern.compile("(.+)\\$(.+)");
90  
91      static String cleanupState(String state) {
92          Matcher m = hashcodePattern.matcher(state);
93          if (m.find()) {
94              state = m.group(1);
95          }
96          m = subclassPattern.matcher(state);
97          if (m.find()) {
98              state = m.group(2);
99          }
100         return state;
101     }
102 
103     static Pattern eventPattern = Pattern.compile("Received event (.+)@\\d+ in state (.+)@\\d+");
104     static Pattern transitionPattern = Pattern.compile("State transition (.+) -> (.+)");
105 
106     static Set<Tuple> getStateTuples(Map<String, List<String>> fsms) {
107         Set<Tuple> tuples = new HashSet<Tuple>();
108         for (List<String> transitions : fsms.values()) {
109             String currentEvent = null;
110             for (String s : transitions) {
111                 //System.err.println(s);
112                 Matcher m = eventPattern.matcher(s);
113                 if (m.find()) {
114                     currentEvent = m.group(1);
115                     continue;
116                 }
117                 m = transitionPattern.matcher(s);
118                 if (m.find()) {
119                     if (currentEvent == null) {
120                         System.err.println("event is null");
121                     }
122                     String state1 = m.group(1);
123                     String state2 = m.group(2);
124                     tuples.add(new Tuple(cleanupState(state1),
125                             currentEvent,
126                             cleanupState(state2)));
127                     continue;
128                 }
129                 if (s.contains("deferred")) {
130                     currentEvent = currentEvent + "[deferred]";
131                 }
132             }
133         }
134         return tuples;
135     }
136 
137     static void drawDotGraph(Set<Tuple> tuples) {
138         Set<String> states = new HashSet<String>();
139         for (Tuple t : tuples) {
140             states.add(t.state1);
141             states.add(t.state2);
142         }
143 
144         System.out.println("digraph finite_state_machine {");
145         for (String s : states) {
146             System.out.println("\tnode [ shape = circle ] " + s + ";");
147         }
148         for (Tuple t : tuples) {
149             System.out.println("\t" + t.state1 + " -> " + t.state2 + " [ label = \"" + t.event + "\" ];");
150         }
151         System.out.println("}");
152     }
153 
154     public static void main(String[] args) throws Exception {
155         if (args.length == 0) {
156             System.out.println("Usage: StateMachineLogParser <logfile> | dot -Tsvg ");
157             System.exit(-1);
158         }
159         BufferedReader f = new BufferedReader(new InputStreamReader(new FileInputStream(args[0]), Charset.forName("UTF-8")));
160         Map<String, List<String>> fsms = getFsmEventMap(f);
161         Set<Tuple> tuples = getStateTuples(fsms);
162         drawDotGraph(tuples);
163     }
164 }