/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2013, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.classic.issue.lbcore224; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Reduce a file consisting of lock and unlock operations by removing matching lock/unlocks. */ public class Reduce { static int NA = -1; enum OperationType {LOCK, UNLOCK} public static void main(String[] args) throws IOException { File inputFile = new File(args[0]); if(!inputFile.exists()) { throw new IllegalArgumentException("Missing file ["+args[0]+"]"); } List<String> lines = readFile(inputFile); System.out.println("Lines count=" + lines.size()); List<Structure> structuredLines = structure(lines); List<Structure> reduction = reduce(structuredLines); if (reduction.isEmpty()) { System.out.println("Reduction is EMPTY as it should be."); } else { System.out.println("Non-empty reduction!!! WTF?"); System.out.println(reduction); } } private static List<String> readFile(File inputFile) throws IOException { BufferedReader reader = null; List<String> lines = new ArrayList(); try { reader = new BufferedReader(new FileReader(inputFile)); String line; while ((line = reader.readLine()) != null) { lines.add(line); } } finally { if (reader != null) try { reader.close(); } catch (IOException e) { } } return lines; } private static List<Structure> reduce(List<Structure> structuredLines) { List<Structure> matching = new ArrayList<Structure>(); int lockIndex = 0; while (lockIndex < structuredLines.size()) { lockIndex = findNearestLock(structuredLines, lockIndex); if (lockIndex == NA) break; else { int unlockIndex = findNearestUnlockInSameThread(structuredLines, lockIndex); if (unlockIndex != NA) { matching.add(structuredLines.get(lockIndex)); matching.add(structuredLines.get(unlockIndex)); } lockIndex++; } } System.out.println("matching list size: " + matching.size()); List<Structure> reduction = new ArrayList<Structure>(); for (Structure s : structuredLines) { if (!matching.contains(s)) { reduction.add(s); } } return reduction; } private static int findNearestLock(List<Structure> reduction, int index) { for (int i = index; i < reduction.size(); i++) { Structure s = reduction.get(i); if (s.operationType == OperationType.LOCK) { return i; } } return NA; } private static int findNearestUnlockInSameThread(List<Structure> reduction, int lockIndex) { int firstCandidateIndex = lockIndex+1; Structure lockStructure = reduction.get(lockIndex); for (int i = firstCandidateIndex; i < reduction.size(); i++) { Structure s = reduction.get(i); if (s.operationType == OperationType.UNLOCK && lockStructure.thread.equals(s.thread)) { return i; } } return NA; } static List<Structure> structure(List<String> lines) { List<Structure> structuredLines = new ArrayList(); Pattern p = Pattern.compile("(\\d{2,5})\\ +(.*) (LOCK|UNLOCK)"); for (String line : lines) { Matcher m = p.matcher(line); if (m.matches()) { String relTime = m.group(1); String t = m.group(2); String opStr = m.group(3); Structure structure = buildStructure(relTime, t, opStr); structuredLines.add(structure); } else { System.out.println("NON MATCHING LINE: ["+ line+"]"); } } return structuredLines; } private static Structure buildStructure(String relTime, String t, String opStr) { long r = Long.parseLong(relTime); OperationType operationType; if (opStr.equals("LOCK")) operationType = OperationType.LOCK; else if (opStr.equals("UNLOCK")) { operationType = OperationType.UNLOCK; } else { throw new IllegalArgumentException(opStr + " is not LOCK|UNLOCK"); } return new Structure(r, t, operationType); } static class Structure { long time; String thread; OperationType operationType; Structure(long time, String thread, OperationType operationType) { this.time = time; this.thread = thread; this.operationType = operationType; } @Override public String toString() { return "Structure{" + "time=" + time + ", thread='" + thread + '\'' + ", operationType=" + operationType + '}'; } } }