/** * */ package de.fhswf.in.inf.java1.aufgabe10; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * A class, that counts words in files. * * @author $Author: $ * @version $Revision: $, $Date: $ UTC */ public class ParallelWordCount { private static final Integer NEWVALUE = new Integer(1); /** * Counts words in one line. * * @author $Author: $ * @version $Revision: $, $Date: $ UTC */ private class LineWordCount implements Runnable { private String[] lineArray; /** * Creates the object which will be threaded. * * @param wordMap * The wordMap into which the counts should be added. * @param line * The line to be counted. */ public LineWordCount(String line) { if (line == null) { throw new IllegalArgumentException("Line can't be null."); } if (line.isEmpty()) { throw new IllegalArgumentException("Line can't be empty."); } lineArray = line.split("[^\\p{IsAlphabetic}\\p{Digit}]+"); } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public final void run() { for (String word : lineArray) { // Split creates empty String, if first char is a split char. if (!word.isEmpty()) { word = word.toLowerCase(); boolean success; do { success = true; Integer tmp = wordMap.putIfAbsent(word, NEWVALUE); if (tmp != null) { success = wordMap.replace(word, tmp, tmp + 1); } } while (!success); } } } } private static final int TIMEOUT = 30; private ConcurrentSkipListMap wordMap; /** * Empty constructor. * */ public ParallelWordCount() { } /** * Reads a file and counts the words. * * @param file * The file to be read. */ public final void readFile(File file) { try (BufferedReader f = new BufferedReader(new FileReader(file))) { if (wordMap == null) { wordMap = new ConcurrentSkipListMap<>(); } wordMap.clear(); String line = null; ExecutorService executer = Executors.newFixedThreadPool(Runtime .getRuntime().availableProcessors()); while ((line = f.readLine()) != null) { Runnable worker = new LineWordCount(line); executer.execute(worker); } executer.shutdown(); boolean success = false; try { success = executer.awaitTermination(TIMEOUT, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } if (!success) { wordMap = null; throw new IllegalStateException( "Waiting for threads has timed out."); } } catch (IOException e) { e.printStackTrace(System.err); } } /** * Returns all words from the file. * * @return An unmodifiable Set of the words from the file. */ public final Set getWords() { if (wordMap == null) { throw new IllegalStateException("First a file must be read."); } return Collections.unmodifiableSet(wordMap.keySet()); } /** * Returns the count of a word in a file. * * @param word * The file to be counted. * @return Returns the count of findings in the file. */ public final int getCount(String word) { if (wordMap == null) { throw new IllegalStateException("First a file must be read."); } if (word == null) { throw new IllegalArgumentException("Word must be a valid referece."); } if (word.isEmpty()) { throw new IllegalArgumentException("The word can't be empty."); } Integer tmp = wordMap.get(word); if (tmp == null) { return 0; } return tmp; } }