// 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.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; 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.domain.v0_6.EntityType; import org.openstreetmap.osmosis.core.domain.v0_6.Relation; import org.openstreetmap.osmosis.core.domain.v0_6.RelationMember; import org.openstreetmap.osmosis.core.domain.v0_6.Way; import org.openstreetmap.osmosis.core.domain.v0_6.WayNode; import org.openstreetmap.osmosis.core.filter.common.DynamicIdTracker; import org.openstreetmap.osmosis.core.filter.common.IdTracker; import org.openstreetmap.osmosis.core.task.v0_6.Sink; /** * A sink that verifies the referential integrity of all data passing through * it. * * @author Brett Henderson */ public class IntegrityReporter implements Sink, EntityProcessor { private static final Logger LOG = Logger.getLogger(IntegrityReporter.class.getName()); private File file; private boolean initialized; private BufferedWriter writer; private IdTracker nodeBitSet; private IdTracker wayBitSet; /** * Creates a new instance. * * @param file * The file to write. */ public IntegrityReporter(File file) { this.file = file; initialized = false; nodeBitSet = new DynamicIdTracker(); wayBitSet = new DynamicIdTracker(); } /** * Writes data to the output file. * * @param data * The data to be written. */ private void write(String data) { try { writer.write(data); } catch (IOException e) { throw new OsmosisRuntimeException("Unable to write data.", e); } } /** * Writes a new line in the output file. */ private void writeNewLine() { try { writer.newLine(); } catch (IOException e) { throw new OsmosisRuntimeException("Unable to write data.", e); } } /** * Initialises the output file for writing. This must be called by * sub-classes before any writing is performed. This method may be called * multiple times without adverse affect allowing sub-classes to invoke it * every time they perform processing. */ protected void initialize() { if (!initialized) { OutputStream outStream = null; try { outStream = new FileOutputStream(file); writer = new BufferedWriter(new OutputStreamWriter(outStream, "UTF-8")); outStream = null; } catch (IOException e) { throw new OsmosisRuntimeException("Unable to open file " + file + " for writing.", e); } finally { if (outStream != null) { try { outStream.close(); } catch (Exception e) { LOG.log(Level.SEVERE, "Unable to close output stream for file " + file + ".", e); } outStream = null; } } initialized = true; write("Entity Type, Entity Id, Referred Type, Referred Id"); writeNewLine(); } } /** * {@inheritDoc} */ public void initialize(Map<String, Object> metaData) { // Do nothing. } /** * {@inheritDoc} */ public void process(EntityContainer entityContainer) { entityContainer.process(this); } /** * {@inheritDoc} */ public void process(BoundContainer bound) { // Do nothing. } /** * {@inheritDoc} */ public void process(NodeContainer node) { nodeBitSet.set(node.getEntity().getId()); } /** * {@inheritDoc} */ public void process(WayContainer wayContainer) { Way way; way = wayContainer.getEntity(); wayBitSet.set(way.getId()); for (WayNode wayNode : way.getWayNodes()) { if (!nodeBitSet.get(wayNode.getNodeId())) { initialize(); write("Way," + way.getId() + ",Node," + wayNode.getNodeId()); writeNewLine(); } } } /** * {@inheritDoc} */ public void process(RelationContainer relationContainer) { Relation relation; relation = relationContainer.getEntity(); for (RelationMember relationMember : relation.getMembers()) { EntityType memberType; memberType = relationMember.getMemberType(); if (EntityType.Node.equals(memberType)) { if (!nodeBitSet.get(relationMember.getMemberId())) { initialize(); write("Relation," + relation.getId() + ",Node," + relationMember.getMemberId()); writeNewLine(); } } else if (EntityType.Way.equals(memberType)) { if (!wayBitSet.get(relationMember.getMemberId())) { initialize(); write("Relation," + relation.getId() + ",Way," + relationMember.getMemberId()); writeNewLine(); } } } } /** * Flushes all changes to file. */ public void complete() { try { if (writer != null) { writer.close(); } } catch (IOException e) { throw new OsmosisRuntimeException("Unable to complete writing to the file " + file + ".", e); } finally { initialized = false; writer = null; } } /** * Cleans up any open file handles. */ public void close() { try { try { if (writer != null) { writer.close(); } } catch (IOException e) { LOG.log(Level.SEVERE, "Unable to close writer.", e); } } finally { initialized = false; writer = null; } } }