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

com.github.dm.jrt.Main Maven / Gradle / Ivy

There is a newer version: 5.9.0
Show newest version
package com.github.dm.jrt;

import com.github.dm.jrt.builder.RoutineBuilder;
import com.github.dm.jrt.channel.IOChannel;
import com.github.dm.jrt.channel.InvocationChannel;
import com.github.dm.jrt.channel.OutputChannel;
import com.github.dm.jrt.channel.ResultChannel;
import com.github.dm.jrt.channel.RoutineException;
import com.github.dm.jrt.channel.TemplateOutputConsumer;
import com.github.dm.jrt.core.ByteChannel;
import com.github.dm.jrt.core.ByteChannel.BufferInputStream;
import com.github.dm.jrt.core.ByteChannel.BufferOutputStream;
import com.github.dm.jrt.core.ByteChannel.ByteBuffer;
import com.github.dm.jrt.core.Channels;
import com.github.dm.jrt.core.Channels.Selectable;
import com.github.dm.jrt.core.JRoutine;
import com.github.dm.jrt.function.BiFunction;
import com.github.dm.jrt.function.Consumer;
import com.github.dm.jrt.function.Function;
import com.github.dm.jrt.function.FunctionalRoutine;
import com.github.dm.jrt.function.Functions;
import com.github.dm.jrt.invocation.InvocationException;
import com.github.dm.jrt.invocation.TemplateInvocation;
import com.github.dm.jrt.runner.Runners;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URLConnection;
import java.util.Map;

import static com.github.dm.jrt.function.Functions.onOutput;
import static com.github.dm.jrt.invocation.Invocations.factoryOf;
import static com.github.dm.jrt.util.TimeDuration.seconds;

public class Main {

    private static final int DATA_INDEX = 0;

    private static final int SIGNAL_INDEX = 1;

    public static void main(final String[] args) {

        Functions.builder().buildRoutine().thenParallelMap(new Function() {

            public Integer apply(final String s) {

                return Integer.parseInt(s);
            }
        }).thenParallelMap(new Function() {

            public Integer apply(final Integer integer) {

                return integer * integer;
            }
        }).thenSyncMap(new Function() {

            public SumData apply(final Integer integer) {

                return new SumData(integer, 1);
            }
        }).thenAsyncAccumulate(new BiFunction() {

            public SumData apply(final SumData data1, final SumData data2) {

                return new SumData(data1.sum + data2.sum, data1.count + data2.count);
            }
        }).thenSyncMap(new Function() {

            public Double apply(final SumData sumData) {

                return Math.sqrt((double) sumData.sum / sumData.count);
            }
        }).asyncCall(args).passTo(onOutput(new Consumer() {

            public void accept(final Double rms) {

                System.out.println(rms);
            }
        })).afterMax(seconds(1)).checkComplete();


        final FunctionalRoutine meanRoutine = //
                Functions.builder()
                         .buildRoutine()
                         .thenParallelMap(new Function() {

                             public Integer apply(final String s) {

                                 return Integer.parseInt(s);
                             }
                         })
                         .thenParallelMap(new Function() {

                             public Integer apply(final Integer integer) {

                                 return integer * integer;
                             }
                         })
                         .thenSyncMap(new Function() {

                             public SumData apply(final Integer integer) {

                                 return new SumData(integer, 1);
                             }
                         })
                         .thenAsyncAccumulate(new BiFunction() {

                             public SumData apply(final SumData data1, final SumData data2) {

                                 return new SumData(data1.sum + data2.sum,
                                                    data1.count + data2.count);
                             }
                         })
                         .thenSyncMap(new Function() {

                             public Double apply(final SumData sumData) {

                                 return Math.sqrt((double) sumData.sum / sumData.count);
                             }
                         });

        final Double rms = meanRoutine.asyncCall(args).afterMax(seconds(1)).next();
        System.out.println(rms);


        final String url =
                "https://upload.wikimedia.org/wikipedia/commons/4/4a/Logo_2013_Google.png";
        final File outFile = new File(System.getProperty("java.io.tmpdir"), "test.png");
        final InvocationChannel, Selectable> inChannel =
                JRoutine.on(factoryOf(ReadInvocation.class))
                        .invocations()
                        .withRunner(Runners.poolRunner())
                        .set()
                        .asyncInvoke();
        final IOChannel uriChannel = Channels.select(inChannel, DATA_INDEX);
        final IOChannel signalChannel = Channels.select(inChannel, SIGNAL_INDEX);
        final RoutineBuilder, Selectable> write =
                JRoutine.on(factoryOf(WriteInvocation.class, outFile))
                        .invocations()
                        .withRunner(Runners.poolRunner(1))
                        .set();
        final OutputChannel> result =
                inChannel.result().passTo(write.asyncInvoke()).result();
        final Map> map =
                Channels.select(result, DATA_INDEX, SIGNAL_INDEX);
        map.get(SIGNAL_INDEX).passTo(new TemplateOutputConsumer() {

            @Override
            public void onComplete() {

                signalChannel.close();
            }

            @Override
            public void onOutput(final Object output) {

                System.out.println(output);

                if (output == Signal.CONTINUE) {

                    signalChannel.pass((Signal) output);
                }
            }
        });

        Channels.stream(uriChannel, map.get(DATA_INDEX))
                .pass(URI.create(url))
                .close()
                .afterMax(seconds(30))
                .checkComplete();


        System.exit(0);
    }

