jnidzwetzki/bboxdb

View on GitHub
bboxdb-tools/src/main/java/org/bboxdb/tools/converter/osm/store/OSMJDBCH2NodeStore.java

Summary

Maintainability
C
1 day
Test Coverage
/*******************************************************************************
 *
 *    Copyright (C) 2015-2022 the BBoxDB project
 *  
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License. 
 *    
 *******************************************************************************/
package org.bboxdb.tools.converter.osm.store;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.bboxdb.tools.converter.osm.util.SerializableNode;
import org.openstreetmap.osmosis.core.domain.v0_6.Node;

public class OSMJDBCH2NodeStore implements OSMNodeStore {
    
    /**
     * The H2 DB file flags
     */
    protected final static String DB_FLAGS = ";create=true";
    
    /**
     * The database connection
     */
    protected final List<Connection> connections = new ArrayList<>();
    
    /**
     * The insert node statement
     */
    protected final List<PreparedStatement> insertNodeStatements = new ArrayList<>();
    
    /**
     * The select node statement
     */
    protected final List<PreparedStatement> selectNodeStatements = new ArrayList<>();

    /**
     * The number of instances
     */
    protected int instances;

    public OSMJDBCH2NodeStore(final List<String> baseDir, final long inputLength) {
        
        // 5 instances per GB
        instances = (int) ((inputLength / (Math.pow(1024, 3)) * 5));
        System.out.println("Using DB instances: " + instances);
                
        try {            
            // Prepare DB_Instances
            for(int i = 0; i < instances; i++) {
                
                final String workfolder = baseDir.get(i % baseDir.size());
                
                final Connection connection = DriverManager.getConnection("jdbc:derby:directory:" + workfolder + "/osm_" + i + ".db" + DB_FLAGS);
                
                
                try (Statement statement = connection.createStatement()) {
                    statement.executeUpdate("DROP TABLE if exists osmnode");
                    statement.executeUpdate("CREATE TABLE osmnode (id BIGINT PRIMARY KEY, data BLOB)");
                }
                
                final PreparedStatement insertNode = connection.prepareStatement("INSERT into osmnode (id, data) values (?,?)");
                final PreparedStatement selectNode = connection.prepareStatement("SELECT data from osmnode where id = ?");
            
                insertNodeStatements.add(insertNode);
                selectNodeStatements.add(selectNode);
                
                connection.commit();
                connections.add(connection);
            }
        } catch (SQLException e) {
            throw new IllegalArgumentException(e);
        }
    }
    
    /**
     * Close all resources
     */
    public void close() {
        
        selectNodeStatements.stream().forEach(p -> {
            try {
                p.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        });
        selectNodeStatements.clear();
        
        insertNodeStatements.stream().forEach(p -> {
            try {
                p.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        });
        insertNodeStatements.clear();
        
        connections.stream().forEach(p -> {
            try {
                p.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        });
        connections.clear();
    }

    /**
     * Store a new node
     * @param node
     * @throws SQLException 
     * @throws IOException 
     */
    public void storeNode(final Node node) throws SQLException, IOException {
        
        final int connectionNumber = getDatabaseForNode(node.getId());
        final Connection connection = connections.get(connectionNumber);
        final PreparedStatement insertNode = insertNodeStatements.get(connectionNumber);
        
        final SerializableNode serializableNode = new SerializableNode(node);
        final byte[] nodeBytes = serializableNode.toByteArray();
        final InputStream is = new ByteArrayInputStream(nodeBytes);
        
        insertNode.setLong(1, node.getId());
        insertNode.setBlob(2, is);
        insertNode.execute();
        is.close();

        connection.commit();
    }

    /**
     * Get the database for nodes
     * @param node
     * @return
     */
    protected int getDatabaseForNode(final long nodeid) {
        return (int) (nodeid % instances);
    }
    
    /**
     * Get the id for the node
     * @param nodeId
     * @return
     * @throws SQLException 
     */
    public SerializableNode getNodeForId(final long nodeId) throws SQLException {
        final int connectionNumber = getDatabaseForNode(nodeId);
        final PreparedStatement selectNode = selectNodeStatements.get(connectionNumber);

        selectNode.setLong(1, nodeId);
        final ResultSet result = selectNode.executeQuery();
        
        if(! result.next()) {
            throw new RuntimeException("Unable to find node for way: " + nodeId);
        }
        
        final byte[] nodeBytes = result.getBytes(1);
        result.close();
        
        final SerializableNode node = SerializableNode.fromByteArray(nodeBytes);
        return node;
    }

    @Override
    public int getInstances() {
        return instances;
    }
}