All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sshd.common.util.closeable.AbstractCloseable Maven / Gradle / Ivy

There is a newer version: 2.14.0
Show newest version
/*
 * 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.closeable;

import java.util.concurrent.atomic.AtomicReference;

import org.apache.sshd.common.future.CloseFuture;
import org.apache.sshd.common.future.DefaultCloseFuture;
import org.apache.sshd.common.future.SshFuture;
import org.apache.sshd.common.future.SshFutureListener;

/**
 * Provides some default implementations for managing channel/connection open/close state
 *
 * @author Apache MINA SSHD Project
 */
public abstract class AbstractCloseable extends IoBaseCloseable {

    public enum State {
        /** Connection is open */
        Opened,
        /** Connection is being closed gracefully */
        Graceful,
        /** Connection is being terminated immediately */
        Immediate,
        /** Connection is closed */
        Closed,
        /* end */;
    }

    /**
     * Lock object for {@code Future}-s based on this closeable instance
     */
    protected final Object futureLock = new Object();

    /**
     * State of this object
     */
    protected final AtomicReference state = new AtomicReference<>(State.Opened);

    /**
     * A future that will be set 'closed' when the object is actually closed
     */
    protected final CloseFuture closeFuture;

    protected AbstractCloseable() {
        this("");
    }

    protected AbstractCloseable(String discriminator) {
        super(discriminator);
        closeFuture = new DefaultCloseFuture(discriminator, futureLock);
    }

    public Object getFutureLock() {
        return futureLock;
    }

    @Override
    public void addCloseFutureListener(SshFutureListener listener) {
        closeFuture.addListener(listener);
    }

    @Override
    public void removeCloseFutureListener(SshFutureListener listener) {
        closeFuture.removeListener(listener);
    }

    @Override
    public final CloseFuture close(boolean immediately) {
        boolean debugEnabled = log.isDebugEnabled();
        if (immediately) {
            if (state.compareAndSet(State.Opened, State.Immediate)
                    || state.compareAndSet(State.Graceful, State.Immediate)) {
                if (debugEnabled) {
                    log.debug("close({}) Closing immediately", this);
                }
                preClose();
                doCloseImmediately();
                if (debugEnabled) {
                    log.debug("close({})[Immediately] closed", this);
                }
            } else {
                if (debugEnabled) {
                    log.debug("close({})[Immediately] state already {}", this, state);
                }
            }
        } else {
            if (state.compareAndSet(State.Opened, State.Graceful)) {
                if (debugEnabled) {
                    log.debug("close({}) Closing gracefully", this);
                }
                preClose();
                SshFuture grace = doCloseGracefully();
                if (grace != null) {
                    grace.addListener(future -> {
                        if (state.compareAndSet(State.Graceful, State.Immediate)) {
                            doCloseImmediately();
                            if (debugEnabled) {
                                log.debug("close({}][Graceful] - operationComplete() closed", AbstractCloseable.this);
                            }
                        }
                    });
                } else {
                    if (state.compareAndSet(State.Graceful, State.Immediate)) {
                        doCloseImmediately();
                        if (debugEnabled) {
                            log.debug("close({})[Graceful] closed", this);
                        }
                    }
                }
            } else {
                if (debugEnabled) {
                    log.debug("close({})[Graceful] state already {}", this, state);
                }
            }
        }
        return closeFuture;
    }

    @Override
    public final boolean isClosed() {
        return state.get() == State.Closed;
    }

    @Override
    public final boolean isClosing() {
        return state.get() != State.Opened;
    }

    /**
     * preClose is guaranteed to be called before doCloseGracefully or doCloseImmediately. When preClose() is called,
     * isClosing() == true
     */
    protected void preClose() {
        // nothing
    }

    protected CloseFuture doCloseGracefully() {
        return null;
    }

    /**
     * 

* doCloseImmediately is called once and only once with state == Immediate *

* *

* Overriding methods should always call the base implementation. It may be called concurrently while preClose() or * doCloseGracefully is executing *

*/ protected void doCloseImmediately() { closeFuture.setClosed(); state.set(State.Closed); } protected Builder builder() { return new Builder(futureLock); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy