// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.core.report.v0_6; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.openstreetmap.osmosis.core.OsmosisRuntimeException; import org.openstreetmap.osmosis.core.container.v0_6.BoundContainer; import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer; import org.openstreetmap.osmosis.core.container.v0_6.EntityProcessor; import org.openstreetmap.osmosis.core.container.v0_6.NodeContainer; import org.openstreetmap.osmosis.core.container.v0_6.RelationContainer; import org.openstreetmap.osmosis.core.container.v0_6.WayContainer; import org.openstreetmap.osmosis.core.task.v0_6.Sink; /** * An OSM data sink that analyses the data sent to it and provides a simple * report. * * @author Brett Henderson */ public class EntityReporter implements Sink { private static final int COLUMN_WIDTH_USER_NAME = 50; private static final int COLUMN_WIDTH_NODE_COUNT = 7; private static final int COLUMN_WIDTH_WAY_COUNT = 7; private static final int COLUMN_WIDTH_RELATION_COUNT = 7; private File file; private Map<String, UserStatistics> userMap; private UserStatistics anonymousUser; private UserStatistics totalUser; /** * Creates a new instance. * * @param file * The file to write. */ public EntityReporter(File file) { this.file = file; userMap = new HashMap<String, UserStatistics>(); anonymousUser = new UserStatistics("anonymous"); totalUser = new UserStatistics("Total"); } /** * {@inheritDoc} */ public void initialize(Map<String, Object> metaData) { // Do nothing. } /** * {@inheritDoc} */ public void process(EntityContainer entityContainer) { String userName; final UserStatistics user; // Obtain the user statistics object. userName = entityContainer.getEntity().getUser().getName(); if (userName != null && userName.length() > 0) { if (userMap.containsKey(userName)) { user = userMap.get(userName); } else { user = new UserStatistics(userName); userMap.put(userName, user); } } else { user = anonymousUser; } // Increment the relevant user statistic. entityContainer.process( new EntityProcessor() { private UserStatistics processorUser = user; public void process(BoundContainer bound) { // Do nothing. } public void process(NodeContainer node) { processorUser.incrementNodeCount(); totalUser.incrementNodeCount(); } public void process(WayContainer way) { processorUser.incrementWayCount(); totalUser.incrementWayCount(); } public void process(RelationContainer relation) { processorUser.incrementRelationCount(); totalUser.incrementRelationCount(); } } ); } /** * Writes a single value and pads it out to the correct column width. * * @param writer * The report destination. * @param data * The data to be written. * @param columnWidth * The width of the column. */ private void writeColumnValue(BufferedWriter writer, String data, int columnWidth) throws IOException { int padLength; // Calculate the required data padding. The total column width is the // specified column width plus one space. padLength = columnWidth - data.length() + 1; if (padLength < 1) { padLength = 1; } writer.write(data); for (int i = 0; i < padLength; i++) { writer.write(' '); } } /** * Writes a single line summary of the user statistics. * * @param writer * The report destination. * @param userStatistics * The user to report on. */ private void writeUserLine(BufferedWriter writer, UserStatistics userStatistics) throws IOException { writeColumnValue(writer, userStatistics.getUserName(), COLUMN_WIDTH_USER_NAME); writeColumnValue(writer, Integer.toString(userStatistics.getNodeCount()), COLUMN_WIDTH_NODE_COUNT); writeColumnValue(writer, Integer.toString(userStatistics.getWayCount()), COLUMN_WIDTH_WAY_COUNT); writeColumnValue(writer, Integer.toString(userStatistics.getRelationCount()), COLUMN_WIDTH_RELATION_COUNT); writer.newLine(); } /** * Add user information to the report file. * * @param writer * The report destination. */ private void writeUserReport(BufferedWriter writer) throws IOException { List<UserStatistics> userList; // Sort the user statistics by user id. userList = new ArrayList<UserStatistics>(userMap.values()); Collections.sort( userList, new Comparator<UserStatistics>() { public int compare(UserStatistics o1, UserStatistics o2) { return o1.getUserName().compareTo(o2.getUserName()); } } ); writer.write("********** User Report **********"); writer.newLine(); writeColumnValue(writer, "USER NAME", COLUMN_WIDTH_USER_NAME); writeColumnValue(writer, "NODES", COLUMN_WIDTH_NODE_COUNT); writeColumnValue(writer, "WAYS", COLUMN_WIDTH_WAY_COUNT); writeColumnValue(writer, "RELNS", COLUMN_WIDTH_RELATION_COUNT); writer.newLine(); writeUserLine(writer, anonymousUser); for (UserStatistics userStatistics : userList) { writeUserLine(writer, userStatistics); } writer.newLine(); writeUserLine(writer, totalUser); } /** * Flushes all changes to file. */ public void complete() { try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { // Produce a report on the user statistics. writeUserReport(writer); } catch (IOException e) { throw new OsmosisRuntimeException("Unable to write report to file " + file + "."); } } /** * {@inheritDoc} */ public void close() { } /** * A class holding the summary information for a single user. */ private static class UserStatistics { private String userName; private int nodeCount; private int wayCount; private int relationCount; /** * Creates a new instance. * * @param userName * The name of the user that this statistics record relates * to. */ public UserStatistics(String userName) { this.userName = userName; } /** * Increments the node count by one. */ public void incrementNodeCount() { nodeCount++; } /** * Increments the way count by one. */ public void incrementWayCount() { wayCount++; } /** * Increments the relation count by one. */ public void incrementRelationCount() { relationCount++; } /** * Returns the name of the user for which this object contains data. * * @return The user name. */ public String getUserName() { return userName; } /** * Returns the node count. * * @return The node count. */ public int getNodeCount() { return nodeCount; } /** * Returns the way count. * * @return The way count. */ public int getWayCount() { return wayCount; } /** * Returns the relation count. * * @return The relation count. */ public int getRelationCount() { return relationCount; } } }