me.melchor9000.net.NettyFuture.java Source code

Java tutorial

Introduction

Here is the source code for me.melchor9000.net.NettyFuture.java

Source

/*
async-net: A basic asynchronous network library, based on netty
Copyright (C) 2016  melchor629 (melchor9000@gmail.com)
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package me.melchor9000.net;

import io.netty.util.concurrent.GenericFutureListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * About the result of an asynchronous task, hidding the Netty implementation
 */
class NettyFuture<ReturnType> implements Future<ReturnType> {
    private final io.netty.util.concurrent.Future<ReturnType> future;
    private final IOService service;
    private final Procedure whenCancelled;
    private Future<?> timeoutFuture;

    NettyFuture(@NotNull io.netty.util.concurrent.Future<ReturnType> future, @NotNull IOService service,
            @Nullable Procedure whenCancelled) {
        this.future = future;
        this.service = service;
        this.whenCancelled = whenCancelled;
        future.addListener(new GenericFutureListener<io.netty.util.concurrent.Future<? super ReturnType>>() {
            @Override
            public void operationComplete(io.netty.util.concurrent.Future<? super ReturnType> future)
                    throws Exception {
                if (timeoutFuture != null)
                    timeoutFuture.cancel(false);
            }
        });
    }

    NettyFuture(@NotNull io.netty.util.concurrent.Future<ReturnType> future, @NotNull IOService service) {
        this(future, service, null);
    }

    public boolean isDone() {
        return future.isDone();
    }

    public boolean isSuccessful() {
        return future.isSuccess();
    }

    public boolean isCancelled() {
        return future.isCancelled();
    }

    @Override
    public boolean isCancelable() {
        return future.isCancellable();
    }

    public void cancel(boolean mayInterrupt) {
        future.cancel(mayInterrupt);
    }

    @NotNull
    public Future<ReturnType> whenDone(@NotNull final Callback<Future<ReturnType>> cbk) {
        future.addListener(new GenericFutureListener<io.netty.util.concurrent.Future<? super ReturnType>>() {
            @Override
            public void operationComplete(io.netty.util.concurrent.Future<? super ReturnType> future)
                    throws Exception {
                try {
                    cbk.call(NettyFuture.this);
                } catch (Exception exception) {
                    throw exception;
                } catch (Throwable throwable) {
                    System.err.println("Caught a Throwable in " + cbk.getClass().getName() + ".call()");
                    throwable.printStackTrace();
                }
            }
        });
        return this;
    }

    @NotNull
    @Override
    public Future<ReturnType> setTimeout(long milliseconds) {
        if (milliseconds <= 0)
            throw new IllegalArgumentException("Only positive non 0 values are accepted");
        if (isDone())
            throw new IllegalStateException("The task is done");
        if (!isCancelable())
            throw new IllegalStateException("The task is not cancellable");
        if (timeoutFuture != null)
            timeoutFuture.cancel(false);
        timeoutFuture = service.schedule(new Procedure() {
            @Override
            public void call() {
                if (!isDone()) {
                    if (whenCancelled != null)
                        whenCancelled.call();
                    cancel(true);
                }
            }
        }, milliseconds);
        return this;
    }

    public ReturnType getValueNow() {
        return future.getNow();
    }

    public Throwable cause() {
        return future.cause();
    }

    public ReturnType getValue(long millis) throws InterruptedException, ExecutionException, TimeoutException {
        return future.get(millis, TimeUnit.MILLISECONDS);
    }

    public ReturnType getValueUninterrumptibly(long millis) throws ExecutionException, TimeoutException {
        ReturnType ret = null;
        long currentMillis = System.currentTimeMillis();
        while (!isDone()) {
            try {
                ret = getValue(millis);
            } catch (InterruptedException ignore) {
                millis -= System.currentTimeMillis() - currentMillis;
            }
        }
        return ret;
    }

    public ReturnType getValue() throws ExecutionException, InterruptedException {
        return future.get();
    }

    public ReturnType getValueUninterrumptibly() throws ExecutionException, InterruptedException {
        ReturnType ret = null;
        while (!isDone()) {
            try {
                ret = getValue();
            } catch (InterruptedException ignore) {
            }
        }
        return ret;
    }

    @NotNull
    public Future<ReturnType> sync() {
        future.syncUninterruptibly();
        return this;
    }
}