You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2015/02/26 12:44:04 UTC

[2/2] mina-sshd git commit: [SSHD-413] org.apache.sshd.common.Closeable should extend java.io.Closeable

[SSHD-413] org.apache.sshd.common.Closeable should extend java.io.Closeable

Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/2f3228a7
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/2f3228a7
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/2f3228a7

Branch: refs/heads/master
Commit: 2f3228a75d7db30ed1655f88302c431e3d740bfb
Parents: eb369ab
Author: Guillaume Nodet <gn...@apache.org>
Authored: Thu Feb 26 11:46:19 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Thu Feb 26 11:46:19 2015 +0100

----------------------------------------------------------------------
 .../java/org/apache/sshd/common/Closeable.java  |   2 +-
 .../sshd/common/channel/AbstractChannel.java    |   2 +-
 .../apache/sshd/common/io/mina/MinaService.java |  33 ++++--
 .../apache/sshd/common/io/mina/MinaSession.java |   2 +-
 .../apache/sshd/common/util/CloseableUtils.java |  31 ++++-
 .../sshd/server/channel/ChannelSession.java     |   3 +-
 .../sshd/common/util/CloseableUtilsTest.java    | 118 +++++++++++++++++++
 7 files changed, 171 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2f3228a7/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java b/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java
index fa9a21d..6afac75 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java
@@ -27,7 +27,7 @@ import org.apache.sshd.common.future.CloseFuture;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface Closeable {
+public interface Closeable extends java.io.Closeable {
 
     /**
      * Close this resource asynchronously and return a future.

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2f3228a7/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
index c2d4231..1d04b17 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
@@ -155,7 +155,7 @@ public abstract class AbstractChannel extends CloseableUtils.AbstractInnerClosea
         return new GracefulChannelCloseable();
     }
 
-    public class GracefulChannelCloseable implements Closeable {
+    public class GracefulChannelCloseable extends CloseableUtils.IoBaseCloseable {
 
         protected volatile boolean closing;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2f3228a7/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java
index 1981eb8..ee795b3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java
@@ -23,7 +23,6 @@ import java.util.Map;
 
 import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.mina.core.service.IoHandler;
-import org.apache.mina.core.service.IoHandlerAdapter;
 import org.apache.mina.core.service.IoProcessor;
 import org.apache.mina.core.service.IoService;
 import org.apache.mina.core.session.IdleStatus;
@@ -33,14 +32,13 @@ import org.apache.mina.transport.socket.SocketSessionConfig;
 import org.apache.mina.transport.socket.nio.NioSession;
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.util.CloseableUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  */
-public abstract class MinaService extends IoHandlerAdapter implements org.apache.sshd.common.io.IoService, IoHandler, Closeable {
+public abstract class MinaService extends CloseableUtils.AbstractCloseable implements org.apache.sshd.common.io.IoService, IoHandler, Closeable {
 
     protected final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -61,17 +59,10 @@ public abstract class MinaService extends IoHandlerAdapter implements org.apache
         getIoService().dispose();
     }
 
-    public CloseFuture close(boolean immediately) {
+    @Override
+    protected void doCloseImmediately() {
         getIoService().dispose();
-        return CloseableUtils.closed();
-    }
-
-    public boolean isClosed() {
-        return getIoService().isDisposed();
-    }
-
-    public boolean isClosing() {
-        return getIoService().isDisposing();
+        super.doCloseImmediately();
     }
 
     public Map<Long, org.apache.sshd.common.io.IoSession> getManagedSessions() {
@@ -87,6 +78,22 @@ public abstract class MinaService extends IoHandlerAdapter implements org.apache
         return sessions;
     }
 
+    public void sessionOpened(IoSession session) throws Exception {
+        // Empty handler
+    }
+
+    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
+        // Empty handler
+    }
+
+    public void messageSent(IoSession session, Object message) throws Exception {
+        // Empty handler
+    }
+
+    public void inputClosed(IoSession session) throws Exception {
+        session.close(true);
+    }
+
     public void sessionCreated(IoSession session) throws Exception {
         org.apache.sshd.common.io.IoSession ioSession = new MinaSession(this, session);
         session.setAttribute(org.apache.sshd.common.io.IoSession.class, ioSession);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2f3228a7/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaSession.java b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaSession.java
index 6f07207..ed8f380 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaSession.java
@@ -82,7 +82,7 @@ public class MinaSession extends CloseableUtils.AbstractInnerCloseable implement
 
     @Override
     protected Closeable getInnerCloseable() {
-        return new Closeable() {
+        return new CloseableUtils.IoBaseCloseable() {
             public boolean isClosing() {
                 return session.isClosing();
             }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2f3228a7/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
index 94acdf5..97ff2d4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
@@ -18,6 +18,8 @@
  */
 package org.apache.sshd.common.util;
 
+import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -44,6 +46,22 @@ import org.slf4j.LoggerFactory;
  */
 public class CloseableUtils {
 
+    // TODO once JDK 8+ becomes the minimum for this project, make it a static method in the Closeable interface
+    public static void close(Closeable closeable) throws IOException {
+        if (closeable == null) {
+            return;
+        }
+
+        if ((!closeable.isClosed()) && (!closeable.isClosing())) {
+            CloseFuture future=closeable.close(true);
+            try {
+                future.await();
+            } catch(InterruptedException e) {
+                throw new InterruptedIOException(e.getClass().getSimpleName() + " while await future closure: " + e.getMessage());
+            }
+        }
+    }
+
     public static CloseFuture closed() {
         CloseFuture future = new DefaultCloseFuture(null);
         future.setClosed();
@@ -130,7 +148,14 @@ public class CloseableUtils {
 
     }
 
-    private static class SimpleCloseable implements Closeable {
+    public static abstract class IoBaseCloseable implements Closeable {
+        // TODO once JDK 8+ becomes the minimum for this project, make it a default method instead of this class
+        public void close() throws IOException {
+            CloseableUtils.close(this);
+        }
+    }
+
+    private static class SimpleCloseable extends IoBaseCloseable {
 
         protected final DefaultCloseFuture future;
         protected final AtomicBoolean closing;
@@ -160,7 +185,7 @@ public class CloseableUtils {
 
     private static class ParallelCloseable extends SimpleCloseable {
 
-        final Iterable<? extends Closeable> closeables;
+        private final Iterable<? extends Closeable> closeables;
 
         private ParallelCloseable(Object lock, Iterable<? extends Closeable> closeables) {
             super(lock);
@@ -253,7 +278,7 @@ public class CloseableUtils {
         }
     }
 
-    public static abstract class AbstractCloseable implements Closeable {
+    public static abstract class AbstractCloseable extends IoBaseCloseable {
 
         protected enum State {
             Opened, Graceful, Immediate, Closed

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2f3228a7/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
index 16a3ec3..658c050 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
@@ -48,6 +48,7 @@ import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.DefaultCloseFuture;
 import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.CloseableUtils;
 import org.apache.sshd.common.util.IoUtils;
 import org.apache.sshd.common.util.LoggingFilterOutputStream;
 import org.apache.sshd.server.AsyncCommand;
@@ -213,7 +214,7 @@ public class ChannelSession extends AbstractServerChannel {
                 .build();
     }
 
-    public class CommandCloseable implements Closeable {
+    public class CommandCloseable extends CloseableUtils.IoBaseCloseable {
         public boolean isClosed() {
             return commandExitFuture.isClosed();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2f3228a7/sshd-core/src/test/java/org/apache/sshd/common/util/CloseableUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/util/CloseableUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/util/CloseableUtilsTest.java
new file mode 100644
index 0000000..3bb8994
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/util/CloseableUtilsTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.util;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sshd.common.Closeable;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.DefaultCloseFuture;
+import org.apache.sshd.util.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class CloseableUtilsTest extends BaseTest {
+    public CloseableUtilsTest() {
+        super();
+    }
+
+    @Test
+    public void testCloseImmediateNotCalledIfAlreadyClosed() throws IOException {
+        Closeable   closeable=new CloseableUtils.IoBaseCloseable() {
+                public CloseFuture close(boolean immediately) {
+                    Assert.fail("Unexpected call to close(" + immediately + ")");
+                    return null;
+                }
+    
+                public boolean isClosed() {
+                    return true;
+                }
+    
+                public boolean isClosing() {
+                    return false;
+                }
+            };
+       closeable.close();
+    }
+
+    @Test
+    public void testCloseImmediateNotCalledIfIsClosing() throws IOException {
+        Closeable   closeable=new CloseableUtils.IoBaseCloseable() {
+                public CloseFuture close(boolean immediately) {
+                    Assert.fail("Unexpected call to close(" + immediately + ")");
+                    return null;
+                }
+    
+                public boolean isClosed() {
+                    return false;
+                }
+    
+                public boolean isClosing() {
+                    return true;
+                }
+            };
+       closeable.close();
+    }
+    
+    @Test
+    public void testCloseImmediateCalledAndWait() throws Exception {
+        final DefaultCloseFuture    future=new DefaultCloseFuture(this);
+        final AtomicInteger         callsCount=new AtomicInteger(0);
+        final Closeable   closeable=new CloseableUtils.IoBaseCloseable() {
+                public CloseFuture close(boolean immediately) {
+                    Assert.assertTrue("Closure is not immediate", immediately);
+                    Assert.assertEquals("Multiple close immediate calls", 1, callsCount.incrementAndGet());
+                    return future;
+                }
+    
+                public boolean isClosed() {
+                    return false;
+                }
+    
+                public boolean isClosing() {
+                    return false;
+                }
+            };
+       ExecutorService  service=ThreadUtils.newSingleThreadExecutor(getCurrentTestName());
+       try {
+           Future<?>    task=service.submit(new Runnable() {
+                    public void run() {
+                        try {
+                            closeable.close();
+                        } catch(IOException e) {
+                            throw new RuntimeException(e);
+                        }
+                    }
+               });
+           future.setClosed();  // signal close complete
+           task.get(5L, TimeUnit.SECONDS);  // make sure #await call terminated
+           Assert.assertEquals("Close immediate not called", 1, callsCount.get());
+       } finally {
+           service.shutdownNow();
+       }
+    }
+}