1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.slf4j.simple.multiThreadedExecution;
26
27 import java.io.PrintStream;
28 import java.util.regex.Pattern;
29
30 public class StateCheckingPrintStream extends PrintStream {
31
32 static String PACKAGE_NAME = "org.slf4j.simple.multiThreadedExecution";
33
34
35 enum State {
36 INITIAL, UNKNOWN, HELLO, THROWABLE, AT1, AT2, OTHER;
37 }
38
39 PrintStream other;
40
41 volatile State currentState = State.INITIAL;
42
43 public StateCheckingPrintStream(PrintStream ps) {
44 super(ps);
45 }
46
47 public void print(String s) {
48 }
49
50 public void println(String s) {
51
52 State next = computeState(s);
53
54 switch (currentState) {
55 case INITIAL:
56 currentState = next;
57 break;
58
59 case UNKNOWN:
60 currentState = next;
61 break;
62
63 case OTHER:
64 if (next == State.UNKNOWN) {
65 currentState = State.UNKNOWN;
66 return;
67 }
68
69 if (next != State.OTHER && next != State.HELLO) {
70 throw badState(s, currentState, next);
71 }
72 currentState = next;
73 break;
74
75 case HELLO:
76 if (next != State.THROWABLE) {
77 throw badState(s, currentState, next);
78 }
79 currentState = next;
80 break;
81 case THROWABLE:
82 if (next != State.AT1) {
83 throw badState(s, currentState, next);
84 }
85 currentState = next;
86 break;
87
88 case AT1:
89 if (next != State.AT2) {
90 throw badState(s, currentState, next);
91 }
92 currentState = next;
93 break;
94
95 case AT2:
96 currentState = next;
97 break;
98 default:
99 throw new IllegalStateException("Unreachable code");
100 }
101 }
102
103 private IllegalStateException badState(String s, State currentState2, State next) {
104 return new IllegalStateException("Unexpected state " + next + " for current state " + currentState2 + " for " + s);
105
106 }
107
108 String OTHER_PATTERN_STR = ".*Other \\d{1,5}";
109 String HELLO_PATTERN_STR = ".*Hello \\d{1,5}";
110 String THROWABLE_PATTERN_STR = "java.lang.Throwable: i=\\d{1,5}";
111 String AT1_PATTERN_STR = "\\s*at " + PACKAGE_NAME + ".*";
112 String AT2_PATTERN_STR = "\\s*at " + ".*Thread.java.*";
113
114 Pattern PATTERN_OTHER = Pattern.compile(OTHER_PATTERN_STR);
115 Pattern PATTERN_HELLO = Pattern.compile(HELLO_PATTERN_STR);
116 Pattern PATTERN_THROWABLE = Pattern.compile(THROWABLE_PATTERN_STR);
117 Pattern PATTERN_AT1 = Pattern.compile(AT1_PATTERN_STR);
118 Pattern PATTERN_AT2 = Pattern.compile(AT2_PATTERN_STR);
119
120 private State computeState(String s) {
121
122 if (PATTERN_OTHER.matcher(s).matches()) {
123 return State.OTHER;
124 } else if (PATTERN_HELLO.matcher(s).matches()) {
125 return State.HELLO;
126 } else if (PATTERN_THROWABLE.matcher(s).matches()) {
127 return State.THROWABLE;
128 } else if (PATTERN_AT1.matcher(s).matches()) {
129 return State.AT1;
130 } else if (PATTERN_AT2.matcher(s).matches()) {
131 return State.AT2;
132 } else {
133 return State.UNKNOWN;
134 }
135 }
136
137 public void println(Object o) {
138 println(o.toString());
139 }
140 }