[SSHD-835] Extracted thread related support classes to own files
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/1e29158b Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/1e29158b Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/1e29158b Branch: refs/heads/master Commit: 1e29158ba59b3d5fc863c30b83805d6958c84c36 Parents: a52a9de Author: Goldstein Lyor <[email protected]> Authored: Thu Jul 26 08:00:15 2018 +0300 Committer: Goldstein Lyor <[email protected]> Committed: Thu Jul 26 08:04:30 2018 +0300 ---------------------------------------------------------------------- .../common/util/threads/NoCloseExecutor.java | 160 ++++++++++ .../util/threads/SshThreadPoolExecutor.java | 138 +++++++++ .../common/util/threads/SshdThreadFactory.java | 78 +++++ .../sshd/common/util/threads/ThreadUtils.java | 294 +------------------ 4 files changed, 379 insertions(+), 291 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1e29158b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/NoCloseExecutor.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/threads/NoCloseExecutor.java b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/NoCloseExecutor.java new file mode 100644 index 0000000..cb42805 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/NoCloseExecutor.java @@ -0,0 +1,160 @@ +/* + * 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.threads; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +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.ValidateUtils; + +/** + * Wraps an {@link ExecutorService} as a {@link CloseableExecutorService} + * and avoids calling its {@code shutdown} methods when the wrapper is shut down + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class NoCloseExecutor implements CloseableExecutorService { + protected final ExecutorService executor; + protected final CloseFuture closeFuture; + + public NoCloseExecutor(ExecutorService executor) { + this.executor = executor; + closeFuture = new DefaultCloseFuture(null, null); + } + + @Override + public <T> Future<T> submit(Callable<T> task) { + ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); + return executor.submit(task); + } + + @Override + public <T> Future<T> submit(Runnable task, T result) { + ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); + return executor.submit(task, result); + } + + @Override + public Future<?> submit(Runnable task) { + ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); + return executor.submit(task); + } + + @Override + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) + throws InterruptedException { + ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); + return executor.invokeAll(tasks); + } + + @Override + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) + throws InterruptedException { + ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); + return executor.invokeAll(tasks, timeout, unit); + } + + @Override + public <T> T invokeAny(Collection<? extends Callable<T>> tasks) + throws InterruptedException, ExecutionException { + ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); + return executor.invokeAny(tasks); + } + + @Override + public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); + return executor.invokeAny(tasks, timeout, unit); + } + + @Override + public void execute(Runnable command) { + ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); + executor.execute(command); + } + + @Override + public void shutdown() { + close(true); + } + + @Override + public List<Runnable> shutdownNow() { + close(true); + return Collections.emptyList(); + } + + @Override + public boolean isShutdown() { + return isClosed(); + } + + @Override + public boolean isTerminated() { + return isClosed(); + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + try { + return closeFuture.await(timeout, unit); + } catch (IOException e) { + throw (InterruptedException) new InterruptedException().initCause(e); + } + } + + @Override + public CloseFuture close(boolean immediately) { + closeFuture.setClosed(); + return closeFuture; + } + + @Override + public void addCloseFutureListener(SshFutureListener<CloseFuture> listener) { + closeFuture.addListener(listener); + } + + @Override + public void removeCloseFutureListener(SshFutureListener<CloseFuture> listener) { + closeFuture.removeListener(listener); + } + + @Override + public boolean isClosed() { + return closeFuture.isClosed(); + } + + @Override + public boolean isClosing() { + return isClosed(); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1e29158b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/SshThreadPoolExecutor.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/threads/SshThreadPoolExecutor.java b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/SshThreadPoolExecutor.java new file mode 100644 index 0000000..ccaa655 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/SshThreadPoolExecutor.java @@ -0,0 +1,138 @@ +/* + * 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.threads; + +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.sshd.common.future.CloseFuture; +import org.apache.sshd.common.future.SshFutureListener; +import org.apache.sshd.common.util.closeable.AbstractCloseable; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class SshThreadPoolExecutor extends ThreadPoolExecutor implements CloseableExecutorService { + protected final DelegateCloseable closeable = new DelegateCloseable(); + + protected class DelegateCloseable extends AbstractCloseable { + protected DelegateCloseable() { + super(); + } + + @Override + protected CloseFuture doCloseGracefully() { + shutdown(); + return closeFuture; + } + + @Override + protected void doCloseImmediately() { + shutdownNow(); + super.doCloseImmediately(); + } + + protected void setClosed() { + closeFuture.setClosed(); + } + } + + public SshThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); + } + + public SshThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, + BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + } + + public SshThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, + BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); + } + + public SshThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, + BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); + } + + @Override + protected void terminated() { + closeable.doCloseImmediately(); + } + + @Override + public void shutdown() { + super.shutdown(); + } + + @Override + public List<Runnable> shutdownNow() { + return super.shutdownNow(); + } + + @Override + public boolean isShutdown() { + return super.isShutdown(); + } + + @Override + public boolean isTerminating() { + return super.isTerminating(); + } + + @Override + public boolean isTerminated() { + return super.isTerminated(); + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return super.awaitTermination(timeout, unit); + } + + @Override + public CloseFuture close(boolean immediately) { + return closeable.close(immediately); + } + + @Override + public void addCloseFutureListener(SshFutureListener<CloseFuture> listener) { + closeable.addCloseFutureListener(listener); + } + + @Override + public void removeCloseFutureListener(SshFutureListener<CloseFuture> listener) { + closeable.removeCloseFutureListener(listener); + } + + @Override + public boolean isClosed() { + return closeable.isClosed(); + } + + @Override + public boolean isClosing() { + return closeable.isClosing(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1e29158b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/SshdThreadFactory.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/threads/SshdThreadFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/SshdThreadFactory.java new file mode 100644 index 0000000..5dc0c7b --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/SshdThreadFactory.java @@ -0,0 +1,78 @@ +/* + * 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.threads; + +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.sshd.common.util.logging.AbstractLoggingBean; + +/** + * Default {@link ThreadFactory} used by {@link ThreadUtils} to create + * thread pools if user did provide one + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class SshdThreadFactory extends AbstractLoggingBean implements ThreadFactory { + private final ThreadGroup group; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; + + public SshdThreadFactory(String name) { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); + String effectiveName = name.replace(' ', '-'); + namePrefix = "sshd-" + effectiveName + "-thread-"; + } + + @Override + public Thread newThread(Runnable r) { + Thread t; + try { + // see SSHD-668 + if (System.getSecurityManager() != null) { + t = AccessController.doPrivileged((PrivilegedExceptionAction<Thread>) () -> + new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0)); + } else { + t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); + } + } catch (PrivilegedActionException e) { + Exception err = e.getException(); + if (err instanceof RuntimeException) { + throw (RuntimeException) err; + } else { + throw new RuntimeException(err); + } + } + + if (!t.isDaemon()) { + t.setDaemon(true); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + if (log.isTraceEnabled()) { + log.trace("newThread({})[{}] runnable={}", group, t.getName(), r); + } + return t; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1e29158b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java index f09237e..c803389 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java @@ -18,36 +18,14 @@ */ package org.apache.sshd.common.util.threads; -import java.io.IOException; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashSet; -import java.util.List; import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; - -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.ValidateUtils; -import org.apache.sshd.common.util.closeable.AbstractCloseable; -import org.apache.sshd.common.util.logging.AbstractLoggingBean; /** * Utility class for thread pools. @@ -176,7 +154,7 @@ public final class ThreadUtils { } public static CloseableExecutorService newFixedThreadPool(String poolName, int nThreads) { - return new ThreadPoolExecutor( + return new SshThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, // TODO make this configurable new LinkedBlockingQueue<>(), @@ -189,7 +167,7 @@ public final class ThreadUtils { } public static CloseableExecutorService newCachedThreadPool(String poolName) { - return new ThreadPoolExecutor( + return new SshThreadPoolExecutor( 0, Integer.MAX_VALUE, // TODO make this configurable 60L, TimeUnit.SECONDS, // TODO make this configurable new SynchronousQueue<>(), @@ -204,270 +182,4 @@ public final class ThreadUtils { public static CloseableExecutorService newSingleThreadExecutor(String poolName) { return newFixedThreadPool(poolName, 1); } - - public static class SshdThreadFactory extends AbstractLoggingBean implements ThreadFactory { - private final ThreadGroup group; - private final AtomicInteger threadNumber = new AtomicInteger(1); - private final String namePrefix; - - public SshdThreadFactory(String name) { - SecurityManager s = System.getSecurityManager(); - group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); - String effectiveName = name.replace(' ', '-'); - namePrefix = "sshd-" + effectiveName + "-thread-"; - } - - @Override - public Thread newThread(final Runnable r) { - Thread t; - try { - // see SSHD-668 - if (System.getSecurityManager() != null) { - t = AccessController.doPrivileged((PrivilegedExceptionAction<Thread>) () -> - new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0)); - } else { - t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); - } - } catch (PrivilegedActionException e) { - Exception err = e.getException(); - if (err instanceof RuntimeException) { - throw (RuntimeException) err; - } else { - throw new RuntimeException(err); - } - } - - if (!t.isDaemon()) { - t.setDaemon(true); - } - if (t.getPriority() != Thread.NORM_PRIORITY) { - t.setPriority(Thread.NORM_PRIORITY); - } - if (log.isTraceEnabled()) { - log.trace("newThread({})[{}] runnable={}", group, t.getName(), r); - } - return t; - } - } - - public static class NoCloseExecutor implements CloseableExecutorService { - protected final ExecutorService executor; - protected final CloseFuture closeFuture; - - public NoCloseExecutor(ExecutorService executor) { - this.executor = executor; - closeFuture = new DefaultCloseFuture(null, null); - } - - @Override - public <T> Future<T> submit(Callable<T> task) { - ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); - return executor.submit(task); - } - - @Override - public <T> Future<T> submit(Runnable task, T result) { - ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); - return executor.submit(task, result); - } - - @Override - public Future<?> submit(Runnable task) { - ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); - return executor.submit(task); - } - - @Override - public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { - ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); - return executor.invokeAll(tasks); - } - - @Override - public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { - ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); - return executor.invokeAll(tasks, timeout, unit); - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { - ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); - return executor.invokeAny(tasks); - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); - return executor.invokeAny(tasks, timeout, unit); - } - - @Override - public void execute(Runnable command) { - ValidateUtils.checkState(!isShutdown(), "Executor has been shut down"); - executor.execute(command); - } - - @Override - public void shutdown() { - close(true); - } - - @Override - public List<Runnable> shutdownNow() { - close(true); - return Collections.emptyList(); - } - - @Override - public boolean isShutdown() { - return isClosed(); - } - - @Override - public boolean isTerminated() { - return isClosed(); - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - try { - return closeFuture.await(timeout, unit); - } catch (IOException e) { - throw (InterruptedException) new InterruptedException().initCause(e); - } - } - - @Override - public CloseFuture close(boolean immediately) { - closeFuture.setClosed(); - return closeFuture; - } - - @Override - public void addCloseFutureListener(SshFutureListener<CloseFuture> listener) { - closeFuture.addListener(listener); - } - - @Override - public void removeCloseFutureListener(SshFutureListener<CloseFuture> listener) { - closeFuture.removeListener(listener); - } - - @Override - public boolean isClosed() { - return closeFuture.isClosed(); - } - - @Override - public boolean isClosing() { - return isClosed(); - } - - } - - public static class ThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements CloseableExecutorService { - - final DelegateCloseable closeable = new DelegateCloseable(); - - class DelegateCloseable extends AbstractCloseable { - DelegateCloseable() { - } - - @Override - protected CloseFuture doCloseGracefully() { - shutdown(); - return closeFuture; - } - - @Override - protected void doCloseImmediately() { - shutdownNow(); - super.doCloseImmediately(); - } - - void setClosed() { - closeFuture.setClosed(); - } - } - - public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); - } - - public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); - } - - public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); - } - - public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, - long keepAliveTime, TimeUnit unit, - BlockingQueue<Runnable> workQueue, - ThreadFactory threadFactory, - RejectedExecutionHandler handler) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); - } - - @Override - protected void terminated() { - closeable.doCloseImmediately(); - } - - @Override - public void shutdown() { - super.shutdown(); - } - - @Override - public List<Runnable> shutdownNow() { - return super.shutdownNow(); - } - - @Override - public boolean isShutdown() { - return super.isShutdown(); - } - - @Override - public boolean isTerminating() { - return super.isTerminating(); - } - - @Override - public boolean isTerminated() { - return super.isTerminated(); - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - return super.awaitTermination(timeout, unit); - } - - @Override - public CloseFuture close(boolean immediately) { - return closeable.close(immediately); - } - - @Override - public void addCloseFutureListener(SshFutureListener<CloseFuture> listener) { - closeable.addCloseFutureListener(listener); - } - - @Override - public void removeCloseFutureListener(SshFutureListener<CloseFuture> listener) { - closeable.removeCloseFutureListener(listener); - } - - @Override - public boolean isClosed() { - return closeable.isClosed(); - } - - @Override - public boolean isClosing() { - return closeable.isClosing(); - } - } }
