This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch pkriens/systemio in repository https://gitbox.apache.org/repos/asf/felix-dev.git
commit e6cd21afecef4e298f928a90cb2b9dfa886fb206 Author: Guillaume Nodet <gno...@gmail.com> AuthorDate: Wed Apr 30 11:21:00 2025 +0200 FELIX-6642: Refactor ThreadIOImpl and SystemIOImpl to use composition instead of inheritance This refactoring changes the design to use composition instead of inheritance, which is more appropriate for these classes. The classes no longer extend InputStream but instead contain inner classes that extend InputStream and provide the same functionality. --- .../felix/gogo/runtime/systemio/SystemIOImpl.java | 40 ++++++++++++----- .../felix/gogo/runtime/threadio/ThreadIOImpl.java | 51 ++++++++++++++++------ .../felix/gogo/runtime/threadio/TestThreadIO.java | 27 ++++++++---- 3 files changed, 84 insertions(+), 34 deletions(-) diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/systemio/SystemIOImpl.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/systemio/SystemIOImpl.java index 17a95dfebc..1660cae049 100644 --- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/systemio/SystemIOImpl.java +++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/systemio/SystemIOImpl.java @@ -36,7 +36,7 @@ import org.osgi.namespace.service.ServiceNamespace; */ @Capability(namespace = ServiceNamespace.SERVICE_NAMESPACE, attribute = "objectClass='org.apache.felix.service.systemio.SystemIO'") -public class SystemIOImpl extends InputStream implements SystemIO +public class SystemIOImpl implements SystemIO { static private final Logger log = Logger.getLogger(SystemIOImpl.class.getName()); @@ -50,6 +50,7 @@ public class SystemIOImpl extends InputStream implements SystemIO private PrintStream rout; private PrintStream rerr; + private SystemInputStream systemInputStream; public void start() @@ -59,14 +60,15 @@ public class SystemIOImpl extends InputStream implements SystemIO stderrs.add(err); rout = new PrintStream(new DelegateStream(stdouts), true); rerr = new PrintStream(new DelegateStream(stderrs), true); + systemInputStream = new SystemInputStream(); System.setOut(rout); System.setErr(rerr); - System.setIn(this); + System.setIn(systemInputStream); } public void stop() { - if (System.in == this) + if (System.in == systemInputStream) { System.setIn(in); } @@ -123,16 +125,30 @@ public class SystemIOImpl extends InputStream implements SystemIO }; } - @Override - public int read() throws IOException - { - assert stdins.size() > 0; - for ( InputStream in : stdins) { - int b = in.read(); - if ( b != SystemIO.NO_DATA) - return b; + /** + * Get the system input stream that will be used to replace System.in + * + * @return the system input stream + */ + public InputStream getSystemInputStream() { + return systemInputStream; + } + + /** + * Inner class that handles the InputStream functionality + */ + private class SystemInputStream extends InputStream { + @Override + public int read() throws IOException + { + assert stdins.size() > 0; + for ( InputStream in : stdins) { + int b = in.read(); + if ( b != SystemIO.NO_DATA) + return b; + } + return -1; // unreachable because stdin is at the end } - return -1; // unreachable because stdin is at the end } } diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadIOImpl.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadIOImpl.java index b6e659486a..1f4f16e02d 100644 --- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadIOImpl.java +++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadIOImpl.java @@ -33,12 +33,13 @@ import org.osgi.namespace.service.ServiceNamespace; @Capability(namespace = ServiceNamespace.SERVICE_NAMESPACE, attribute = "objectClass='org.apache.felix.service.threadio.ThreadIO'") -public class ThreadIOImpl extends InputStream implements ThreadIO +public class ThreadIOImpl implements ThreadIO { static final Logger log = Logger.getLogger(ThreadIOImpl.class.getName()); final SystemIO systemio; final ThreadLocal<Streams> threadLocal = new ThreadLocal<>(); Closeable system; + private ThreadInputStream threadInputStream; class Streams { @@ -91,6 +92,16 @@ public class ThreadIOImpl extends InputStream implements ThreadIO public ThreadIOImpl(SystemIO systemio) { this.systemio = systemio; + this.threadInputStream = new ThreadInputStream(); + } + + /** + * Constructor for use in non-OSGi environments (like gogo/jline) + */ + public ThreadIOImpl() + { + this.systemio = null; + this.threadInputStream = new ThreadInputStream(); } public void start() @@ -126,9 +137,9 @@ public class ThreadIOImpl extends InputStream implements ThreadIO private synchronized void init() { - if (system == null) + if (system == null && systemio != null) { - system = systemio.system(this, new ThreadOutStream() + system = systemio.system(threadInputStream, new ThreadOutStream() { @Override @@ -149,19 +160,33 @@ public class ThreadIOImpl extends InputStream implements ThreadIO } } - @Override - public int read() throws IOException - { - Streams s = threadLocal.get(); - while (s != null) + /** + * Get the thread input stream that can be used to replace System.in + * + * @return the thread input stream + */ + public InputStream getThreadInputStream() { + return threadInputStream; + } + + /** + * Inner class that handles the InputStream functionality + */ + private class ThreadInputStream extends InputStream { + @Override + public int read() throws IOException { - if (s.in == null) - s = s.prev; - else + Streams s = threadLocal.get(); + while (s != null) { - return s.in.read(); + if (s.in == null) + s = s.prev; + else + { + return s.in.read(); + } } + return SystemIO.NO_DATA; } - return SystemIO.NO_DATA; } } diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/threadio/TestThreadIO.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/threadio/TestThreadIO.java index 0b3b39e437..f9e7314eb0 100644 --- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/threadio/TestThreadIO.java +++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/threadio/TestThreadIO.java @@ -80,7 +80,7 @@ public class TestThreadIO /** * Simple test too see if the basics work. - * @throws IOException + * @throws IOException */ @SuppressWarnings("resource") @Test @@ -112,7 +112,7 @@ public class TestThreadIO tio.close(); } } - + @Test @SuppressWarnings("resource") public void testNullInputStream() throws IOException { @@ -129,7 +129,7 @@ public class TestThreadIO byte data[] = new byte[3]; System.in.read(data); assertTrue(Arrays.equals(test, data)); - + tio.close(); } finally @@ -151,10 +151,19 @@ public class TestThreadIO tio.start(); try { - byte data[] = new byte[3]; - System.in.read(data); - assertTrue(Arrays.equals(test, data)); - tio.close(); + // Save the original System.in + InputStream originalIn = System.in; + // Set System.in to the ThreadInputStream + System.setIn(tio.getThreadInputStream()); + try { + byte data[] = new byte[3]; + System.in.read(data); + assertTrue(Arrays.equals(test, data)); + tio.close(); + } finally { + // Restore original System.in + System.setIn(originalIn); + } } finally { @@ -163,9 +172,9 @@ public class TestThreadIO tio.stop(); } } - + @Test public void testWithFrameworkService() { - + } }