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() {
-      
+
    }
 }

Reply via email to