reactor.ipc.netty.NettyOutbound.java Source code

Java tutorial

Introduction

Here is the source code for reactor.ipc.netty.NettyOutbound.java

Source

/*
 * Copyright (c) 2011-2016 Pivotal Software Inc, All Rights Reserved.
 *
 * Licensed 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 reactor.ipc.netty;

import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Objects;
import java.util.function.Consumer;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.DefaultFileRegion;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.ipc.connector.Outbound;

/**
 * @author Stephane Maldini
 */
public interface NettyOutbound extends Outbound<ByteBuf>, Publisher<Void> {

    /**
     * Return the assigned {@link ByteBufAllocator}.
     *
     * @return the {@link ByteBufAllocator}
     */
    default ByteBufAllocator alloc() {
        return context().channel().alloc();
    }

    /**
     * Provide a new {@link NettyOutbound} scoped configuration for sending. The
     * {@link NettyPipeline.SendOptions} changes will apply to the next written object or
     * {@link Publisher}.
     *
     * @param configurator the callback invoked to retrieve send configuration
     *
     * @return {@code this} instance
     */
    default NettyOutbound options(Consumer<? super NettyPipeline.SendOptions> configurator) {
        context().channel().pipeline()
                .fireUserEventTriggered(new NettyPipeline.SendOptionsChangeEvent(configurator, null));
        return this;
    }

    /**
     * Return a {@link NettyContext} to operate on the underlying
     * {@link Channel} state.
     *
     * @return the {@link NettyContext}
     */
    NettyContext context();

    /**
     * Assign a {@link Runnable} to be invoked when writes have become idle for the given
     * timeout.
     *
     * @param idleTimeout the idle timeout
     * @param onWriteIdle the idle timeout handler
     *
     * @return {@literal this}
     */
    default NettyOutbound onWriteIdle(long idleTimeout, Runnable onWriteIdle) {
        context().addHandler(NettyPipeline.OnChannelWriteIdle,
                new ReactorNetty.OutboundIdleStateHandler(idleTimeout, onWriteIdle));
        return this;
    }

    @Override
    default NettyOutbound send(Publisher<? extends ByteBuf> dataStream) {
        return sendObject(dataStream);
    }

    /**
     * /** Send bytes to the peer, listen for any error on write and close on terminal
     * signal (complete|error). If more than one publisher is attached (multiple calls to
     * send()) completion occurs after all publishers complete.
     *
     * @param dataStream the dataStream publishing Buffer items to write on this channel
     *
     * @return A Publisher to signal successful sequence write (e.g. after "flush") or any
     * error during write
     */
    default NettyOutbound sendByteArray(Publisher<? extends byte[]> dataStream) {
        return sendObject(Flux.from(dataStream).map(Unpooled::wrappedBuffer));
    }

    /**
     * Send content from given {@link Path} using
     * {@link java.nio.channels.FileChannel#transferTo(long, long, WritableByteChannel)}
     * support. If the system supports it and the path resolves to a local file
     * system {@link File} then transfer will use zero-byte copy
     * to the peer.
     * <p>It will
     * listen for any error on
     * write and close
     * on terminal signal (complete|error). If more than one publisher is attached
     * (multiple calls to send()) completion occurs after all publishers complete.
     * <p>
     * Note: this will emit {@link io.netty.channel.FileRegion} in the outbound
     * {@link io.netty.channel.ChannelPipeline}
     *
     * @param file the file Path
     *
     * @return A Publisher to signal successful sequence write (e.g. after "flush") or any
     * error during write
     */
    default NettyOutbound sendFile(Path file) {
        try {
            return sendFile(file, 0L, Files.size(file));
        } catch (IOException e) {
            return then(Mono.error(e));
        }
    }

