package au.gov.amsa.util.nmea.saver; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import rx.Observable; import rx.Scheduler; import rx.Subscriber; import rx.schedulers.Schedulers; import au.gov.amsa.util.nmea.NmeaUtil; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; public class NmeaSaver { private static Logger log = LoggerFactory.getLogger(NmeaSaver.class); private volatile Subscriber<String> subscriber; private final FileFactory factory; private final Observable<String> source; private final Clock clock; @VisibleForTesting NmeaSaver(Observable<String> nmea, FileFactory factory, Clock clock) { this.source = nmea; this.factory = factory; this.clock = clock; } public NmeaSaver(Observable<String> nmea, FileFactory factory) { this(nmea, factory, new SystemClock()); } public void start() { start(Schedulers.io()); } public void start(Scheduler scheduler) { subscriber = createSubscriber(factory, clock); source.subscribeOn(scheduler).subscribe(subscriber); } public void stop() { if (subscriber != null) subscriber.unsubscribe(); } private static Subscriber<String> createSubscriber(final FileFactory factory, final Clock clock) { return new Subscriber<String>() { Optional<BufferedWriter> current = Optional.absent(); Optional<String> currentKey = Optional.absent(); boolean firstLineInFile = true; @Override public void onCompleted() { log.warn("should not complete"); closeCurrentWriter(); } @Override public void onError(Throwable e) { log.error(e.getMessage(), e); closeCurrentWriter(); } private void closeCurrentWriter() { if (current.isPresent()) try { current.get().close(); } catch (IOException e1) { log.error(e1.getMessage(), e1); } } @Override public void onNext(String line) { try { long now = clock.getTimeMs(); String amendedLine = NmeaUtil.supplementWithTime(line, now); String fileKey = factory.key(amendedLine, now); if (!currentKey.isPresent() || !fileKey.equals(currentKey.get())) { if (current.isPresent()) current.get().close(); File file = factory.file(amendedLine, now); firstLineInFile = !file.exists(); current = Optional.of((new BufferedWriter( new OutputStreamWriter(new FileOutputStream(file, true))))); currentKey = Optional.of(fileKey); } if (!firstLineInFile) current.get().write('\n'); firstLineInFile = false; current.get().write(amendedLine); } catch (IOException e) { log.error(e.getMessage(), e); } catch (RuntimeException e) { // TODO monitor the count of these JIRA ER-2878 // could not parse the message, ignore // log.warn(e.getMessage() + ":" + line, e); } } }; } }