001package com.streamconverter.sloc.command;
002
003import com.streamconverter.command.AbstractStreamCommand;
004import com.streamconverter.sloc.ModuleSloc;
005import java.io.EOFException;
006import java.io.IOException;
007import java.io.InputStream;
008import java.io.ObjectInputStream;
009import java.io.ObjectOutputStream;
010import java.io.OutputStream;
011
012/**
013 * {@link ModuleSloc} オブジェクトのストリームを集約して合計行を追加するコマンド。
014 *
015 * <p>入力: {@link JacocoXmlToModuleSlocCommand} が出力する {@link ObjectOutputStream} ストリーム
016 *
017 * <p>出力: 各 {@link ModuleSloc} + 合計を表す {@link ModuleSloc}("Total", ...) を {@link ObjectOutputStream}
018 * で書き出す
019 *
020 * <p>1件ずつ読みながら即座に書き出し、カウントのみ累積するためモジュール数によらずメモリ使用量は O(1)。
021 *
022 * <p><b>セキュリティ前提:</b> 入力ストリームは同一 JVM 内の前段コマンド({@link
023 * JacocoXmlToModuleSlocCommand})が書き出したものであり、外部入力を直接受け取らない。予期しない型が 含まれる場合は {@link
024 * ClassNotFoundException} / {@link ClassCastException} を {@link java.io.IOException} に変換して伝播する。
025 */
026public class SlocAggregateCommand extends AbstractStreamCommand {
027
028  @Override
029  public void execute(InputStream input, OutputStream output) throws IOException {
030    int totalLines = 0;
031    int totalCovered = 0;
032    int totalMissed = 0;
033
034    try (ObjectInputStream ois = new ObjectInputStream(input);
035        ObjectOutputStream oos = new ObjectOutputStream(output)) {
036      while (true) {
037        try {
038          ModuleSloc sloc = (ModuleSloc) ois.readObject();
039          oos.writeObject(sloc);
040          totalLines += sloc.lines();
041          totalCovered += sloc.covered();
042          totalMissed += sloc.missed();
043        } catch (EOFException e) {
044          break;
045        } catch (ClassNotFoundException | ClassCastException e) {
046          throw new IOException("Unexpected object type in stream: expected ModuleSloc", e);
047        }
048      }
049      oos.writeObject(new ModuleSloc(ModuleSloc.TOTAL_NAME, totalLines, totalCovered, totalMissed));
050    }
051  }
052}