package osm.jp.api;
import hayashi.yuu.tools.json.JsonTool;
import java.io.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLSyntaxErrorException;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonBuilderFactory;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonValue;
import javax.xml.parsers.ParserConfigurationException;
import jp.co.areaweb.tools.csv.CsvRecord;
import jp.co.areaweb.tools.database.DatabaseTool;
import org.hsqldb.HsqlException;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public abstract class Osmdb {
public String tableName;
public Connection hsqldb = null; // hsqldb DatabaseTool.openDb("database");
public Osmdb(Connection hsqldb, String tableName) {
this.hsqldb = hsqldb;
this.tableName = tableName;
}
abstract public void create() throws SQLException;
void sql(String sql) throws SQLException {
System.out.println(sql);
try (PreparedStatement ps = hsqldb.prepareStatement(sql)) {
ps.executeUpdate();
}
catch (SQLSyntaxErrorException e) {
System.out.println("107:"+ e.toString());
if (!(e.toString().startsWith("java.sql.SQLSyntaxErrorException: user lacks privilege or object not found:"))) {
throw e;
}
}
}
public static void outputWriter(PrintWriter pw, String text) {
System.out.println("\t" + text);
pw.print(text);
}
public static final int POINT_NO = 0; // 評価ポイント無し→ score=50
public static final int POINT_FIXME = 1; // 評価ポイント|!(fixme=null) → score=1
public static final int POINT_NO_BRAND = 2; // 評価ポイント|brand=null → score=1
public static final int POINT_NO_NAME = 4; // 評価ポイント|name=null → score=1
public static final int POINT_BUS_NO = 8; // 評価ポイント|!(bus=yes) → score=0
/**
* 'table.OSM_EXIST'の内容をCSV形式にして標準出力に出力する
* @throws java.sql.SQLException
*/
public void export() throws SQLException {
String header = "idref,lat,lon,score";
System.out.println("TABLE: "+ tableName);
System.out.println(header);
PreparedStatement ps8 = hsqldb.prepareStatement(
"SELECT idref,lat,lon,score,removed FROM "+ tableName
);
try (ResultSet rset8 = ps8.executeQuery()) {
while (rset8.next()) {
String idcode = rset8.getString(1);
Double lat = rset8.getDouble(2);
Double lon = rset8.getDouble(3);
int score = rset8.getInt(4);
boolean removed = rset8.getBoolean(5);
String out = String.format(
"OSM: %s,%2.5f,%3.5f,%d,%b",
idcode, lat, lon, score, removed
);
System.out.println(out);
}
}
}
public int importExistingNode(Connection osmdb, ResultSet rset, int point, boolean removed) throws IOException, SQLException {
String osmidStr = rset.getString("osm_id");
String latStr = rset.getString("lat");
String lonStr = rset.getString("lon");
String brandStr = rset.getString("brand");
String nameStr = rset.getString("name");
String fixmeStr = "";
int score = 50;
if (((point & POINT_NO_BRAND) != 0) && isNull(brandStr)) {
score = 1;
}
if (((point & POINT_NO_NAME) != 0) && isNull(nameStr)) {
score = 1;
}
boolean fixme = false;
boolean busYes = false;
if (((point & (POINT_FIXME | POINT_BUS_NO)) != 0)) {
PreparedStatement ps8 = osmdb.prepareStatement(
"SELECT * FROM planet_osm_nodes where id='"+ osmidStr +"'"
);
try (ResultSet rset8 = ps8.executeQuery()) {
while (rset8.next()) {
String tags = rset8.getString("tags");
if (tags != null) {
tags = tags.substring(1);
tags = tags.substring(0, tags.length()-1);
CsvRecord csv = new CsvRecord();
csv.analizeRecord(tags);
boolean key = true;
boolean bus = false;
for (String str : csv) {
if (key) {
if (str.startsWith("fixme")) {
fixme = true;
}
if (str.equals("bus")) {
bus = true;
}
key = false;
}
else {
if (bus) {
if (str.equals("yes")) {
busYes = true;
}
bus = false;
}
key = true;
}
}
//System.out.println(tags);
}
}
}
if (((point & POINT_FIXME) != 0) && fixme) {
score = 1;
}
if (((point & POINT_BUS_NO) != 0) && !busYes) {
score = 0;
}
}
if (score > 0) {
// idref と brandStr をデータベースに格納する
System.out.println(
"INSERT INTO "+ tableName
+ " (idref,lat,lon,score,name,removed) VALUES ("
+ osmidStr +","
+ latStr +","
+ lonStr +","
+ Integer.toString(score) +","
+ "'"+ nameStr +"',"
+ "false"
+ ")N"
);
try (PreparedStatement ps5 = hsqldb.prepareStatement(
"INSERT INTO "+ tableName +" (idref,lat,lon,score,name,removed) VALUES (?,?,?,?,?,?)"
)) {
ps5.setString(1, osmidStr);
ps5.setDouble(2, Double.parseDouble(latStr));
ps5.setDouble(3, Double.parseDouble(lonStr));
ps5.setInt(4, score);
ps5.setString(5, nameStr);
ps5.setBoolean(6, removed);
ps5.executeUpdate();
return 1;
}
catch (HsqlException | SQLIntegrityConstraintViolationException e) {
// integrity constraint violation: unique constraint or index violation; SYS_PK_10069 table: FUEL_EXIST
// [HsqlException]は、無視する
// integrity constraint violation: unique constraint or index violation; SYS_PK_10069 table: FUEL_EXIST
// [SQLIntegrityConstraintViolationException]は、無視する
}
}
return 0;
}
/**
* File(HttpPOST.EXIST_FILE)を読み取って、データベースに反映させる。<br>
* その際に、OSMノードを評価し、scoreを算定する
*
* @param sqlWhere POI条件
* @param point 評価ポイント[POINT_NO|POINT_BRAND|POINT_NAME] 1: 'brand' 2:'name'
* @param removed
* @throws Exception エラー
*/
public void readExisting(String sqlWhere, int point, boolean removed) throws Exception {
long counter = 0L;
try (Connection osmdb = DatabaseTool.openDb("osmdb")) {
String sqlSelect = "osm_id,"
+ "brand,"
+ "disused,"
+ "name,"
+ "ST_Y(ST_Transform(way,4326)) as lat,"
+ "ST_X(ST_Transform(way,4326)) as lon";
String sqlNode = String.format(
"SELECT %s FROM planet_osm_point %s",
sqlSelect,
sqlWhere
);
PreparedStatement ps1 = osmdb.prepareStatement(sqlNode);
try (ResultSet rset1 = ps1.executeQuery()) {
while (rset1.next()) {
counter += importExistingNode(osmdb, rset1, point, removed);
}
}
String sqlArea = String.format(
"SELECT %s FROM planet_osm_polygon %s",
"osm_id,brand,disused,name,ST_Y(ST_Transform(ST_Centroid(way),4326)) as lat,ST_X(ST_Transform(ST_Centroid(way),4326)) as lon",
sqlWhere
);
PreparedStatement ps2 = osmdb.prepareStatement(sqlArea);
try (ResultSet rset2 = ps2.executeQuery()) {
while (rset2.next()) {
counter += importExistingNode(osmdb, rset2, point, removed);
}
}
System.out.println("Exists Node count = " + counter);
}
}
/**
*
* SELECT
* planet_osm_nodes.id,
* planet_osm_nodes.tags
* planet_osm_nodes.way --> lat & lon
* FROM
* public.planet_osm_point,
* public.planet_osm_nodes
* WHERE (
* planet_osm_point.osm_id = planet_osm_nodes.id
* and 'disused:amenity'=ANY(planet_osm_nodes.tags)
* and 'fuel'=ANY(planet_osm_nodes.tags)
* )
*
* @param kStr
* @param vStr
* @param point
* @throws Exception
*/
public void readExistingSub(String kStr, String vStr, int point) throws Exception {
readExistingSub(kStr, vStr, point, true);
}
public void readExistingSub(String kStr, String vStr, int point, boolean removed) throws Exception {
JsonBuilderFactory factory = Json.createBuilderFactory(null);
JsonObjectBuilder builder = factory.createObjectBuilder();
builder.add("k",kStr);
builder.add("v", vStr);
JsonObject tag = builder.build();
readExistingSub(tag, point, removed);
}
/**
*
* @param tag {k: string, v: string}
* @param point
* @throws Exception
*/
public void readExistingSub(JsonObject tag,int point) throws Exception {
readExistingSub(tag, point, true);
}
/**
*
* @param tag {k: string, v: string}
* @param point
* @param removed
* @throws Exception
*/
public void readExistingSub(JsonObject tag,int point, boolean removed) throws Exception {
long counter = 0L;
try (Connection osmdb = DatabaseTool.openDb("osmdb")) {
String sqlSelect = "SELECT tags,id,ST_Y(ST_Transform(way,4326)) as lat,ST_X(ST_Transform(way,4326)) as lon";
String sqlWhere = String.format(
"WHERE (osm_id=id AND '%s'=ANY(tags) AND '%s'=ANY(tags))",
tag.getString("k"), tag.getString("v")
);
String sql = String.format(
"%s FROM planet_osm_point,planet_osm_nodes %s", sqlSelect, sqlWhere
);
System.out.println(sql);
PreparedStatement ps1 = osmdb.prepareStatement(sql);
try (ResultSet rset1 = ps1.executeQuery()) {
while (rset1.next()) {
String tags = rset1.getString("tags");
String idref = rset1.getString("id");
String latStr = rset1.getString("lat");
String lonStr = rset1.getString("lon");
double lat = Double.valueOf(latStr);
double lon = Double.valueOf(lonStr);
int score = score(point, tags);
counter += insertExistingNode(idref, lat, lon, score, "", removed);
}
}
System.out.println("Exists Node count = " + counter);
}
}
/**
*
* @param array tags: [{k: string, v: string}]
* @param point
* @throws Exception
*/
public void readExistingSub(JsonArray array,int point) throws Exception {
readExistingSub(array,point, true);
}
/**
*
* @param array tags: [{k: string, v: string}]
* @param point
* @param removed
* @throws Exception
*/
public void readExistingSub(JsonArray array,int point, boolean removed) throws Exception {
long counter = 0L;
try (Connection osmdb = DatabaseTool.openDb("osmdb")) {
String sqlSelect = "SELECT "
+ "tags,"
+ "id,"
+ "ST_Y(ST_Transform(way,4326)) as lat,"
+ "ST_X(ST_Transform(way,4326)) as lon";
String sqlSS = "";
for (JsonValue v : array) {
JsonObject tag = (JsonObject)v;
sqlSS += String.format(
" AND ('%s'=ANY(tags) AND '%s'=ANY(tags))",
tag.getString("k"), tag.getString("v")
);
}
String sqlWhere = String.format("WHERE (osm_id=id %s)", sqlSS);
String sql = String.format(
"%s FROM planet_osm_point,planet_osm_nodes %s",
sqlSelect, sqlWhere
);
System.out.println(sql);
PreparedStatement ps1 = osmdb.prepareStatement(sql);
try (ResultSet rset1 = ps1.executeQuery()) {
while (rset1.next()) {
String tags = rset1.getString("tags");
String idref = rset1.getString("id");
String latStr = rset1.getString("lat");
String lonStr = rset1.getString("lon");
double lat = Double.valueOf(latStr);
double lon = Double.valueOf(lonStr);
int score = score(point, tags);
counter += insertExistingNode(idref, lat, lon, score, "", removed);
}
}
System.out.println("Exists Node count = " + counter);
}
}
int score(int point, String tags) {
int score = 50;
if (tags == null) {
return score;
}
boolean brandYes = false;
boolean busYes = false;
boolean fixmeYes = false;
boolean nameYes = false;
tags = tags.substring(1);
tags = tags.substring(0, tags.length()-1);
CsvRecord csv = new CsvRecord();
csv.analizeRecord(tags);
boolean key = true;
boolean bus = false;
for (String str : csv) {
if (key) {
if (str.startsWith("fixme")) {
fixmeYes = true;
}
else if (str.equals("bus")) {
bus = true;
}
else if (str.equals("brand")) {
brandYes = true;
}
else if (str.startsWith("name")) {
nameYes = true;
}
key = false;
}
else {
if (bus) {
if (str.equals("yes")) {
busYes = true;
}
bus = false;
}
key = true;
}
}
if (((point & POINT_NO_BRAND) != 0) && !brandYes) {
score = 1;
}
if (((point & POINT_NO_NAME) != 0) && !nameYes) {
score = 1;
}
if (((point & POINT_FIXME) != 0) && fixmeYes) {
score = 1;
}
if (((point & POINT_BUS_NO) != 0) && !busYes) {
score = 0;
}
return score;
}
/**
*
* @param idref
* @param lat
* @param lon
* @param score
* @param name
* @return
* @throws IOException
* @throws SQLException
*/
public int insertExistingNode(String idref, double lat, double lon, int score, String name) throws IOException, SQLException {
return insertExistingNode(idref, lat, lon, score, name, false);
}
/**
*
* @param idref
* @param lat
* @param lon
* @param score
* @param name
* @param removed
* @return
* @throws IOException
* @throws SQLException
*/
public int insertExistingNode(String idref, double lat, double lon, int score, String name, boolean removed) throws IOException, SQLException {
// idref と brandStr をデータベースに格納する
/*
*/
String sql = String.format("DELETE FROM %s WHERE idref=?", tableName);
try (PreparedStatement ps5 = hsqldb.prepareStatement(sql)) {
ps5.setString(1, idref);
ps5.executeUpdate();
}
catch (HsqlException | SQLIntegrityConstraintViolationException e) {
// integrity constraint violation: unique constraint or index violation; SYS_PK_10069 table: FUEL_EXIST
// [HsqlException]は、無視する
// integrity constraint violation: unique constraint or index violation; SYS_PK_10069 table: FUEL_EXIST
// [SQLIntegrityConstraintViolationException]は、無視する
}
sql = String.format(
"INSERT INTO %s (idref,lat,lon,score,name,removed) VALUES (%s,%2.7f,%3.7f,%d,%s,%s)",
tableName,
idref, lat, lon, score, name, (removed ? "true":"false")
);
System.out.println(sql);
sql = String.format(
"INSERT INTO %s (idref,lat,lon,score,name,removed) VALUES (?,?,?,?,?,?)",
tableName
);
try (PreparedStatement ps5 = hsqldb.prepareStatement(sql)) {
ps5.setString(1, idref);
ps5.setDouble(2, lat);
ps5.setDouble(3, lon);
ps5.setInt(4, score);
ps5.setString(5, name);
ps5.setBoolean(6, removed);
ps5.executeUpdate();
return 1;
}
catch (HsqlException | SQLIntegrityConstraintViolationException e) {
// integrity constraint violation: unique constraint or index violation; SYS_PK_10069 table: FUEL_EXIST
// [HsqlException]は、無視する
// integrity constraint violation: unique constraint or index violation; SYS_PK_10069 table: FUEL_EXIST
// [SQLIntegrityConstraintViolationException]は、無視する
}
return 0;
}
/**
* REMOVEDファイルからデータを揉み込む
*
* @param revovedFile
* @throws FileNotFoundException
* @throws IOException
* @throws SQLException
*/
public void loadRemoved(File revovedFile) throws FileNotFoundException, IOException, SQLException {
if (revovedFile == null) {
throw new FileNotFoundException();
}
if (!revovedFile.exists()) {
throw new FileNotFoundException();
}
if (!revovedFile.isFile()) {
throw new FileNotFoundException();
}
try (PreparedStatement ps = hsqldb.prepareStatement(
"UPDATE "
+ tableName
+ " SET idref=?,removed=true,fixed1=100"
+ " WHERE gmlid=? AND area=?"
)) {
LineNumberReader reader = new LineNumberReader(
new InputStreamReader(new FileInputStream(revovedFile))
);
String lineStr;
while ((lineStr = reader.readLine()) != null) {
if (lineStr == null) {
continue;
}
if (lineStr.trim().length() < 3) {
continue;
}
JsonObject json = JsonTool.parse(lineStr);
String gmlid = json.getString("gmlid");
String idref = json.getString("idref");
int area = json.getInt("area");
ps.setString(1, idref);
ps.setString(2, gmlid);
ps.setInt(3, area);
ps.executeUpdate();
}
}
}
/**
* removedデータをファイルに出力する
*
* @param removedFile
* @throws SQLException
* @throws java.io.IOException
*/
public void outputRemoved(File removedFile) throws SQLException, IOException {
String whereStr = "WHERE (removed=?)";
String fromStr = "FROM "+ tableName;
String sortStr = "ORDER BY area,gmlid";
String sql = String.format("SELECT * %s %s %s", fromStr, whereStr, sortStr);
try (FileWriter fw = new FileWriter(removedFile);
PreparedStatement ps1 = hsqldb.prepareStatement(sql))
{
System.out.println(sql);
ps1.setBoolean(1, true);
try (ResultSet rset1 = ps1.executeQuery()) {
while (rset1.next()) {
String gmlid = rset1.getString("gmlid");
int area = rset1.getInt("area");
String idref = rset1.getString("idref");
JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
jsonBuilder.add("gmlid", gmlid);
jsonBuilder.add("idref", (idref==null ? "" : idref));
jsonBuilder.add("area", area);
JsonObject value = jsonBuilder.build();
String line = value.toString();
fw.write(line);
fw.write("\n");
fw.flush();
}
}
fw.close();
}
}
boolean isNull(String vstr) {
if (vstr == null) {
return true;
}
return (vstr.trim().length() < 1);
}
int readAreaNodes(Connection con, Node node) throws IOException, SQLException {
int iCounter = 0;
NodeList nodes = node.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node node2 = nodes.item(i);
switch (node2.getNodeName()) {
case "node":
iCounter++;
importAreaNode(con, node2);
break;
default:
iCounter += readAreaNodes(con, node2);
break;
}
}
return iCounter;
}
void importAreaNode(Connection con, Node node) throws IOException, SQLException {
String idrefStr = "";
String latStr = "";
String lonStr = "";
NodeList nodes = node.getChildNodes();
if (nodes.getLength() > 0) {
return;
}
NamedNodeMap nodeMap = node.getAttributes();
if (nodeMap != null) {
for (int j=0; j < nodeMap.getLength(); j++) {
switch (nodeMap.item(j).getNodeName()) {
case "id":
idrefStr = nodeMap.item(j).getNodeValue();
break;
case "lat":
latStr = nodeMap.item(j).getNodeValue();
break;
case "lon":
lonStr = nodeMap.item(j).getNodeValue();
break;
default:
break;
}
}
// idref と brandStr をデータベースに格納する
System.out.println("insert into AREA_NODE(idref,lat,lon) values("+ idrefStr +","+ latStr +","+ lonStr+")");
try (PreparedStatement ps5 = con.prepareStatement(
"INSERT INTO AREA_NODE (idref,lat,lon) VALUES (?,?,?)"
)) {
ps5.setString(1, idrefStr);
ps5.setDouble(2, Double.parseDouble(latStr));
ps5.setDouble(3, Double.parseDouble(lonStr));
ps5.executeUpdate();
}
}
}
static Position getNdPosition(Connection con, String idref) throws SQLException {
PreparedStatement ps8 = con.prepareStatement(
"SELECT lat,lon FROM AREA_NODE where idref=?"
);
ps8.setString(1, idref);
try (ResultSet rset8 = ps8.executeQuery()) {
while (rset8.next()) {
Double lat = rset8.getDouble(1);
Double lon = rset8.getDouble(2);
return new Position(lat,lon);
}
}
return null;
}
public void dropTable () throws FileNotFoundException, ClassNotFoundException, SQLException, IOException, ParserConfigurationException, SAXException {
String sqlStr = "DROP TABLE IF EXISTS "+ tableName;
try (PreparedStatement ps = hsqldb.prepareStatement(sqlStr)) {
System.out.println(sqlStr);
ps.executeUpdate();
}
}
}