001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/io/quadtree/DBQuadtree.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 package org.deegree.io.quadtree; 037 038 import java.sql.Connection; 039 import java.sql.ResultSet; 040 import java.sql.SQLException; 041 import java.sql.Statement; 042 import java.util.ArrayList; 043 import java.util.HashMap; 044 import java.util.List; 045 import java.util.Map; 046 047 import org.deegree.framework.log.ILogger; 048 import org.deegree.framework.log.LoggerFactory; 049 import org.deegree.io.DBConnectionPool; 050 import org.deegree.io.DBPoolException; 051 import org.deegree.io.JDBCConnection; 052 import org.deegree.model.spatialschema.Envelope; 053 import org.deegree.model.spatialschema.GeometryFactory; 054 import org.deegree.model.spatialschema.Point; 055 056 /** 057 * 058 * 059 * 060 * @version $Revision: 18195 $ 061 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 062 * @author last edited by: $Author: mschneider $ 063 * 064 * @version 1.0. $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $ 065 * @param <T> 066 * the datatype to be used as id 067 * 068 * @since 2.0 069 */ 070 public class DBQuadtree<T> implements Quadtree<T> { 071 072 private static ILogger LOG = LoggerFactory.getLogger( DBQuadtree.class ); 073 074 private String fk_root; 075 076 private int depth; 077 078 private int id = 0; 079 080 private String indexName = null; 081 082 private JDBCConnection jdbc = null; 083 084 private Map<String, DBNode<T>> nodeCache = new HashMap<String, DBNode<T>>( 10000 ); 085 086 private double accuracyX; 087 088 private double accuracyY; 089 090 private DBQuadtree.SupportedVersions version; 091 092 private Connection con = null; 093 094 private DBConnectionPool pool = null; 095 096 /** 097 * The <code>SupportedVersions</code> supported by this quatree 098 * 099 */ 100 public static enum SupportedVersions { 101 /** 102 * the old version or 1.0.0 103 */ 104 ONE, 105 /** 106 * The new version or "2.0.0" 107 */ 108 TWO 109 } 110 111 /** 112 * Creates a Database with given version. 113 * 114 * @param id 115 * of the table which contains the features. 116 * @param indexName 117 * this name will be used to create the table that stores the nodes of a specific 118 * quadtree 119 * @param jdbc 120 * description of database connection 121 * @param version 122 * of the quadtree, which is usefull for the determination of the layout, if null 123 * then the version is assumed to be unknown and the old layout is used. 124 * @throws IndexException 125 */ 126 public DBQuadtree( int id, String indexName, JDBCConnection jdbc, String version ) throws IndexException { 127 this( id, indexName, jdbc, 0.0001, 0.0001, version ); 128 } 129 130 /** 131 * initializes a quadtree already existing in a database. New items will have a slightly larger 132 * bbox with 0.0001 added to each boundary, this is usefull for point geometries. 133 * 134 * @param id 135 * of the table which contains the features. 136 * @param indexName 137 * this name will be used to create the table that stores the nodes of a specific 138 * quadtree 139 * @param jdbc 140 * description of database connection 141 * @throws IndexException 142 * if the quadtree node with 'id' could not be read from the database. 143 */ 144 public DBQuadtree( int id, String indexName, JDBCConnection jdbc ) throws IndexException { 145 this( id, indexName, jdbc, 0.0001, 0.0001, "1.0.0" ); 146 } 147 148 /** 149 * initializes a quadtree already existing in a database 150 * 151 * @param id 152 * of the table which contains the features. 153 * @param indexName 154 * this name will be used to create the table that stores the nodes of a specific 155 * quadtree 156 * @param jdbc 157 * description of database connection 158 * @param accuracyX 159 * @param accuracyY 160 * @param version 161 * of the quadtree, which is usefull for the determination of the layout, if null 162 * then the version is assumed to be "1.0.0" (the first version) and the old layout 163 * is used. 164 * @throws IndexException 165 * if the quadtree node with 'id' could not be read from the database. 166 */ 167 public DBQuadtree( int id, String indexName, JDBCConnection jdbc, double accuracyX, double accuracyY, String version ) 168 throws IndexException { 169 this.id = id; 170 this.jdbc = jdbc; 171 this.indexName = indexName; 172 this.accuracyX = accuracyX; 173 this.accuracyY = accuracyY; 174 pool = DBConnectionPool.getInstance(); 175 try { 176 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 177 } catch ( DBPoolException e ) { 178 String msg = "Could not acquire a database connection for the quadtree, no possibility to go on!"; 179 LOG.logError( msg + " Cause: " + e.getMessage() ); 180 throw new IndexException( msg, e ); 181 } 182 183 if ( version == null || !"2.0.0".equals( version.trim() ) ) { 184 this.version = SupportedVersions.ONE; 185 } else { 186 this.version = SupportedVersions.TWO; 187 } 188 readRootNodeId(); 189 } 190 191 /** 192 * 193 * @param id 194 * @return node 195 */ 196 DBNode<T> getFromCache( String id ) { 197 return nodeCache.get( id ); 198 } 199 200 /** 201 * 202 * @param node 203 */ 204 void addToCache( DBNode<T> node ) { 205 nodeCache.put( node.getId(), node ); 206 } 207 208 /** 209 * 210 * @param node 211 */ 212 DBNode<T> removeFromCache( DBNode<T> node ) { 213 return nodeCache.remove( node.getId() ); 214 } 215 216 /** 217 * inserts a new item into a quadtree 218 * 219 * @param item 220 * @param envelope 221 */ 222 public void insert( T item, Envelope envelope ) 223 throws IndexException { 224 DBNode<T> node = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version ); 225 node.insert( item, envelope ); 226 } 227 228 /** 229 * @param item 230 * @param point 231 */ 232 public void insert( T item, Point point ) 233 throws IndexException { 234 DBNode<T> node = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version ); 235 Envelope envelope = GeometryFactory.createEnvelope( point.getX() - accuracyX, point.getY() - accuracyY, 236 point.getX() + accuracyX, point.getY() + accuracyY, null ); 237 node.insert( item, envelope ); 238 } 239 240 /** 241 * 242 * @param envelope 243 * @return list a items intersecting with the passed envelope 244 */ 245 public List<T> query( Envelope envelope ) 246 throws IndexException { 247 LOG.logDebug( "Performing query for envelope: " + envelope ); 248 // Thread.dumpStack(); 249 List<T> visitor = new ArrayList<T>( 1000 ); 250 DBNode<T> node = new DBNode<T>( fk_root, null, this, indexName, jdbc, 1, version ); 251 envelope = envelope.createIntersection( node.getEnvelope() ); 252 if ( envelope == null ) { 253 LOG.logDebug( "Found no intersection with the root element of the quadtree, returning an emtpy feature collection." ); 254 return new ArrayList<T>(); 255 } 256 return node.query( envelope, visitor, 1 ); 257 } 258 259 /** 260 * deletes an item from a quadtree 261 * 262 * @param item 263 */ 264 public void deleteItem( T item ) 265 throws IndexException { 266 DBNode<T> root = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version ); 267 root.delete( item, root.getEnvelope() ); 268 } 269 270 /** 271 * updates the envelope of an item 272 * 273 * @param item 274 * @param newBBox 275 */ 276 public void update( T item, Envelope newBBox ) 277 throws IndexException { 278 Node<T> root = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version ); 279 root.update( item, newBBox ); 280 } 281 282 public void deleteRange( Envelope envelope ) { 283 throw new UnsupportedOperationException(); 284 // TODO 285 // and even more magic 286 } 287 288 /** 289 * @return depth of a quadtree 290 */ 291 public int getDepth() { 292 return depth; 293 } 294 295 /** 296 * @return true if the db connection could be released to the pool, false otherwise. 297 */ 298 public boolean releaseConnection() { 299 try { 300 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 301 } catch ( DBPoolException e ) { 302 LOG.logError( "Could not release database connection because: " + e.getMessage() ); 303 return false; 304 } 305 return true; 306 } 307 308 /** 309 * reads the root node from the database 310 * 311 * @throws IndexException 312 * if the database could not be loaded or no quadtree rootnode was found. 313 */ 314 private void readRootNodeId() 315 throws IndexException { 316 317 try { 318 StringBuffer sb = new StringBuffer( 200 ); 319 sb.append( "Select FK_ROOT, DEPTH from TAB_QUADTREE where ID = " ); 320 sb.append( id ); 321 322 Statement stmt = con.createStatement(); 323 ResultSet rs = stmt.executeQuery( sb.toString() ); 324 if ( rs.next() ) { 325 fk_root = rs.getString( "FK_ROOT" ); 326 depth = rs.getInt( "DEPTH" ); 327 } else { 328 throw new IndexException( "Could not read FK_ROOT and DEPTH for Quadtree with ID" + id ); 329 } 330 rs.close(); 331 stmt.close(); 332 } catch ( SQLException e ) { 333 throw new IndexException( "Could not load quadtree definition from database because: " + e.getMessage() ); 334 } 335 336 } 337 338 /** 339 * @return envelope of a quadtree's root node 340 */ 341 public Envelope getRootBoundingBox() 342 throws IndexException { 343 DBNode<T> root = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version ); 344 return root.getEnvelope(); 345 } 346 347 }