001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/io/quadtree/DBNode.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2007 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/deegree/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 This library is free software; you can redistribute it and/or 012 modify it under the terms of the GNU Lesser General Public 013 License as published by the Free Software Foundation; either 014 version 2.1 of the License, or (at your option) any later version. 015 016 This library is distributed in the hope that it will be useful, 017 but WITHOUT ANY WARRANTY; without even the implied warranty of 018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 Lesser General Public License for more details. 020 021 You should have received a copy of the GNU Lesser General Public 022 License along with this library; if not, write to the Free Software 023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 024 025 Contact: 026 027 Andreas Poth 028 lat/lon GmbH 029 Aennchenstr. 19 030 53177 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Prof. Dr. Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: greve@giub.uni-bonn.de 041 042 ---------------------------------------------------------------------------*/ 043 package org.deegree.io.quadtree; 044 045 import java.sql.Connection; 046 import java.sql.PreparedStatement; 047 import java.sql.ResultSet; 048 import java.sql.Statement; 049 import java.util.List; 050 051 import org.deegree.framework.log.ILogger; 052 import org.deegree.framework.log.LoggerFactory; 053 import org.deegree.io.DBConnectionPool; 054 import org.deegree.io.JDBCConnection; 055 import org.deegree.model.spatialschema.Envelope; 056 import org.deegree.model.spatialschema.GeometryFactory; 057 058 /** 059 * Represents a node of a {@link DBQuadtree}. Nodes contain items which have a spatial extent 060 * corresponding to the node's position in the quadtree. 061 * 062 * 063 * @version $Revision: 7845 $ 064 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 065 * @author last edited by: $Author: apoth $ 066 * 067 * @version 1.0. $Revision: 7845 $, $Date: 2007-07-25 09:45:35 +0200 (Mi, 25 Jul 2007) $ 068 * 069 * @since 2.0 070 */ 071 class DBNode implements Node { 072 073 private static ILogger LOG = LoggerFactory.getLogger( DBNode.class ); 074 075 private String id = null; 076 077 private int level; 078 079 private String[] fk_subnode = new String[4]; 080 081 private Envelope envelope = null; 082 083 private JDBCConnection jdbc = null; 084 085 private DBQuadtree qt = null; 086 087 private String indexName = null; 088 089 /** 090 * 091 * @param id 092 * @param jdbc 093 */ 094 public DBNode( String id, Envelope env, DBQuadtree qt, String indexName, JDBCConnection jdbc, int level ) 095 throws IndexException { 096 this.id = id; 097 this.envelope = env; 098 this.jdbc = jdbc; 099 this.qt = qt; 100 this.level = level; 101 this.indexName = indexName.trim(); 102 if ( !load() ) { 103 create(); 104 } 105 } 106 107 /* 108 * (non-Javadoc) 109 * 110 * @see org.deegree.io.quadtree.Node#getId() 111 */ 112 public String getId() { 113 return id; 114 } 115 116 Envelope getEnvelope() { 117 return envelope; 118 } 119 120 /* 121 * (non-Javadoc) 122 * 123 * @see org.deegree.io.quadtree.Node#insert(java.lang.Object, 124 * org.deegree.model.spatialschema.Envelope) 125 */ 126 public void insert( Object item, Envelope itemEnv ) 127 throws IndexException { 128 if ( level != qt.getDepth() ) { 129 if ( !envelope.intersects( itemEnv ) ) { 130 System.out.println( "node envelope: " + envelope ); 131 System.out.println( "item envelope: " + itemEnv ); 132 throw new IndexException( "item envelope does not intersects node envelope" ); 133 } 134 // split the envelope of this node into four equal sized quarters 135 Envelope[] envs = split(); 136 boolean inter = false; 137 int k = 0; 138 for ( int i = 0; i < envs.length; i++ ) { 139 if ( envs[i].intersects( itemEnv ) ) { 140 k++; 141 // check which subnodes are intersected by the 142 // items envelope; just this nodes 143 // are considered for futher processing 144 if ( fk_subnode[i] == null || fk_subnode[i].trim().length() == 0 ) { 145 inter = true; 146 fk_subnode[i] = id + '_' + i; 147 } 148 Node node = qt.getFromCache( fk_subnode[i] ); 149 if ( node == null ) { 150 node = new DBNode( fk_subnode[i], envs[i], qt, indexName, jdbc, level + 1 ); 151 qt.addToCache( node ); 152 } 153 node.insert( item, itemEnv ); 154 } 155 } 156 if ( k == 4 ) { 157 assigneItem( item ); 158 } 159 qt.addToCache( this ); 160 if ( inter ) { 161 update(); 162 } 163 } else { 164 assigneItem( item ); 165 } 166 167 } 168 169 /* 170 * (non-Javadoc) 171 * 172 * @see org.deegree.io.quadtree.Node#query(org.deegree.model.spatialschema.Envelope, 173 * java.util.List, int) 174 */ 175 public List<Object> query( Envelope searchEnv, List<Object> visitor, int level ) 176 throws IndexException { 177 /* 178 * if ( level == qt.getDepth() || (searchEnv.getWidth() > envelope.getWidth() || 179 * searchEnv.getHeight() > envelope.getHeight()) ) { addAssignedItems( visitor ); } else { 180 */ 181 addAssignedItems( visitor ); 182 if ( level != qt.getDepth() ) { 183 Envelope[] envs = split(); 184 for ( int i = 0; i < envs.length; i++ ) { 185 if ( fk_subnode[i] != null && envs[i].intersects( searchEnv ) ) { 186 // check which subnodes are intersected by the 187 // items envelope; just this nodes 188 // are considered for futher processing 189 Node node = new DBNode( fk_subnode[i], envs[i], qt, indexName, jdbc, level + 1 ); 190 node.query( searchEnv, visitor, level + 1 ); 191 } 192 } 193 } 194 return visitor; 195 } 196 197 /* 198 * (non-Javadoc) 199 * 200 * @see org.deegree.io.quadtree.Node#deleteItem(java.lang.Object) 201 */ 202 public void deleteItem( Object item ) { 203 if ( level == qt.getDepth() ) { 204 205 } else { 206 207 } 208 } 209 210 /* 211 * (non-Javadoc) 212 * 213 * @see org.deegree.io.quadtree.Node#deleteRange(org.deegree.model.spatialschema.Envelope) 214 */ 215 public void deleteRange( Envelope envelope ) { 216 if ( level == qt.getDepth() ) { 217 218 } else { 219 220 } 221 } 222 223 /** 224 * load all parameter from of node from the database returns true is a node with current ID is 225 * already available from the database 226 * 227 */ 228 private boolean load() 229 throws IndexException { 230 Connection con = null; 231 DBConnectionPool pool = null; 232 boolean available = true; 233 try { 234 pool = DBConnectionPool.getInstance(); 235 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 236 237 StringBuffer sb = new StringBuffer( 100 ); 238 sb.append( "Select * from " ).append( indexName ); 239 sb.append( " where ID = '" ).append( id ).append( "'" ); 240 241 Statement stmt = con.createStatement(); 242 ResultSet rs = stmt.executeQuery( sb.toString() ); 243 if ( rs.next() ) { 244 double minx = rs.getFloat( "MINX" ); 245 double miny = rs.getFloat( "MINY" ); 246 double maxx = rs.getFloat( "MAXX" ); 247 double maxy = rs.getFloat( "MAXY" ); 248 envelope = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, null ); 249 fk_subnode[0] = rs.getString( "FK_SUBNODE1" ); 250 fk_subnode[1] = rs.getString( "FK_SUBNODE2" ); 251 fk_subnode[2] = rs.getString( "FK_SUBNODE3" ); 252 fk_subnode[3] = rs.getString( "FK_SUBNODE4" ); 253 } else { 254 available = false; 255 } 256 rs.close(); 257 stmt.close(); 258 } catch ( Exception e ) { 259 LOG.logError( e.getMessage(), e ); 260 throw new IndexException( "could not load node definition from database", e ); 261 } finally { 262 try { 263 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 264 } catch ( Exception e1 ) { 265 e1.printStackTrace(); 266 } 267 } 268 return available; 269 } 270 271 /** 272 * updates the database representation of the current node 273 * 274 * @throws IndexException 275 */ 276 private void update() 277 throws IndexException { 278 Connection con = null; 279 DBConnectionPool pool = null; 280 try { 281 pool = DBConnectionPool.getInstance(); 282 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 283 284 StringBuffer sb = new StringBuffer( 100 ); 285 sb.append( "UPDATE " ).append( indexName ).append( " set " ); 286 boolean sub = false; 287 for ( int i = 0; i < fk_subnode.length; i++ ) { 288 if ( fk_subnode[i] != null ) { 289 sb.append( " FK_SUBNODE" ).append( i + 1 ).append( "='" ); 290 sb.append( fk_subnode[i] ).append( "' ," ); 291 sub = true; 292 } 293 } 294 if ( sub ) { 295 // just execute update if at least one sub node != null 296 sb = new StringBuffer( sb.substring( 0, sb.length() - 1 ) ); 297 sb.append( " where ID = '" ).append( id ).append( "'" ); 298 Statement stmt = con.createStatement(); 299 stmt.execute( sb.toString() ); 300 stmt.close(); 301 } 302 } catch ( Exception e ) { 303 LOG.logError( e.getMessage(), e ); 304 throw new IndexException( "could not update node definition at database " + "for node: " + id, e ); 305 } finally { 306 try { 307 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 308 } catch ( Exception e1 ) { 309 e1.printStackTrace(); 310 } 311 } 312 } 313 314 /** 315 * creates a new node with current ID and envelope 316 * 317 * @throws IndexException 318 */ 319 void create() 320 throws IndexException { 321 Connection con = null; 322 DBConnectionPool pool = null; 323 try { 324 pool = DBConnectionPool.getInstance(); 325 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 326 327 StringBuffer sb = new StringBuffer( 100 ); 328 sb.append( "INSERT INTO " ).append( indexName ); 329 sb.append( " ( ID, MINX, MINY, MAXX , MAXY ) " ); 330 sb.append( "VALUES ( ?, ?, ?, ?, ? ) " ); 331 PreparedStatement stmt = con.prepareStatement( sb.toString() ); 332 stmt.setString( 1, id ); 333 stmt.setFloat( 2, (float) envelope.getMin().getX() ); 334 stmt.setFloat( 3, (float) envelope.getMin().getY() ); 335 stmt.setFloat( 4, (float) envelope.getMax().getX() ); 336 stmt.setFloat( 5, (float) envelope.getMax().getY() ); 337 stmt.execute(); 338 stmt.close(); 339 } catch ( Exception e ) { 340 LOG.logError( e.getMessage(), e ); 341 throw new IndexException( "could not create node definition at database", e ); 342 } finally { 343 try { 344 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 345 } catch ( Exception e1 ) { 346 e1.printStackTrace(); 347 } 348 } 349 } 350 351 /** 352 * assignes an item to a node by creating a new row in the JT_QTNODE_ITEM table 353 * 354 * @param Item 355 */ 356 private void assigneItem( Object item ) 357 throws IndexException { 358 Connection con = null; 359 DBConnectionPool pool = null; 360 try { 361 pool = DBConnectionPool.getInstance(); 362 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 363 364 StringBuffer sb = new StringBuffer( 100 ); 365 sb.append( "INSERT INTO " ).append( indexName.trim() ).append( "_ITEM " ); 366 sb.append( "( FK_QTNODE, FK_ITEM ) " ).append( "VALUES ( ?, ? ) " ); 367 PreparedStatement stmt = con.prepareStatement( sb.toString() ); 368 stmt.setString( 1, id ); 369 if ( item instanceof Integer ) { 370 stmt.setInt( 2, (Integer) item ); 371 } else { 372 stmt.setString( 2, item.toString() ); 373 } 374 stmt.execute(); 375 stmt.close(); 376 } catch ( Exception e ) { 377 LOG.logError( e.getMessage(), e ); 378 throw new IndexException( "could not create node definition at database", e ); 379 } finally { 380 try { 381 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 382 } catch ( Exception e1 ) { 383 e1.printStackTrace(); 384 } 385 } 386 } 387 388 /** 389 * adds all item(IDs) assigned to this node 390 * 391 * @param visitor 392 * @return 393 * @throws IndexException 394 */ 395 private List addAssignedItems( List<Object> visitor ) 396 throws IndexException { 397 398 Connection con = null; 399 DBConnectionPool pool = null; 400 try { 401 pool = DBConnectionPool.getInstance(); 402 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 403 404 StringBuffer sb = new StringBuffer( 100 ); 405 sb.append( "SELECT DISTINCT FK_ITEM from " ).append( indexName ).append( "_ITEM" ); 406 sb.append( " where " ).append( "FK_QTNODE = '" ).append( id ).append( "'" ); 407 Statement stmt = con.createStatement(); 408 ResultSet rs = stmt.executeQuery( sb.toString() ); 409 while ( rs.next() ) { 410 Object s = rs.getObject( 1 ); 411 if ( !visitor.contains( s ) ) { 412 visitor.add( s ); 413 } 414 } 415 stmt.close(); 416 } catch ( Exception e ) { 417 LOG.logError( e.getMessage(), e ); 418 throw new IndexException( "could not create node definition at database", e ); 419 } finally { 420 try { 421 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 422 } catch ( Exception e1 ) { 423 e1.printStackTrace(); 424 } 425 } 426 427 return visitor; 428 } 429 430 private Envelope[] split() { 431 Envelope[] envs = new Envelope[4]; 432 double nW = envelope.getWidth() / 2d; 433 double nH = envelope.getHeight() / 2d; 434 435 envs[0] = GeometryFactory.createEnvelope( envelope.getMin().getX(), envelope.getMin().getY(), 436 envelope.getMin().getX() + nW, envelope.getMin().getY() + nH, null ); 437 envs[1] = GeometryFactory.createEnvelope( envelope.getMin().getX() + nW, envelope.getMin().getY(), 438 envelope.getMin().getX() + ( 2 * nW ), envelope.getMin().getY() + nH, 439 null ); 440 envs[2] = GeometryFactory.createEnvelope( envelope.getMin().getX() + nW, envelope.getMin().getY() + nH, 441 envelope.getMin().getX() + ( 2 * nW ), envelope.getMin().getY() 442 + ( 2 * nH ), null ); 443 envs[3] = GeometryFactory.createEnvelope( envelope.getMin().getX(), envelope.getMin().getY() + nH, 444 envelope.getMin().getX() + nW, envelope.getMin().getY() + ( 2 * nH ), 445 null ); 446 447 return envs; 448 } 449 450 }