    /**
     * Send content from given {@link Path} using
     * {@link java.nio.channels.FileChannel#transferTo(long, long, WritableByteChannel)}
     * support. If the system supports it and the path resolves to a local file
     * system {@link File} then transfer will use zero-byte copy
     * to the peer.
     * <p>It will
     * listen for any error on
     * write and close
     * on terminal signal (complete|error). If more than one publisher is attached
     * (multiple calls to send()) completion occurs after all publishers complete.
     * <p>
     * Note: this will emit {@link io.netty.channel.FileRegion} in the outbound
     * {@link io.netty.channel.ChannelPipeline}
     *
     * @param file the file Path
     * @param position where to start
     * @param count how much to transfer
     *
     * @return A Publisher to signal successful sequence write (e.g. after "flush") or any
     * error during write
     */
    default NettyOutbound sendFile(Path file, long position, long count) {
        Objects.requireNonNull(file);
        return then(Mono.using(() -> FileChannel.open(file, StandardOpenOption.READ),
                fc -> FutureMono
                        .from(context().channel().writeAndFlush(new DefaultFileRegion(fc, position, count))),
                fc -> {
                    try {
                        fc.close();
                    } catch (IOException ioe) {
                        /*IGNORE*/}
                }));
    }

    /**
     * Send data to the peer, listen for any error on write and close on terminal signal
     * (complete|error).Each individual {@link Publisher} completion will flush
     * the underlying IO runtime.
     *
     * @param dataStreams the dataStream publishing OUT items to write on this channel
     *
     * @return A {@link Mono} to signal successful sequence write (e.g. after "flush") or
     * any error during write
     */
    default NettyOutbound sendGroups(Publisher<? extends Publisher<? extends ByteBuf>> dataStreams) {
        return then(Flux.from(dataStreams).concatMapDelayError(this::send, false, 32).then());
    }

    /**
     * Send Object to the peer, listen for any error on write and close on terminal signal
     * (complete|error). If more than one publisher is attached (multiple calls to send())
     * completion occurs after all publishers complete.
     *
     * @param dataStream the dataStream publishing Buffer items to write on this channel
     *
     * @return A Publisher to signal successful sequence write (e.g. after "flush") or any
     * error during write
     */
    default NettyOutbound sendObject(Publisher<?> dataStream) {
        return then(FutureMono.deferFuture(() -> context().channel().writeAndFlush(dataStream)));
    }

    /**
     * Send data to the peer, listen for any error on write and close on terminal signal
     * (complete|error).
     *
     * @param msg the object to publish
     *
     * @return A {@link Mono} to signal successful sequence write (e.g. after "flush") or
     * any error during write
     */
    default NettyOutbound sendObject(Object msg) {
        return then(FutureMono.deferFuture(() -> context().channel().writeAndFlush(msg)));
    }

    /**
     * Send String to the peer, listen for any error on write and close on terminal signal
     * (complete|error). If more than one publisher is attached (multiple calls to send())
     * completion occurs after all publishers complete.
     *
     * @param dataStream the dataStream publishing Buffer items to write on this channel
     *
     * @return A Publisher to signal successful sequence write (e.g. after "flush") or any
     * error during write
     */
    default NettyOutbound sendString(Publisher<? extends String> dataStream) {
        return sendString(dataStream, Charset.defaultCharset());
    }

    /**
     * Send String to the peer, listen for any error on write and close on terminal signal
     * (complete|error). If more than one publisher is attached (multiple calls to send())
     * completion occurs after all publishers complete.
     *
     * @param dataStream the dataStream publishing Buffer items to write on this channel
     * @param charset the encoding charset
     *
     * @return A Publisher to signal successful sequence write (e.g. after "flush") or any
     * error during write
     */
    default NettyOutbound sendString(Publisher<? extends String> dataStream, Charset charset) {
        return sendObject(Flux.from(dataStream).map(s -> alloc().buffer().writeBytes(s.getBytes(charset))));
    }

    /**
     * Subscribe a {@code Void} subscriber to this outbound and trigger all eventual
     * parent outbound send.
     *
     * @param s the {@link Subscriber} to listen for send sequence completion/failure
     */
    @Override
    default void subscribe(Subscriber<? super Void> s) {
        then().subscribe(s);
    }

    /**
     * Append a {@link Publisher} task such as a Mono and return a new
     * {@link NettyOutbound} to sequence further send.
     *
     * @param other the {@link Publisher} to subscribe to when this pending outbound
     * {@link #then()} is complete;
     *
     * @return a new {@link NettyOutbound} that
     */
    @Override
    default NettyOutbound then(Publisher<Void> other) {
        return new ReactorNetty.OutboundThen(this, other);
    }

}