// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.pgsnapshot.v0_6.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.Entity;
import org.openstreetmap.osmosis.core.domain.v0_6.Node;
import org.openstreetmap.osmosis.core.domain.v0_6.OsmUser;
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.Tag;
import org.openstreetmap.osmosis.core.domain.v0_6.Way;
import org.openstreetmap.osmosis.core.domain.v0_6.WayNode;
import org.openstreetmap.osmosis.core.lifecycle.CompletableContainer;
import org.openstreetmap.osmosis.pgsnapshot.common.CopyFileWriter;
import org.openstreetmap.osmosis.pgsnapshot.common.NodeLocationStoreType;
import org.openstreetmap.osmosis.pgsnapshot.common.PointBuilder;
import org.openstreetmap.osmosis.core.task.v0_6.Sink;
import org.openstreetmap.osmosis.hstore.PGHStore;
/**
* An OSM data sink for storing all data to a set of database dump files. These
* files can be used for populating an empty database.
*
* @author Brett Henderson
*/
public class CopyFilesetBuilder implements Sink, EntityProcessor {
private boolean enableBboxBuilder;
private boolean enableLinestringBuilder;
private boolean keepInvalidWays;
private WayGeometryBuilder wayGeometryBuilder;
private CompletableContainer writerContainer;
private MemberTypeValueMapper memberTypeValueMapper;
private CopyFileWriter userWriter;
private CopyFileWriter nodeWriter;
private CopyFileWriter wayWriter;
private CopyFileWriter wayNodeWriter;
private CopyFileWriter relationWriter;
private CopyFileWriter relationMemberWriter;
private PointBuilder pointBuilder;
private Set<Integer> userSet;
/**
* Creates a new instance.
*
* @param copyFileset
* The set of COPY files to be populated.
* @param enableBboxBuilder
* If true, the way bbox geometry is built during processing
* instead of relying on the database to build them after import.
* This increases processing but is faster than relying on the
* database.
* @param enableLinestringBuilder
* If true, the way linestring geometry is built during
* processing instead of relying on the database to build them
* after import. This increases processing but is faster than
* relying on the database.
* @param storeType
* The node location storage type used by the geometry builders.
* @param keepInvalidWays
* If true, zero and single node ways are kept. Otherwise they are
* silently dropped to avoid putting invalid geometries into the
* database which can cause problems with postgis functions.
*/
public CopyFilesetBuilder(
CopyFileset copyFileset, boolean enableBboxBuilder,
boolean enableLinestringBuilder, NodeLocationStoreType storeType,
boolean keepInvalidWays) {
this.enableBboxBuilder = enableBboxBuilder;
this.enableLinestringBuilder = enableLinestringBuilder;
this.keepInvalidWays = keepInvalidWays;
writerContainer = new CompletableContainer();
userWriter = writerContainer.add(new CopyFileWriter(copyFileset.getUserFile()));
nodeWriter = writerContainer.add(new CopyFileWriter(copyFileset.getNodeFile()));
wayWriter = writerContainer.add(new CopyFileWriter(copyFileset.getWayFile()));
wayNodeWriter = writerContainer.add(new CopyFileWriter(copyFileset.getWayNodeFile()));
relationWriter = writerContainer.add(new CopyFileWriter(copyFileset.getRelationFile()));
relationMemberWriter = writerContainer.add(new CopyFileWriter(copyFileset.getRelationMemberFile()));
pointBuilder = new PointBuilder();
wayGeometryBuilder = new WayGeometryBuilder(storeType);
memberTypeValueMapper = new MemberTypeValueMapper();
memberTypeValueMapper = new MemberTypeValueMapper();
userSet = new HashSet<Integer>();
}
/**
* {@inheritDoc}
*/
public void initialize(Map<String, Object> metaData) {
// Do nothing.
}
/**
* {@inheritDoc}
*/
public void process(EntityContainer entityContainer) {
OsmUser user;
// Write a user entry if the user doesn't already exist.
user = entityContainer.getEntity().getUser();
if (!user.equals(OsmUser.NONE)) {
if (!userSet.contains(user.getId())) {
userWriter.writeField(user.getId());
userWriter.writeField(user.getName());
userWriter.endRecord();
userSet.add(user.getId());
}
}
// Process the entity itself.
entityContainer.process(this);
}
/**
* {@inheritDoc}
*/
public void process(BoundContainer boundContainer) {
// Do nothing.
}
private PGHStore buildTags(Entity entity) {
PGHStore tags;
tags = new PGHStore();
for (Tag tag : entity.getTags()) {
tags.put(tag.getKey(), tag.getValue());
}
return tags;
}
/**
* {@inheritDoc}
*/
public void process(NodeContainer nodeContainer) {
Node node;
node = nodeContainer.getEntity();
nodeWriter.writeField(node.getId());
nodeWriter.writeField(node.getVersion());
nodeWriter.writeField(node.getUser().getId());
nodeWriter.writeField(node.getTimestamp());
nodeWriter.writeField(node.getChangesetId());
nodeWriter.writeField(buildTags(node));
nodeWriter.writeField(pointBuilder.createPoint(node.getLatitude(), node.getLongitude()));
nodeWriter.endRecord();
if (enableBboxBuilder || enableLinestringBuilder) {
wayGeometryBuilder.addNodeLocation(node);
}
}
/**
* {@inheritDoc}
*/
public void process(WayContainer wayContainer) {
Way way;
int sequenceId;
List<Long> nodeIds;
way = wayContainer.getEntity();
nodeIds = new ArrayList<Long>(way.getWayNodes().size());
for (WayNode wayNode : way.getWayNodes()) {
nodeIds.add(wayNode.getNodeId());
}
// Keep invalid ways out of the database if desired by the user
if (way.getWayNodes().size() > 1 || keepInvalidWays) {
wayWriter.writeField(way.getId());
wayWriter.writeField(way.getVersion());
wayWriter.writeField(way.getUser().getId());
wayWriter.writeField(way.getTimestamp());
wayWriter.writeField(way.getChangesetId());
wayWriter.writeField(buildTags(way));
wayWriter.writeField(nodeIds);
if (enableBboxBuilder) {
wayWriter.writeField(wayGeometryBuilder.createWayBbox(way));
}
if (enableLinestringBuilder) {
wayWriter.writeField(wayGeometryBuilder.createWayLinestring(way));
}
wayWriter.endRecord();
sequenceId = 0;
for (WayNode wayNode : way.getWayNodes()) {
wayNodeWriter.writeField(way.getId());
wayNodeWriter.writeField(wayNode.getNodeId());
wayNodeWriter.writeField(sequenceId++);
wayNodeWriter.endRecord();
}
}
}
/**
* {@inheritDoc}
*/
public void process(RelationContainer relationContainer) {
Relation relation;
int memberSequenceId;
relation = relationContainer.getEntity();
relationWriter.writeField(relation.getId());
relationWriter.writeField(relation.getVersion());
relationWriter.writeField(relation.getUser().getId());
relationWriter.writeField(relation.getTimestamp());
relationWriter.writeField(relation.getChangesetId());
relationWriter.writeField(buildTags(relation));
relationWriter.endRecord();
memberSequenceId = 0;
for (RelationMember member : relation.getMembers()) {
relationMemberWriter.writeField(relation.getId());
relationMemberWriter.writeField(member.getMemberId());
relationMemberWriter.writeField(memberTypeValueMapper.getMemberType(member.getMemberType()));
relationMemberWriter.writeField(member.getMemberRole());
relationMemberWriter.writeField(memberSequenceId++);
relationMemberWriter.endRecord();
}
}
/**
* Writes any buffered data to the database and commits.
*/
public void complete() {
writerContainer.complete();
}
/**
* Releases all resources.
*/
public void close() {
writerContainer.close();
wayGeometryBuilder.close();
}
}