package sockslib.common.net;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* @author Youchao Feng
* @version 1.0
* @date Sep 21, 2015 2:34 PM
*/
public class MonitorOutputStreamWrapper extends OutputStream {
private OutputStream originalOutputStream;
private List<OutputStreamMonitor> monitors;
public MonitorOutputStreamWrapper(OutputStream outputStream, OutputStreamMonitor... monitors) {
this.originalOutputStream = outputStream;
this.monitors = new ArrayList<>(monitors.length);
Collections.addAll(this.monitors, monitors);
}
public MonitorOutputStreamWrapper(OutputStream outputStream, List<OutputStreamMonitor> monitors) {
this.originalOutputStream = checkNotNull(outputStream);
this.monitors = checkNotNull(monitors);
}
public static OutputStream wrap(OutputStream outputStream, OutputStreamMonitor... monitors) {
return new MonitorOutputStreamWrapper(outputStream, monitors);
}
public static OutputStream wrap(OutputStream outputStream, List<OutputStreamMonitor> monitors) {
return new MonitorOutputStreamWrapper(outputStream, monitors);
}
public MonitorOutputStreamWrapper addMonitor(OutputStreamMonitor monitor) {
if (monitors == null) {
monitors = new ArrayList<>(1);
}
monitors.add(checkNotNull(monitor));
return this;
}
public MonitorOutputStreamWrapper removeMonitor(OutputStreamMonitor monitor) {
if (monitors != null) {
monitors.remove(monitor);
}
return this;
}
public OutputStream getOriginalOutputStream() {
return originalOutputStream;
}
public void setOriginalOutputStream(OutputStream originalOutputStream) {
this.originalOutputStream = checkNotNull(originalOutputStream);
}
@Override
public void write(int b) throws IOException {
originalOutputStream.write(b);
byte[] bytes = {(byte) b};
informMonitor(bytes);
}
public List<OutputStreamMonitor> getMonitors() {
return monitors;
}
public void setMonitors(List<OutputStreamMonitor> monitors) {
this.monitors = monitors;
}
@Override
public void close() throws IOException {
originalOutputStream.close();
}
@Override
public void flush() throws IOException {
originalOutputStream.flush();
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
originalOutputStream.write(b, off, len);
informMonitor(b, off, len);
}
@Override
public void write(byte[] b) throws IOException {
originalOutputStream.write(b);
informMonitor(b);
}
private void informMonitor(byte[] bytes) {
if (monitors != null) {
for (OutputStreamMonitor monitor : monitors) {
monitor.onWrite(bytes);
}
}
}
private void informMonitor(byte[] bytes, int off, int length) {
if (monitors != null) {
for (OutputStreamMonitor monitor : monitors) {
monitor.onWrite(Arrays.copyOfRange(bytes, off, off + length));
}
}
}
}