001package org.unix4j.processor; 002 003import org.unix4j.command.ExitValueException; 004import org.unix4j.io.Input; 005import org.unix4j.line.Line; 006 007import java.util.List; 008 009/** 010 * A line processor for multiple inputs processing the same operation for each 011 * input object individually. An operation here is another {@link LineProcessor} 012 * reading the lines passed to it from the standard input. 013 * <p> 014 * The {@link #processLine(Line)} method does nothing and returns false 015 * indicating that the (standard) input is not read by this processor. The 016 * {@link #finish()} method reads the lines from the {@link Input} object passed 017 * to the constructor and passes them as input to the delegate processor 018 * performing the real work. 019 */ 020public class MultipleInputLineProcessor implements LineProcessor { 021 022 private final List<? extends Input> inputs; 023 private final InputProcessor processor; 024 private final LineProcessor output; 025 private final LineProcessor nonFinishingOutput; 026 027 /** 028 * Constructor with input objects (usually file operands of the command) and 029 * the input processor of the command that reads from the standard input. 030 * 031 * @param inputs 032 * the input devices, usually file operands of the command 033 * @param processor 034 * the operation applied to every input in the given 035 * {@code inputs} list 036 */ 037 public MultipleInputLineProcessor(List<? extends Input> inputs, InputProcessor processor, final LineProcessor output) { 038 this.inputs = inputs; 039 this.processor = processor; 040 this.output = output; 041 this.nonFinishingOutput = new LineProcessor() { 042 @Override 043 public boolean processLine(final Line line) { 044 return output.processLine(line); 045 } 046 047 @Override 048 public void finish() { 049 //ignore, we finish only at the very end of all files 050 } 051 }; 052 } 053 054 @Override 055 public boolean processLine(Line line) { 056 return false;// we want no input, we have it already 057 } 058 059 /** 060 * Performs the following operations to process all {@code Input} objects 061 * that have been passed to the constructor: 062 * <ol> 063 * <li>Calls {@link #beginMultiple(List, LineProcessor) beginMultiple(..)}</li> 064 * <li>Iterates over all input objects in sequence</li> 065 * <li>Calls {@link InputProcessor#begin(Input, LineProcessor)}</li> 066 * <li>Calls {@link InputProcessor#processLine(Input, Line, LineProcessor)} 067 * for every line in the current input</li> 068 * <li>Calls {@link InputProcessor#finish(Input, LineProcessor)}</li> 069 * <li>Calls {@link #finishMultiple(List, LineProcessor) finishMultiple(..)} 070 * </li> 071 * </ol> 072 */ 073 @Override 074 public void finish() { 075 beginMultiple(inputs, output); 076 for (int i = 0; i < inputs.size(); i++) { 077 final Input input = inputs.get(i); 078 try { 079 processor.begin(input, output); 080 for (final Line line : input) { 081 if (!processor.processLine(input, line, output)) { 082 break;// wants no more lines 083 } 084 } 085 processor.finish(input, nonFinishingOutput); 086 } catch (ExitValueException e) { 087 e.setInput(input); 088 throw e; 089 } 090 } 091 finishMultiple(inputs, output); 092 } 093 094 /** 095 * Called once at the beginning before iterating over the {@link Input} 096 * objects in the given {@code inputs} list. 097 * <p> 098 * The DEFAULT implementation performs no operation. 099 * 100 * @param inputs 101 * the input object being iterated next 102 * @param output 103 * the output to write to 104 */ 105 protected void beginMultiple(List<? extends Input> inputs, LineProcessor output) { 106 // default: no op 107 } 108 109 /** 110 * Called once at the end after iterating over the {@link Input} objects in 111 * the given {@code inputs} list. 112 * <p> 113 * The DEFAULT implementation calls {@link LineProcessor#finish() 114 * output.finish()} and closes all input objects. 115 * 116 * @param inputs 117 * the input object being iterated next 118 * @param output 119 * the output to write to 120 */ 121 protected void finishMultiple(List<? extends Input> inputs, LineProcessor output) { 122 output.finish(); 123 for (final Input input : inputs) { 124 input.close(); 125 } 126 } 127 128}