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}