001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2024
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas/
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see https://www.gnu.org/licenses/.
027 */
028
029package edu.wisc.ssec.mcidasv.jython;
030
031import static java.util.Objects.requireNonNull;
032
033import java.io.ByteArrayOutputStream;
034import java.io.IOException;
035import java.io.OutputStream;
036import java.io.UnsupportedEncodingException;
037import java.util.Map;
038import java.util.concurrent.ConcurrentHashMap;
039
040public class OutputStreamDemux extends ByteArrayOutputStream {
041
042    protected enum OutputType { NORMAL, ERROR };
043
044    private OutputType type;
045
046    private final Map<String, ByteArrayOutputStream> streamMap = new ConcurrentHashMap<>();
047    private final Map<String, Interpreter> interpreterMap = new ConcurrentHashMap<>();
048    private final Map<String, Console> consoleMap = new ConcurrentHashMap<>();
049
050    private static String id() {
051        return Thread.currentThread().getName();
052    }
053
054    public synchronized void addStream(final Console console, final Interpreter interpreter, final OutputType type) {
055        requireNonNull(console, "Cannot provide a null Jython console");
056        requireNonNull(interpreter, "Cannot provide a null Jython interpreter");
057        this.type = requireNonNull(type, "Cannot provide a null output type");
058        String threadId = id();
059        streamMap.put(threadId, new ByteArrayOutputStream());
060        interpreterMap.put(threadId, interpreter);
061        consoleMap.put(threadId, console);
062    }
063
064    @Override public void close() throws IOException {
065        streamMap.get(id()).close();
066    }
067
068    @Override public synchronized void flush() throws IOException {
069        streamMap.get(id()).flush();
070        Console console = consoleMap.get(id());
071        Interpreter interpreter = interpreterMap.get(id());
072        interpreter.handleStreams(console, null);
073    }
074
075    @Override public void write(byte[] b) throws IOException {
076        streamMap.get(id()).write(b);
077    }
078
079    @Override public void write(byte[] b, int off, int len) {
080        streamMap.get(id()).write(b, off, len);
081    }
082
083    @Override public void write(int b) {
084        streamMap.get(id()).write(b);
085    }
086
087    @Override public void reset() {
088        streamMap.get(id()).reset();
089    }
090
091    @Override public int size() {
092        return streamMap.get(id()).size();
093    }
094
095    @Override public byte[] toByteArray() {
096        return streamMap.get(id()).toByteArray();
097    }
098
099    @Deprecated @Override public String toString(int hibyte) {
100        return streamMap.get(id()).toString();
101    }
102
103    @Override public String toString(String charsetName) throws UnsupportedEncodingException {
104        return streamMap.get(id()).toString(charsetName);
105    }
106
107    @Override public void writeTo(OutputStream out) throws IOException {
108        streamMap.get(id()).writeTo(out);
109    }
110
111    @Override public String toString() {
112        ByteArrayOutputStream stream = streamMap.get(id());
113        if (stream == null) {
114            return "null";
115        } else {
116            return stream.toString();
117        }
118    }
119}