001/**
002 * Copyright (c) 2004-2021 QOS.ch
003 * All rights reserved.
004 *
005 * Permission is hereby granted, free of charge, to any person obtaining
006 * a copy of this software and associated documentation files (the
007 * "Software"), to  deal in  the Software without  restriction, including
008 * without limitation  the rights to  use, copy, modify,  merge, publish,
009 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
010 * permit persons to whom the Software  is furnished to do so, subject to
011 * the following conditions:
012 *
013 * The  above  copyright  notice  and  this permission  notice  shall  be
014 * included in all copies or substantial portions of the Software.
015 *
016 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
017 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
018 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
021 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023 *
024 */
025package org.slf4j.simple.multiThreadedExecution;
026
027import java.io.PrintStream;
028import java.util.regex.Pattern;
029
030public class StateCheckingPrintStream extends PrintStream {
031
032    static String PACKAGE_NAME = "org.slf4j.simple.multiThreadedExecution";
033    
034    
035    enum State {
036        INITIAL, UNKNOWN, HELLO, THROWABLE, AT1, AT2, OTHER;
037    }
038
039    PrintStream other;
040
041    volatile State currentState = State.INITIAL;
042
043    public StateCheckingPrintStream(PrintStream ps) {
044        super(ps);
045    }
046
047    public void print(String s) {
048    }
049
050    public void println(String s) {
051
052        State next = computeState(s);
053        //System.out.println(next + " " + s);
054        switch (currentState) {
055        case INITIAL:
056            currentState = next;
057            break;
058
059        case UNKNOWN:
060            currentState = next;
061            break;
062
063        case OTHER:
064            if (next == State.UNKNOWN) {
065                currentState = State.UNKNOWN;
066                return;
067            }
068
069            if (next != State.OTHER && next != State.HELLO) {
070                throw badState(s, currentState, next);
071            }
072            currentState = next;
073            break;
074
075        case HELLO:
076            if (next != State.THROWABLE) {
077                throw badState(s, currentState, next);
078            } 
079            currentState = next;
080            break;
081        case THROWABLE:
082            if (next != State.AT1) {
083                throw badState(s, currentState, next);
084            }
085            currentState = next;
086            break;
087
088        case AT1:
089            if (next != State.AT2) {
090                throw badState(s, currentState, next);
091            }
092            currentState = next;
093            break;
094
095        case AT2:
096            currentState = next;
097            break;
098        default:
099            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}