1c4679defSVladimir Kotal /* 2c4679defSVladimir Kotal * CDDL HEADER START 3c4679defSVladimir Kotal * 4c4679defSVladimir Kotal * The contents of this file are subject to the terms of the 5c4679defSVladimir Kotal * Common Development and Distribution License (the "License"). 6c4679defSVladimir Kotal * You may not use this file except in compliance with the License. 7c4679defSVladimir Kotal * 8c4679defSVladimir Kotal * See LICENSE.txt included in this distribution for the specific 9c4679defSVladimir Kotal * language governing permissions and limitations under the License. 10c4679defSVladimir Kotal * 11c4679defSVladimir Kotal * When distributing Covered Code, include this CDDL HEADER in each 12c4679defSVladimir Kotal * file and include the License file at LICENSE.txt. 13c4679defSVladimir Kotal * If applicable, add the following below this CDDL HEADER, with the 14c4679defSVladimir Kotal * fields enclosed by brackets "[]" replaced with your own identifying 15c4679defSVladimir Kotal * information: Portions Copyright [yyyy] [name of copyright owner] 16c4679defSVladimir Kotal * 17c4679defSVladimir Kotal * CDDL HEADER END 18c4679defSVladimir Kotal */ 19c4679defSVladimir Kotal 20c4679defSVladimir Kotal /* 21*5d9f3aa0SAdam Hornáček * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 22c4679defSVladimir Kotal */ 23c4679defSVladimir Kotal package org.opengrok.indexer.util; 24c4679defSVladimir Kotal 25c4679defSVladimir Kotal import java.io.BufferedInputStream; 26c4679defSVladimir Kotal import java.io.BufferedReader; 27c4679defSVladimir Kotal import java.io.IOException; 28c4679defSVladimir Kotal import java.io.InputStream; 29c4679defSVladimir Kotal import java.io.InputStreamReader; 30c4679defSVladimir Kotal import java.nio.charset.Charset; 31c4679defSVladimir Kotal import java.nio.charset.StandardCharsets; 32c4679defSVladimir Kotal import java.util.ArrayList; 33c4679defSVladimir Kotal import java.util.List; 34c4679defSVladimir Kotal 35c4679defSVladimir Kotal /** 36c4679defSVladimir Kotal * The purpose of this class is to provide {@code StreamHandler} that limits the output 37c4679defSVladimir Kotal * to specified number of lines. Compared to {@code SpoolHandler} it consumes 38c4679defSVladimir Kotal * limited amount of heap. 39c4679defSVladimir Kotal */ 40c4679defSVladimir Kotal public class HeadHandler implements Executor.StreamHandler { 41c4679defSVladimir Kotal private final int maxLines; 42c4679defSVladimir Kotal 43c4679defSVladimir Kotal private final List<String> lines = new ArrayList<>(); 44c4679defSVladimir Kotal private final Charset charset; 45c4679defSVladimir Kotal 46c4679defSVladimir Kotal private static final int bufferedReaderSize = 200; 47c4679defSVladimir Kotal 48c4679defSVladimir Kotal /** 49c4679defSVladimir Kotal * Charset of the underlying reader is set to UTF-8. 50c4679defSVladimir Kotal * @param maxLines maximum number of lines to store 51c4679defSVladimir Kotal */ HeadHandler(int maxLines)52c4679defSVladimir Kotal public HeadHandler(int maxLines) { 53c4679defSVladimir Kotal this.maxLines = maxLines; 54c4679defSVladimir Kotal this.charset = StandardCharsets.UTF_8; 55c4679defSVladimir Kotal } 56c4679defSVladimir Kotal 57c4679defSVladimir Kotal /** 58c4679defSVladimir Kotal * @param maxLines maximum number of lines to store 59c4679defSVladimir Kotal * @param charset character set 60c4679defSVladimir Kotal */ HeadHandler(int maxLines, Charset charset)61c4679defSVladimir Kotal public HeadHandler(int maxLines, Charset charset) { 62c4679defSVladimir Kotal this.maxLines = maxLines; 63c4679defSVladimir Kotal this.charset = charset; 64c4679defSVladimir Kotal } 65c4679defSVladimir Kotal 66c4679defSVladimir Kotal /** 67c4679defSVladimir Kotal * @return number of lines read 68c4679defSVladimir Kotal */ count()69c4679defSVladimir Kotal public int count() { 70c4679defSVladimir Kotal return lines.size(); 71c4679defSVladimir Kotal } 72c4679defSVladimir Kotal 73c4679defSVladimir Kotal /** 74c4679defSVladimir Kotal * @param index index 75c4679defSVladimir Kotal * @return line at given index. Will be non {@code null} for valid index. 76c4679defSVladimir Kotal */ get(int index)77c4679defSVladimir Kotal public String get(int index) { 78c4679defSVladimir Kotal return lines.get(index); 79c4679defSVladimir Kotal } 80c4679defSVladimir Kotal 81c4679defSVladimir Kotal // for testing getBufferedReaderSize()82c4679defSVladimir Kotal static int getBufferedReaderSize() { 83c4679defSVladimir Kotal return bufferedReaderSize; 84c4679defSVladimir Kotal } 85c4679defSVladimir Kotal 86c4679defSVladimir Kotal @Override processStream(InputStream input)87c4679defSVladimir Kotal public void processStream(InputStream input) throws IOException { 88c4679defSVladimir Kotal try (BufferedInputStream bufStream = new BufferedInputStream(input); 89c4679defSVladimir Kotal BufferedReader reader = new BufferedReader(new InputStreamReader(bufStream, this.charset), 90c4679defSVladimir Kotal bufferedReaderSize)) { 91c4679defSVladimir Kotal int lineNum = 0; 92c4679defSVladimir Kotal while (lineNum < maxLines) { 93c4679defSVladimir Kotal String line = reader.readLine(); 94c4679defSVladimir Kotal if (line == null) { // EOF 95c4679defSVladimir Kotal return; 96c4679defSVladimir Kotal } 97c4679defSVladimir Kotal lines.add(line); 98c4679defSVladimir Kotal lineNum++; 99c4679defSVladimir Kotal } 100c4679defSVladimir Kotal 101c4679defSVladimir Kotal // Read and forget the rest. 102c4679defSVladimir Kotal byte[] buf = new byte[1024]; 103c4679defSVladimir Kotal while ((bufStream.read(buf)) != -1) { 104c4679defSVladimir Kotal ; 105c4679defSVladimir Kotal } 106c4679defSVladimir Kotal } 107c4679defSVladimir Kotal } 108c4679defSVladimir Kotal } 109