package osm.jp.api; 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 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; public abstract class Osmdb { public static final String TABLE_NAME = "OSM_EXIST"; /* public static void main(String[] args) throws MalformedURLException, ProtocolException, IOException { double minlat = 35.13d; double maxlat = 35.66d; double minlon = 138.99d; double maxlon = 139.79d; //getCapabilities(new File("output.xml"), "highway", "bus_stop", minlat, maxlat, minlon, maxlon); //getCapabilities(new File("output.xml"), "highway", "disused:bus_stop", minlat, maxlat, minlon, maxlon); //getCapabilities(new File("output.xml"), "amenity", "bus_station", minlat, maxlat, minlon, maxlon); //getCapabilities(new File("output.xml"), "public_transport", "platform", minlat, maxlat, minlon, maxlon); getCapabilities("public_transport", "stop_position", minlat, maxlat, minlon, maxlon, "node"); getCapabilities("amenity", "fuel", minlat, maxlat, minlon, maxlon, "way"); } */ /** * 'HSQLDB.table.OSM_EXIST'を新規に作る * 'HSQLDB.table.AREA_NODE'を新規に作る * 既にテーブルが存在する時にはERROR * @param con * @throws SQLException */ public static void create(Connection con) throws SQLException { String createSt; sql(con, "DROP TABLE IF EXISTS "+ Osmdb.TABLE_NAME +" CASCADE"); sql(con, "DROP INDEX IF EXISTS "+ Osmdb.TABLE_NAME +"_index;"); sql(con, "DROP TABLE IF EXISTS AREA_NODE CASCADE"); // 'table.OSM_EXIST'を新規に作る createSt = "CREATE TABLE "+ Osmdb.TABLE_NAME +" (idref VARCHAR(12) NOT NULL, name VARCHAR(128), lat DOUBLE, lon DOUBLE, score INT, PRIMARY KEY(idref));"; Db.updateSQL(con, createSt); createSt = "CREATE INDEX "+ Osmdb.TABLE_NAME +"_index ON "+ Osmdb.TABLE_NAME +" (lat, lon);"; Db.updateSQL(con, createSt); // 'table.AREA_NODE'を新規に作る createSt = "CREATE TABLE AREA_NODE (idref VARCHAR(12) NOT NULL, pid VARCHAR(12), lat DOUBLE, lon DOUBLE);"; Db.updateSQL(con, createSt); } static void sql(Connection con, String sql) throws SQLException { System.out.println(sql); try (PreparedStatement ps = con.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形式にして標準出力に出力する * @param hsqldb * @throws java.sql.SQLException */ public static void export(Connection hsqldb) throws SQLException { String header = "idref,lat,lon,score"; System.out.println("TABLE: "+ TABLE_NAME); System.out.println(header); PreparedStatement ps8 = hsqldb.prepareStatement("SELECT idref,lat,lon,score FROM "+ TABLE_NAME); 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); System.out.println("OSM: "+ idcode +","+ lat +","+ lon +","+ score); } } } public int importExistingNode(Connection hsqldb, Connection osmdb, ResultSet rset, int point) 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 "+ TABLE_NAME +" (idref,lat,lon,score,name) VALUES ("+ osmidStr +","+ latStr +","+ lonStr+","+ Integer.toString(score) +",'"+ nameStr +"')N"); try (PreparedStatement ps5 = hsqldb.prepareStatement("INSERT INTO "+ TABLE_NAME +" (idref,lat,lon,score,name) 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.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 hsqldb 反映先のデータベースコネクタ(HSQLDB) * @param sqlWhere POI条件 * @param point 評価ポイント[POINT_NO|POINT_BRAND|POINT_NAME] 1: 'brand' 2:'name' * @throws Exception エラー */ public void readExisting(Connection hsqldb, String sqlWhere, int point) throws Exception { Connection osmdb = null; long counter = 0L; try { 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); System.out.println(sqlNode); PreparedStatement ps1 = osmdb.prepareStatement(sqlNode); try (ResultSet rset1 = ps1.executeQuery()) { while (rset1.next()) { counter += importExistingNode(hsqldb, osmdb, rset1, point); } } sqlSelect = "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"; String sqlArea = String.format("SELECT %s FROM planet_osm_polygon %s", sqlSelect, sqlWhere); System.out.println(sqlArea); PreparedStatement ps2 = osmdb.prepareStatement(sqlArea); try (ResultSet rset2 = ps2.executeQuery()) { while (rset2.next()) { counter += importExistingNode(hsqldb, osmdb, rset2, point); } } System.out.println("Exists Node count = " + counter); } finally { DatabaseTool.closeDb(osmdb); } } /** * * 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 hsqldb * @param kStr * @param vStr * @param point * @throws Exception */ public void readExistingSub(Connection hsqldb, String kStr, String vStr, int point) throws Exception { Connection osmdb = null; long counter = 0L; try { 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))", kStr, vStr); 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 += importExistingNode(hsqldb, osmdb, rset1, point); counter += insertExistingNode(hsqldb, idref, lat, lon, score, ""); } } System.out.println("Exists Node count = " + counter); } finally { DatabaseTool.closeDb(osmdb); } } 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 hsqldb * @param idref * @param lat * @param lon * @param score * @param name * @return * @throws IOException * @throws SQLException */ public int insertExistingNode(Connection hsqldb, String idref, double lat, double lon, int score, String name) throws IOException, SQLException { // idref と brandStr をデータベースに格納する String sql = String.format("INSERT INTO %s (idref,lat,lon,score,name) VALUES (%s,%2.7f,%3.7f,%d,%s)", TABLE_NAME, idref, lat, lon, score, name); System.out.println(sql); sql = String.format("INSERT INTO %s (idref,lat,lon,score,name) VALUES (?,?,?,?,?)", TABLE_NAME); 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.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; } 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(); } } } void importExistingArea(Connection con, Node node, int point) throws IOException, SQLException { String idrefStr = ""; double maxlat = -90.0D; double maxlon = -180.0D; double minlat = 90.0D; double minlon = 180.0D; String nameStr = ""; String brandStr = ""; String fixmeStr = ""; 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; default: break; } } NodeList nodes = node.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node2 = nodes.item(i); if (node2.getNodeName().equals("tag")) { OsmnodeTag tagnode = new OsmnodeTag(node2); String value = tagnode.getValue("brand"); if (value != null) { brandStr = value; } value = tagnode.getValue("name:ja"); if (value != null) { nameStr = value; } value = tagnode.getValue("name"); if (value != null) { nameStr = value; } value = tagnode.getValue("fixme"); if (value != null) { fixmeStr = value; } } else if (node2.getNodeName().equals("nd")) { OsmnodeNd ndnode = new OsmnodeNd(node2); String ref = ndnode.getRef(); Position pos = getNdPosition(con, ref); if (pos != null) { minlat = (pos.lat < minlat ? pos.lat : minlat); minlon = (pos.lon < minlon ? pos.lon : minlon); maxlat = (pos.lat > maxlat ? pos.lat : maxlat); maxlon = (pos.lon > maxlon ? pos.lon : maxlon); } } } if ((maxlat != -90.0D) && (maxlon != -180.0D) && (minlon != 180.0D) && (minlat != 90.0D)) { double lat = (maxlat + minlat) / 2; double lon = (maxlon + minlon) / 2; int score = 50; if (((point & POINT_NO_BRAND) != 0) && brandStr.equals("")) { score = 1; } if (((point & POINT_NO_NAME) != 0) && nameStr.equals("")) { score = 1; } if (((point & POINT_FIXME) != 0) && !fixmeStr.equals("")) { score = 1; } // idref と nameStr をデータベースに格納する System.out.println("INSERT INTO "+ TABLE_NAME +" (idref,lat,lon,score,name) VALUES("+ idrefStr +","+ lat +","+ lon+","+ Integer.toString(score) +",'"+ nameStr +"');"); try (PreparedStatement ps5 = con.prepareStatement("INSERT INTO "+ TABLE_NAME +" (idref,lat,lon,score,name) VALUES (?,?,?,?,?)")) { ps5.setString(1, idrefStr); ps5.setDouble(2, lat); ps5.setDouble(3, lon); ps5.setInt(4, score); ps5.setString(5, nameStr); 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]は、無視する } } } } 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; } }