package org.v8LogScanner.rgx; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Reader; import java.nio.CharBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RgxReader implements AutoCloseable { // The main pattern using to find event blocks in the log file. private final String EVENT_RGX = ".+?(?=\\d{2}:\\d{2}\\.\\d{6})"; //The index into the buffer currently held by the Reader private int position; // The buffer which the reader read in. private CharBuffer buf; // Channel input reader using to read a text from // log files into the buffer. private Reader reader = null; // Stream supply a channel which reader used FileInputStream fs = null; private Pattern pattern; private Matcher matcher; //When is using next() need to control reading state of the buffer private boolean needInput = false; // The remaining input converted to string from the buffer. // It needs as the pattern cannot matches last event from a file. private String remaining = ""; private int limit; //The filtered logs content returned by RgxReader. private ArrayList<String> result; public RgxReader(String fileName, Charset charset, int _limit) throws FileNotFoundException { this(CharBuffer.allocate(1024)); fs = new FileInputStream(fileName); ReadableByteChannel channel = fs.getChannel(); CharsetDecoder decoder = charset.newDecoder(); reader = Channels.newReader(channel, decoder, -1); buf.limit(0); limit = _limit; } public RgxReader(CharBuffer source) { pattern = Pattern.compile(EVENT_RGX, Pattern.DOTALL); buf = source; matcher = pattern.matcher(buf); buf.position(position); matcher.useTransparentBounds(true); matcher.useAnchoringBounds(false); result = new ArrayList<>(limit); } public boolean next() throws IOException { if (reader == null) throw new IncorrectReaderMethod(); result.clear(); int n = 0; while (true) { if (!needInput) readFromBuffer(limit); if (result.size() >= limit) return true; if (needInput) { // make space if (buf.limit() == buf.capacity()) { makeSpace(); } // read input int p = buf.position(); buf.position(buf.limit()); buf.limit(buf.capacity()); n = reader.read(buf); if (n == -1 && !remaining.isEmpty()) { result.add(remaining.trim()); remaining = ""; return true; } else if (n == -1 && remaining.isEmpty()) return false; // Restore current position and limit for reading buf.limit(buf.position()); buf.position(p); position = buf.position(); needInput = false; } } } public void readFromBuffer(int limit) throws IOException { matcher.region(position, buf.limit()); while (matcher.lookingAt()) { String s = matcher.group(); //!! bad fix *+ matching empty string if (s.length() > 1) result.add(s.trim()); position = matcher.end(); if (limit > 0 && result.size() >= limit) { needInput = false; return; } matcher.region(position, buf.limit()); } if (buf.hasRemaining() && buf.limit() > position && position >= 0) { buf.position(position); remaining = buf.toString(); buf.position(buf.limit()); } needInput = true; } private void makeSpace() { int offset = position; buf.position(offset); // Gain space by compacting buffer if (offset > 0) { buf.compact(); position -= offset; buf.flip(); return; } // Gain space by growing buffer int newSize = buf.capacity() * 2; CharBuffer newBuf = CharBuffer.allocate(newSize); newBuf.put(buf); newBuf.flip(); position -= offset; buf = newBuf; matcher.reset(buf); } public ArrayList<String> getResult() { return result; } public void close() throws IOException { fs.close(); reader.close(); } } class IncorrectReaderMethod extends IOException { private static final long serialVersionUID = -6768497416328793322L; public IncorrectReaderMethod() { super("Incorrect method has been chosen." + " You need to use \"readFromBuffer()\" instead"); } }