/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package osmimport;
import java.io.IOException;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
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.Node;
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.task.v0_6.Sink;
import org.openstreetmap.osmosis.pgsimple.common.NodeLocationStoreType;
import org.postgis.LineString;
import org.postgis.Polygon;
import org.voltdb.VoltProcedure;
import org.voltdb.client.Client;
import org.voltdb.client.ClientConfig;
import org.voltdb.client.ClientFactory;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.ClientStatsContext;
import org.voltdb.client.ClientStatusListenerExt;
import org.voltdb.client.NoConnectionsException;
import org.voltdb.client.ProcedureCallback;
import org.voltdb.types.TimestampType;
//import SyncBenchmark.StatusListener;
public class VoltDBOsmSink implements Sink, EntityProcessor {
public static final String INS_NODE_PROC = "NODES.insert";
public static final String INS_NODE_TAG_PROC = "NODE_TAGS.insert";
public static final String INS_RELATIONS_PROC = "RELATIONS.insert";
public static final String INS_RELATIONS_MEMBER_PROC = "RELATION_MEMBERS.insert";
public static final String INS_RELATION_TAGS_PROC = "RELATION_TAGS.insert";
public static final String INS_USERS_PROC = "USERS.insert";
public static final String INS_WAYS_PROC = "WAYS.insert";
public static final String INS_WAYS_NODES_PROC = "WAY_NODES.insert";
public static final String INS_WAY_TAGS_PROC = "WAY_TAGS.insert";
private boolean enableLinestringBuilder = false;
private boolean enableBboxBuilder = true;
private boolean keepInvalidWays = false;
private final WayPolygonGeometryBuilder wayGeometryBuilder = new WayPolygonGeometryBuilder(NodeLocationStoreType.TempFile);
// Reference to the database connection we will use
private String server;
private ClientStatsContext periodicStatsContext;
private ClientStatsContext fullStatsContext;
private Client client;
public VoltDBOsmSink(String server) {
this.server = server;
}
@Override
public void initialize(Map<String, Object> arg0) {
try {
connect(server);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
private void connect(String servers) throws InterruptedException, ClassNotFoundException, SQLException {
System.out.println("Connecting to VoltDB...");
ClientConfig clientConfig = new ClientConfig("", "", new VoltDBOsmSink.StatusListener());
clientConfig.setMaxTransactionsPerSecond(10000);
client = ClientFactory.createClient(clientConfig);
try {
// if we have more then one server, we would connect to each one
// individually inside a loop.
client.createConnection(servers);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
periodicStatsContext = client.createStatsContext();
fullStatsContext = client.createStatsContext();
}
@Override
public void complete() {
}
@Override
public void release() {
try {
client.drain();
} catch (NoConnectionsException | InterruptedException e) {
e.printStackTrace();
}
try {
client.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void process(EntityContainer entity) {
entity.process(this);
}
public void process(BoundContainer boundContainer) {
// Do nothing.
}
public void process(NodeContainer nodeContainer) {
Node node;
node = nodeContainer.getEntity();
double lat = node.getLatitude();
double lng = node.getLongitude();
String pointText = "POINT(" + lng + " " + lat + ")";
// keep track of the nodes so we can build polygons later
if (enableBboxBuilder || enableLinestringBuilder) {
wayGeometryBuilder.addNodeLocation(node);
}
// client.callProcedure(callback, procName, parameters)
try {
client.callProcedure(new InsertCallback(), INS_NODE_PROC, node.getId(), node.getVersion(),
node.getUser().getId(), new TimestampType(node.getTimestamp().getTime()), node.getChangesetId(),
pointText);
} catch (NoConnectionsException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Collection<Tag> tags = node.getTags();
for (Tag tag : tags) {
// System.out.println(INS_NODE_TAG_PROC+","+node.getId()+","+tag.getKey()+","+tag.getValue());
try {
client.callProcedure(new InsertCallback(), INS_NODE_TAG_PROC, node.getId(), tag.getKey(),
tag.getValue());
} catch (NoConnectionsException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void process(WayContainer wayContainer) {
Way way;
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) {
for (Tag tag : way.getTags()) {
try {
client.callProcedure(new InsertCallback(), INS_WAY_TAGS_PROC, way.getId(), tag.getKey(),
tag.getValue());
} catch (NoConnectionsException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// Add these to the ways_nodes_table;
int sequence = 0;
for (Long nodeId : nodeIds) {
try {
client.callProcedure(new InsertCallback(), INS_WAYS_NODES_PROC, way.getId(), nodeId, sequence);
} catch (NoConnectionsException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
sequence++;
}
StringBuffer sb = new StringBuffer();
// if the first node id == the last nodeId, we know that this is a
// closed loop.
long n0 = nodeIds.get(0);
long nn = nodeIds.get(nodeIds.size() - 1);
if (n0 == nn) {
if (enableBboxBuilder) {
Polygon pg = wayGeometryBuilder.createPolygon(way);
pg.outerWKT(sb);
}
} else {
// it's a lineString, but we don't support it yet.
if (enableLinestringBuilder) {
LineString lineString = wayGeometryBuilder.createWayLinestring(way);
lineString.outerWKT(sb);
} else {
return;
}
}
String bbox = sb.toString();
try {
client.callProcedure(new InsertCallback(), INS_WAYS_PROC, way.getId(), way.getVersion(),
way.getUser().getId(), way.getTimestamp(), way.getChangesetId(), bbox);
} catch (NoConnectionsException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* {@inheritDoc}
*/
public void process(RelationContainer relationContainer) {
Relation relation;
int memberSequenceId;
relation = relationContainer.getEntity();
try {
client.callProcedure(new InsertCallback(), INS_RELATIONS_PROC, relation.getId(), relation.getVersion(),
relation.getUser().getId(), relation.getTimestamp(), relation.getChangesetId());
} catch (NoConnectionsException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
memberSequenceId = 0;
for (RelationMember member : relation.getMembers()) {
try {
client.callProcedure(new InsertCallback(), INS_RELATIONS_MEMBER_PROC, relation.getId(),
member.getMemberId(), member.getMemberType().ordinal(), member.getMemberRole(),
memberSequenceId);
} catch (NoConnectionsException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
memberSequenceId++;
}
for (Tag tag : relation.getTags()) {
try {
client.callProcedure(new InsertCallback(), INS_RELATION_TAGS_PROC, relation.getId(), tag.getKey(),
tag.getValue());
} catch (NoConnectionsException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Provides a callback to be notified on node failure. This example only
* logs the event.
*/
public static class StatusListener extends ClientStatusListenerExt {
@Override
public void connectionLost(String hostname, int port, int connectionsLeft, DisconnectCause cause) {
System.err.printf("Connection to %s:%d was lost.\n", hostname, port);
}
public void backpressure(boolean status) {
}
}
public static class InsertCallback implements ProcedureCallback {
@Override
public void clientCallback(ClientResponse response) throws Exception {
if (response.getStatus() != ClientResponse.SUCCESS) {
System.err.println(response.getStatusString());
return;
}
}
}
}