blob: 0f14b7d1a7a84788525fbaacaab0c87d7fb92e60 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.debug.internal.core;
import java.io.IOException;
import java.nio.charset.Charset;
import org.eclipse.debug.core.model.IBinaryStreamMonitor;
import org.eclipse.debug.core.model.IBinaryStreamsProxy;
import org.eclipse.debug.core.model.IStreamMonitor;
import org.eclipse.debug.core.model.IStreamsProxy;
import org.eclipse.debug.core.model.IStreamsProxy2;
/**
* Standard implementation of a streams proxy for {@link IStreamsProxy},
* {@link IStreamsProxy2} and {@link IBinaryStreamsProxy}.
* <p>
* Will use the same monitor instances for binary and string stream handling.
*/
public class StreamsProxy implements IBinaryStreamsProxy {
/**
* The monitor for the output stream (connected to standard out of the process)
*/
private OutputStreamMonitor fOutputMonitor;
/**
* The monitor for the error stream (connected to standard error of the process)
*/
private OutputStreamMonitor fErrorMonitor;
/**
* The monitor for the input stream (connected to standard in of the process)
*/
private InputStreamMonitor fInputMonitor;
/**
* Records the open/closed state of communications with
* the underlying streams. Note: fClosed is initialized to
* <code>false</code> by default.
*/
private boolean fClosed;
/**
* Creates a <code>StreamsProxy</code> on the streams of the given system
* process.
*
* @param process system process to create a streams proxy on
* @param charset the process's charset or <code>null</code> if default
*/
@SuppressWarnings("resource")
public StreamsProxy(Process process, Charset charset) {
if (process == null) {
return;
}
fOutputMonitor = new OutputStreamMonitor(process.getInputStream(), charset);
fErrorMonitor = new OutputStreamMonitor(process.getErrorStream(), charset);
fInputMonitor = new InputStreamMonitor(process.getOutputStream(), charset);
fOutputMonitor.startMonitoring();
fErrorMonitor.startMonitoring();
fInputMonitor.startMonitoring();
}
/**
* Creates a <code>StreamsProxy</code> on the streams of the given system
* process.
*
* @param process system process to create a streams proxy on
* @param encoding the process's encoding or <code>null</code> if default
* @deprecated use {@link #StreamsProxy(Process, Charset)} instead
*/
@Deprecated
public StreamsProxy(Process process, String encoding) {
// This constructor was once removed in favor of the Charset variant
// but Bug 562653 brought up a client which use this internal class via
// reflection and breaks without this constructor. So we restored the
// old constructor for the time being.
this(process, Charset.forName(encoding));
}
/**
* Causes the proxy to close all communications between it and the
* underlying streams after all remaining data in the streams is read.
*/
public void close() {
if (!isClosed(true)) {
fOutputMonitor.close();
fErrorMonitor.close();
fInputMonitor.close();
}
}
/**
* Returns whether the proxy is currently closed. This method
* synchronizes access to the <code>fClosed</code> flag.
*
* @param setClosed If <code>true</code> this method will also set the
* <code>fClosed</code> flag to true. Otherwise, the <code>fClosed</code>
* flag is not modified.
* @return Returns whether the stream proxy was already closed.
*/
private synchronized boolean isClosed(boolean setClosed) {
boolean closed = fClosed;
if (setClosed) {
fClosed = true;
}
return closed;
}
/**
* Causes the proxy to close all
* communications between it and the
* underlying streams immediately.
* Data remaining in the streams is lost.
*/
public void kill() {
synchronized (this) {
fClosed= true;
}
fOutputMonitor.kill();
fErrorMonitor.kill();
fInputMonitor.close();
}
@Override
public IStreamMonitor getErrorStreamMonitor() {
return fErrorMonitor;
}
@Override
public IStreamMonitor getOutputStreamMonitor() {
return fOutputMonitor;
}
@Override
public void write(String input) throws IOException {
if (!isClosed(false)) {
fInputMonitor.write(input);
} else {
throw new IOException();
}
}
@Override
public void closeInputStream() throws IOException {
if (!isClosed(false)) {
fInputMonitor.closeInputStream();
} else {
throw new IOException();
}
}
@Override
public IBinaryStreamMonitor getBinaryErrorStreamMonitor() {
return fErrorMonitor;
}
@Override
public IBinaryStreamMonitor getBinaryOutputStreamMonitor() {
return fOutputMonitor;
}
@Override
public void write(byte[] data, int offset, int length) throws IOException {
if (!isClosed(false)) {
fInputMonitor.write(data, offset, length);
} else {
throw new IOException();
}
}
}