    enum Signal {

        CONTINUE,
        SUCCESS
    }

    private static class ReadInvocation
            extends TemplateInvocation, Selectable> {


        private InputStream mInputStream;

        private void continueReading(@NotNull final ResultChannel> result) {

            try {

                BufferOutputStream outputStream = null;

                try {

                    outputStream =
                            ByteChannel.byteChannel().passTo(Channels.select(result, DATA_INDEX));

                    if (outputStream.write(mInputStream) < 0) {

                        result.pass(new Selectable(Signal.SUCCESS, SIGNAL_INDEX));
                    }

                } finally {

                    if (outputStream != null) {

                        outputStream.close();
                    }
                }

            } catch (final IOException e) {

                throw new InvocationException(e);
            }
        }

        @Override
        public void onInput(final Selectable selectable,
                @NotNull final ResultChannel> result) {

            switch (selectable.index) {

                case DATA_INDEX:

                    final URI uri = selectable.data();

                    try {

                        final URLConnection connection = uri.toURL().openConnection();

                        if (connection instanceof HttpURLConnection) {

                            final int code = ((HttpURLConnection) connection).getResponseCode();

                            if ((code < 200) || (code >= 300)) {

                                throw new IOException();
                            }
                        }

                        mInputStream = connection.getInputStream();
                        continueReading(result);

                    } catch (final IOException e) {

                        throw new InvocationException(e);
                    }

                    break;

                case SIGNAL_INDEX:

                    if (selectable.data == Signal.CONTINUE) {

                        continueReading(result);
                    }

                    break;

                default:

                    break;
            }
        }

        @Override
        public void onTerminate() {

            final InputStream inputStream = mInputStream;

            if (inputStream != null) {

                try {

                    inputStream.close();

                } catch (final IOException ignored) {

                }
            }
        }
    }

    private static class SumData {

        private final int count;

        private final int sum;

        private SumData(final int sum, final int count) {

            this.sum = sum;
            this.count = count;
        }
    }

    private static class WriteInvocation
            extends TemplateInvocation, Selectable> {

        private final File mFile;

        private BufferedOutputStream mOutputStream;

        public WriteInvocation(@NotNull final File file) {

            mFile = file;
        }

        @Override
        public void onAbort(@Nullable final RoutineException reason) {

            closeStream();

            if (!mFile.delete()) {

                System.out.println("Cannot delete file: " + mFile);
            }
        }

        @Override
        public void onInitialize() {

            try {

                mOutputStream = new BufferedOutputStream(new FileOutputStream(mFile));

            } catch (final FileNotFoundException e) {

                throw new InvocationException(e);
            }
        }

        private void closeStream() {

            try {

                mOutputStream.close();

            } catch (final IOException e) {

                throw new InvocationException(e);
            }
        }

        @Override
        @SuppressWarnings("StatementWithEmptyBody")
        public void onInput(final Selectable selectable,
                @NotNull final ResultChannel> result) {

            switch (selectable.index) {

                case DATA_INDEX:

                    final ByteBuffer buffer = selectable.data();
                    final BufferInputStream inputStream = ByteChannel.inputStream(buffer);
                    final BufferedOutputStream outputStream = mOutputStream;

                    try {

                        inputStream.readAll(outputStream);
                        result.pass(new Selectable(Signal.CONTINUE, SIGNAL_INDEX));

                    } catch (final IOException e) {

                        throw new InvocationException(e);

                    } finally {

                        inputStream.close();
                    }

                    break;

                case SIGNAL_INDEX:

                    if (selectable.data == Signal.SUCCESS) {

                        closeStream();

                        try {

                            final String path = mFile.getCanonicalPath();
                            result.pass(new Selectable(path, DATA_INDEX))
                                  .pass(new Selectable(Signal.SUCCESS, SIGNAL_INDEX));

                        } catch (final IOException e) {

                            result.abort(e);
                        }
                    }

                    break;

                default:

                    break;
            }
        }
    }
}