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.OutputStream; 010import java.io.OutputStreamWriter; 011import java.io.PrintWriter; 012import java.nio.charset.StandardCharsets; 013import java.text.NumberFormat; 014import java.util.Locale; 015 016/** 017 * {@link ModuleSloc} オブジェクトのストリームを人が読みやすいレポート形式に整形するコマンド。 018 * 019 * <p>入力: {@link SlocAggregateCommand} が出力する {@link java.io.ObjectOutputStream} ストリーム (各モジュールの 020 * {@link ModuleSloc} + name="Total" の合計行) 021 * 022 * <p><b>セキュリティ前提:</b> 入力ストリームは同一 JVM 内の前段コマンド({@link SlocAggregateCommand})が 023 * 書き出したものであり、外部入力を直接受け取らない。予期しない型が含まれる場合は {@link ClassNotFoundException} / {@link 024 * ClassCastException} を {@link java.io.IOException} に変換して伝播する。 025 * 026 * <p>出力例: 027 * 028 * <pre> 029 * === SLOC Report === 030 * 031 * streamconverter-core 1,869 032 * streamconverter-db 349 033 * streamconverter-http 92 034 * streamconverter-tools 1,038 035 * streamconverter-web 79 036 * ─────────────────────────────── 037 * Total 3,427 038 * </pre> 039 */ 040public class SlocReportFormatCommand extends AbstractStreamCommand { 041 042 private static final int MODULE_COL_WIDTH = 25; 043 private static final int LINES_COL_WIDTH = 6; 044 045 @Override 046 public void execute(InputStream input, OutputStream output) throws IOException { 047 String separator = " " + "─".repeat(MODULE_COL_WIDTH + LINES_COL_WIDTH + 1); 048 NumberFormat numberFormat = NumberFormat.getInstance(Locale.US); 049 050 try (ObjectInputStream ois = new ObjectInputStream(input); 051 PrintWriter writer = 052 new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8))) { 053 writer.println("=== SLOC Report ==="); 054 writer.println(); 055 while (true) { 056 try { 057 ModuleSloc sloc = (ModuleSloc) ois.readObject(); 058 if (ModuleSloc.TOTAL_NAME.equals(sloc.name())) { 059 writer.println(separator); 060 } 061 writer.printf( 062 " %-" + MODULE_COL_WIDTH + "s %" + LINES_COL_WIDTH + "s%n", 063 sloc.name(), 064 numberFormat.format(sloc.lines())); 065 } catch (EOFException e) { 066 break; 067 } catch (ClassNotFoundException | ClassCastException e) { 068 throw new IOException("Unexpected object type in stream: expected ModuleSloc", e); 069 } 070 } 071 } 072 } 073}