001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.classic.issue.lbcore224; 015 016import java.io.*; 017import java.util.ArrayList; 018import java.util.List; 019import java.util.regex.Matcher; 020import java.util.regex.Pattern; 021 022/** 023 * Reduce a file consisting of lock and unlock operations by removing matching lock/unlocks. 024 */ 025public class Reduce { 026 027 static int NA = -1; 028 029 enum OperationType { 030 LOCK, UNLOCK 031 } 032 033 public static void main(String[] args) throws IOException { 034 File inputFile = new File(args[0]); 035 if (!inputFile.exists()) { 036 throw new IllegalArgumentException("Missing file [" + args[0] + "]"); 037 } 038 List<String> lines = readFile(inputFile); 039 System.out.println("Lines count=" + lines.size()); 040 List<Structure> structuredLines = structure(lines); 041 List<Structure> reduction = reduce(structuredLines); 042 if (reduction.isEmpty()) { 043 System.out.println("Reduction is EMPTY as it should be."); 044 } else { 045 System.out.println("Non-empty reduction!!! WTF?"); 046 System.out.println(reduction); 047 } 048 049 } 050 051 private static List<String> readFile(File inputFile) throws IOException { 052 BufferedReader reader = null; 053 List<String> lines = new ArrayList<>(); 054 try { 055 reader = new BufferedReader(new FileReader(inputFile)); 056 String line; 057 while ((line = reader.readLine()) != null) { 058 lines.add(line); 059 } 060 } finally { 061 if (reader != null) 062 try { 063 reader.close(); 064 } catch (IOException e) { 065 } 066 } 067 return lines; 068 } 069 070 private static List<Structure> reduce(List<Structure> structuredLines) { 071 List<Structure> matching = new ArrayList<>(); 072 int lockIndex = 0; 073 while (lockIndex < structuredLines.size()) { 074 lockIndex = findNearestLock(structuredLines, lockIndex); 075 if (lockIndex == NA) 076 break; 077 else { 078 int unlockIndex = findNearestUnlockInSameThread(structuredLines, lockIndex); 079 if (unlockIndex != NA) { 080 matching.add(structuredLines.get(lockIndex)); 081 matching.add(structuredLines.get(unlockIndex)); 082 } 083 lockIndex++; 084 } 085 } 086 System.out.println("matching list size: " + matching.size()); 087 List<Structure> reduction = new ArrayList<Structure>(); 088 for (Structure s : structuredLines) { 089 if (!matching.contains(s)) { 090 reduction.add(s); 091 } 092 } 093 return reduction; 094 095 } 096 097 private static int findNearestLock(List<Structure> reduction, int index) { 098 for (int i = index; i < reduction.size(); i++) { 099 Structure s = reduction.get(i); 100 if (s.operationType == OperationType.LOCK) { 101 return i; 102 } 103 } 104 return NA; 105 } 106 107 private static int findNearestUnlockInSameThread(List<Structure> reduction, int lockIndex) { 108 int firstCandidateIndex = lockIndex + 1; 109 Structure lockStructure = reduction.get(lockIndex); 110 for (int i = firstCandidateIndex; i < reduction.size(); i++) { 111 Structure s = reduction.get(i); 112 if (s.operationType == OperationType.UNLOCK && lockStructure.thread.equals(s.thread)) { 113 return i; 114 } 115 } 116 return NA; 117 } 118 119 static List<Structure> structure(List<String> lines) { 120 List<Structure> structuredLines = new ArrayList<>(); 121 Pattern p = Pattern.compile("(\\d{2,5})\\ +(.*) (LOCK|UNLOCK)"); 122 123 for (String line : lines) { 124 Matcher m = p.matcher(line); 125 if (m.matches()) { 126 String relTime = m.group(1); 127 String t = m.group(2); 128 String opStr = m.group(3); 129 Structure structure = buildStructure(relTime, t, opStr); 130 structuredLines.add(structure); 131 } else { 132 System.out.println("NON MATCHING LINE: [" + line + "]"); 133 } 134 135 } 136 return structuredLines; 137 } 138 139 private static Structure buildStructure(String relTime, String t, String opStr) { 140 long r = Long.parseLong(relTime); 141 OperationType operationType; 142 if (opStr.equals("LOCK")) 143 operationType = OperationType.LOCK; 144 else if (opStr.equals("UNLOCK")) { 145 operationType = OperationType.UNLOCK; 146 } else { 147 throw new IllegalArgumentException(opStr + " is not LOCK|UNLOCK"); 148 } 149 return new Structure(r, t, operationType); 150 } 151 152 static class Structure { 153 long time; 154 String thread; 155 OperationType operationType; 156 157 Structure(long time, String thread, OperationType operationType) { 158 this.time = time; 159 this.thread = thread; 160 this.operationType = operationType; 161 } 162 163 @Override 164 public String toString() { 165 return "Structure{" + "time=" + time + ", thread='" + thread + '\'' + ", operationType=" + operationType + '}'; 166 } 167 } 168 169}