Java tutorial
/*************************************************************************** * * * PunkSearch - Searching over LAN * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ package org.punksearch.stats; import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.punksearch.ip.Ip; import java.io.File; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; /** * Statistics for a crawled host. * <p/> * Has several utility methods to deal with host statistics. * * @author Yury Soldak (ysoldak@gmail.com) */ public class HostStats implements Comparable<HostStats> { private static Log log = LogFactory.getLog(HostStats.class); public static final String DUMP_PREFIX = "hosts-"; public static final String DUMP_SUFFIX = ".csv"; private Ip ip; private String protocol; private long size; private long count; /** * Creates instance of host statistics. * * @param ip String representation of host IP. * @param protocol Protocol used to crawl the host (smb|ftp). * @param size Total size of crawled data. * @param count Total count of crawled items (both directories and files). */ public HostStats(String ip, String protocol, long size, long count) { this(new Ip(ip), protocol, size, count); } /** * Companion constructor. Use it if you have IP as an object. */ public HostStats(Ip ip, String protocol, long size, long count) { this.ip = ip; this.protocol = protocol; this.size = size; this.count = count; } public Ip getIp() { return ip; } public String getProtocol() { return protocol; } public long getSize() { return size; } public long getCount() { return count; } @Override public boolean equals(Object obj) { if (obj instanceof HostStats) { return (compareTo((HostStats) obj) == 0 && size == ((HostStats) obj).size && count == ((HostStats) obj).count); } return false; } @Override public int hashCode() { return protocol.hashCode() + ip.hashCode() + Long.valueOf(size).hashCode(); } public int compareTo(HostStats obj) { int ips = ip.compareTo(obj.getIp()); if (ips != 0) { return ips; } else { return protocol.compareTo(obj.getProtocol()); } } @Override public String toString() { return ip + "," + protocol + "," + size + "," + count; } /** * Utility method to merge all statistics files in a directory created with dump method into one big file. * <p/> * Dumping into final file may fail in case of permissions or free space problems. In this case the method just * writes warning in the log and returns. Maybe we should throw an exception here, think about (TODO). * * @param inputDirPath Directory to search for statistics files. * @param outFilePath File to dump merged statistics. */ public static void merge(String inputDirPath, String outFilePath) { File dir = new File(inputDirPath); String[] fileNames = dir.list(); List<String> list = new ArrayList<String>(); for (String fileName : fileNames) { if (fileName.startsWith(DUMP_PREFIX) && fileName.endsWith(DUMP_SUFFIX)) { list.add(fileName); } } fileNames = list.toArray(new String[list.size()]); if (fileNames.length > 0) { Arrays.sort(fileNames); String dirPath = dir.getAbsolutePath() + File.separator; List<HostStats> result = parse(dirPath + fileNames[fileNames.length - 1]); if (fileNames.length > 1) { for (int i = fileNames.length - 2; i >= 0; i--) { List<HostStats> curHostStats = parse(dirPath + fileNames[i]); for (HostStats curHS : curHostStats) { boolean found = false; for (HostStats resultHS : result) { if (curHS.compareTo(resultHS) == 0) { found = true; break; } } if (!found) { result.add(curHS); } } } } Collections.sort(result); try { FileUtils.writeLines(new File(outFilePath), result); } catch (IOException e) { log.warn("Can't dump host stats into file (check permissions and free space): " + outFilePath); } } } /** * Utility method which parses a statistics file. * <p/> * Parsing may fail in case of permission problems. In this case the method just writes warning in the log and * returns empty list. Maybe we should throw an exception here, think about (TODO). * * @param hostsFilePath Statistics file to parse. * @return List of host statistics instances. May return empty list in case of permission problems. */ @SuppressWarnings("unchecked") public static List<HostStats> parse(String hostsFilePath) { List<HostStats> result = new ArrayList<HostStats>(); try { List<String> lines = FileUtils.readLines(new File(hostsFilePath)); for (String line : lines) { String[] parts = line.trim().split(","); if (line.trim().startsWith("#") || parts.length < 4) { continue; } HostStats hs = new HostStats(parts[0], parts[1], Long.parseLong(parts[2]), Long.parseLong(parts[3])); result.add(hs); } } catch (IOException e) { log.warn("Can't read host stats from file (check permissions): " + hostsFilePath); } return result; } /** * Utility method to dump a list of host stats into a file. * <p/> * Dumping may fail in case of permissions or free space problems. In this case the method just writes warning in * the log and returns. Maybe we should throw an exception here, think about (TODO). * * @param dirPath Directory where to create new statistics file. * @param hostStats List of host statistics to dump into the file. */ public static void dump(String dirPath, List<HostStats> hostStats) { Collections.sort(hostStats); File dir = new File(dirPath); if (!dir.exists() && !dir.mkdir()) { log.warn("Can't make directory (check permissions and free space): " + dirPath); return; } DateFormat df = new SimpleDateFormat("yyyy.MM.dd-HH.mm.ss"); String fileName = DUMP_PREFIX + df.format(new Date()) + DUMP_SUFFIX; File dumpFile = new File(dirPath + File.separator + fileName); try { FileUtils.writeLines(dumpFile, hostStats); } catch (IOException e) { log.warn("Can't dump host stats into (check permissions and free space): " + dirPath + File.separator + fileName); } } }