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

au.gov.amsa.risky.format.BinaryFixesOnSubscribeWithBackp Maven / Gradle / Ivy

There is a newer version: 0.6.19
Show newest version
package au.gov.amsa.risky.format;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.Queue;
import java.util.zip.GZIPInputStream;

import com.github.davidmoten.util.Optional;

import au.gov.amsa.risky.format.BinaryFixesOnSubscribeWithBackp.State;
import rx.Observable;
import rx.Observer;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.observables.SyncOnSubscribe;

public final class BinaryFixesOnSubscribeWithBackp extends SyncOnSubscribe {

    private final InputStream is;
    private final Optional mmsi;
    private final BinaryFixesFormat format;

    public BinaryFixesOnSubscribeWithBackp(InputStream is, Optional mmsi, BinaryFixesFormat format) {
        this.is = is;
        this.mmsi = mmsi;
        this.format = format;
    }

    public final static class State {
        final InputStream is;
        final Optional mmsi;
        final Queue queue;

        public State(InputStream is, Optional mmsi, Queue queue) {
            this.is = is;
            this.mmsi = mmsi;
            this.queue = queue;
        }

    }

    /**
     * Returns stream of fixes from the given file. If the file name ends in '.gz'
     * then the file is unzipped before being read.
     * 
     * @param file
     * @return fixes stream
     */
    public static Observable from(final File file, BinaryFixesFormat format) {

        Func0 resourceFactory = new Func0() {

            @Override
            public InputStream call() {
                try {
                    if (file.getName().endsWith(".gz"))
                        return new GZIPInputStream(new FileInputStream(file));
                    else
                        return new FileInputStream(file);
                } catch (FileNotFoundException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        };

        Func1> obsFactory = new Func1>() {

            @Override
            public Observable call(InputStream is) {
                Optional mmsi;
                if (format == BinaryFixesFormat.WITH_MMSI)
                    mmsi = Optional.absent();
                else
                    mmsi = Optional.of(BinaryFixesUtil.getMmsi(file));

                return Observable.create(new BinaryFixesOnSubscribeWithBackp(is, mmsi, format));
            }
        };
        Action1 disposeAction = new Action1() {

            @Override
            public void call(InputStream is) {
                try {
                    is.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        return Observable.using(resourceFactory, obsFactory, disposeAction, true);

    }

    @Override
    protected State generateState() {
        return new State(is, mmsi, new LinkedList());
    }

    @Override
    protected State next(State state, Observer observer) {
        int recordSize = BinaryFixes.recordSize(format);
        Fix f = state.queue.poll();
        if (f != null)
            observer.onNext(f);
        else {
            byte[] bytes = new byte[4096 * BinaryFixes.recordSize(format)];
            try {
                int length;
                if ((length = readFully(state.is, bytes)) > 0) {
                    for (int i = 0; i < length; i += recordSize) {
                        ByteBuffer bb = ByteBuffer.wrap(bytes, i, recordSize);
                        final int mmsi;
                        if (state.mmsi.isPresent()) {
                            mmsi = state.mmsi.get();
                        } else {
                            mmsi = bb.getInt();
                        }
                        Fix fix = BinaryFixesUtil.toFix(mmsi, bb);
                        state.queue.add(fix);
                    }
                    observer.onNext(state.queue.remove());
                } else
                    observer.onCompleted();
            } catch (IOException e) {
                observer.onError(e);
            }
        }
        return state;
    }

    private static final int readFully(InputStream in, byte[] bytes) throws IOException {
        int n = 0;
        int len = bytes.length;
        while (n < len) {
            int count = in.read(bytes, n, len - n);
            if (count < 0) {
                if (n == 0)
                    return -1;
                else
                    return n;
            }
            n += count;
        }
        return n;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy