001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/io/quadtree/DBQuadtreeManager.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2006 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 53115 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.io.IOException; 046 import java.io.StringReader; 047 import java.sql.Connection; 048 import java.sql.Date; 049 import java.sql.PreparedStatement; 050 import java.sql.ResultSet; 051 import java.sql.Statement; 052 import java.util.UUID; 053 054 import org.deegree.datatypes.Types; 055 import org.deegree.framework.log.ILogger; 056 import org.deegree.framework.log.LoggerFactory; 057 import org.deegree.framework.util.StringTools; 058 import org.deegree.io.DBConnectionPool; 059 import org.deegree.io.JDBCConnection; 060 import org.deegree.io.shpapi.ShapeFile; 061 import org.deegree.model.feature.Feature; 062 import org.deegree.model.feature.schema.FeatureType; 063 import org.deegree.model.feature.schema.PropertyType; 064 import org.deegree.model.spatialschema.Envelope; 065 import org.deegree.model.spatialschema.GMLGeometryAdapter; 066 import org.deegree.model.spatialschema.Geometry; 067 import org.deegree.model.spatialschema.GeometryFactory; 068 import org.deegree.model.spatialschema.Point; 069 070 /** 071 * Access control to a quadtree for managing spatial indizes stored in a 072 * usual database. 073 * 074 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 075 * @author last edited by: $Author: apoth $ 076 * 077 * @version $Revision: 7786 $, $Date: 2007-07-19 09:37:19 +0200 (Do, 19 Jul 2007) $ 078 */ 079 public class DBQuadtreeManager { 080 081 private static final ILogger LOG = LoggerFactory.getLogger( DBQuadtreeManager.class ); 082 083 protected JDBCConnection jdbc = null; 084 085 protected String table = null; 086 087 protected String column = null; 088 089 protected String owner = null; 090 091 protected String indexName = null; 092 093 protected int maxDepth = 6; 094 095 protected Quadtree qt = null; 096 097 protected Envelope envelope = null; 098 099 protected String backend = null; 100 101 /** 102 * 103 */ 104 protected void checkForBackend() { 105 String driver = jdbc.getDriver(); 106 // find out which database is used 107 if ( driver.toUpperCase().indexOf( "POSTGRES" ) > -1 ) { 108 backend = "POSTGRES"; 109 } else if ( driver.toUpperCase().indexOf( "SQLSERVER" ) > -1 ) { 110 backend = "SQLSERVER"; 111 } else if ( driver.toUpperCase().indexOf( "INGRES" ) > -1 112 || driver.equals( "ca.edbc.jdbc.EdbcDriver" ) ) { 113 backend = "INGRES"; 114 } else if ( driver.toUpperCase().indexOf( "HSQLDB" ) > -1 ) { 115 backend = "HSQLDB"; 116 } else { 117 backend = "GENERICSQL"; 118 } 119 } 120 121 /** 122 * @param jdbc 123 * database connection info 124 * @param indexName 125 * this name will be used to create the table that stores the nodes of a specific 126 * quadtree 127 * @param table 128 * name of table the index shall be created for 129 * @param column 130 * name of column the index shall be created for 131 * @param owner 132 * owner of the table (optional, database user will be used if set to null ) 133 * @param maxDepth 134 * max depth of the generated quadtree (default = 6 if a value < 2 will be passed) 135 */ 136 public DBQuadtreeManager( JDBCConnection jdbc, String indexName, String table, String column, 137 String owner, int maxDepth ) { 138 this.jdbc = jdbc; 139 this.table = table.trim(); 140 this.column = column.trim(); 141 this.indexName = indexName.trim(); 142 if ( owner == null ) { 143 this.owner = jdbc.getUser(); 144 } else { 145 this.owner = owner; 146 } 147 if ( maxDepth > 1 ) { 148 this.maxDepth = maxDepth; 149 } 150 151 checkForBackend(); 152 153 createIndexTable( indexName ); 154 } 155 156 /** 157 * 158 * @param driver 159 * database connection driver 160 * @param logon 161 * database connection logon 162 * @param user 163 * database user 164 * @param password 165 * database user's password 166 * @param encoding 167 * character encoding to be used (if possible) 168 * @param indexName 169 * this name will be used to create the table that stores the nodes of a specific 170 * quadtree 171 * @param table 172 * name of table the index shall be created for 173 * @param column 174 * name of column the index shall be created for 175 * @param owner 176 * owner of the table (optional, database user will be used if set to null ) 177 * @param maxDepth 178 * max depth of the generated quadtree (default = 6 if a value < 2 will be passed) 179 */ 180 public DBQuadtreeManager( String driver, String logon, String user, String password, 181 String encoding, String indexName, String table, String column, 182 String owner, int maxDepth ) { 183 jdbc = new JDBCConnection( driver, logon, user, password, null, encoding, null ); 184 this.table = table.trim(); 185 this.column = column.trim(); 186 this.indexName = indexName.trim(); 187 if ( owner == null ) { 188 this.owner = user; 189 } else { 190 this.owner = owner; 191 } 192 if ( maxDepth > 1 ) { 193 this.maxDepth = maxDepth; 194 } 195 196 checkForBackend(); 197 198 createIndexTable( indexName ); 199 } 200 201 /** 202 * initializes a QuadtreeManager to access an alread existing Quadtree 203 * 204 * @param jdbc 205 * database connection info 206 * @param table 207 * name of table the index shall be created for 208 * @param column 209 * name of column the index shall be created for 210 * @param owner 211 * owner of the table (optional, database user will be used if set to null ) 212 */ 213 public DBQuadtreeManager( JDBCConnection jdbc, String table, String column, String owner ) { 214 this.jdbc = jdbc; 215 this.table = table.trim(); 216 this.column = column.trim(); 217 if ( owner == null ) { 218 this.owner = jdbc.getUser(); 219 } else { 220 this.owner = owner; 221 } 222 223 checkForBackend(); 224 } 225 226 /** 227 * initializes a QuadtreeManager to access an alread existing Quadtree 228 * 229 * @param driver 230 * database connection driver 231 * @param logon 232 * database connection logon 233 * @param user 234 * database user 235 * @param password 236 * database user's password 237 * @param encoding 238 * character encoding to be used (if possible) 239 * @param table 240 * name of table the index shall be created for 241 * @param column 242 * name of column the index shall be created for 243 * @param owner 244 * owner of the table (optional, database user will be used if set to null ) 245 */ 246 public DBQuadtreeManager( String driver, String logon, String user, String password, 247 String encoding, String table, String column, String owner ) { 248 jdbc = new JDBCConnection( driver, logon, user, password, null, encoding, null ); 249 this.table = table.trim(); 250 this.column = column.trim(); 251 if ( owner == null ) { 252 this.owner = user; 253 } else { 254 this.owner = owner; 255 } 256 257 checkForBackend(); 258 } 259 260 /** 261 * loads the metadata of a Index from the TAB_DEEGREE_IDX table 262 * 263 * @return FK to the index 264 * @throws IndexException 265 */ 266 private int loadIndexMetadata() 267 throws IndexException { 268 int fk_indexTree = -1; 269 Connection con = null; 270 DBConnectionPool pool = null; 271 try { 272 pool = DBConnectionPool.getInstance(); 273 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 274 jdbc.getPassword() ); 275 276 StringBuffer sb = new StringBuffer( 200 ); 277 sb.append( "Select INDEX_NAME, FK_INDEXTREE from TAB_DEEGREE_IDX where " ); 278 sb.append( "column_name = '" ).append( column ).append( "' AND " ); 279 sb.append( "table_name = '" ).append( table ).append( "' AND " ); 280 sb.append( "owner = '" ).append( owner ).append( "'" ); 281 282 Statement stmt = con.createStatement(); 283 ResultSet rs = stmt.executeQuery( sb.toString() ); 284 285 if ( rs.next() ) { 286 indexName = rs.getString( "INDEX_NAME" ); 287 fk_indexTree = rs.getInt( "FK_INDEXTREE" ); 288 } else { 289 throw new IndexException( "could not read index metadata" ); 290 } 291 rs.close(); 292 stmt.close(); 293 } catch ( Exception e ) { 294 throw new IndexException( "could not load quadtree definition from database", e ); 295 } finally { 296 try { 297 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 298 jdbc.getPassword() ); 299 } catch ( Exception e1 ) { 300 e1.printStackTrace(); 301 } 302 } 303 return fk_indexTree; 304 } 305 306 /** 307 * returns the current Quadtree 308 * 309 * @return the current Quadtree 310 * @throws IndexException 311 */ 312 public Quadtree getQuadtree() 313 throws IndexException { 314 if ( qt == null ) { 315 qt = loadQuadtree(); 316 } 317 return qt; 318 } 319 320 /** 321 * loads an already existing quadtree 322 * 323 * @return 324 * @throws IndexException 325 */ 326 protected Quadtree loadQuadtree() 327 throws IndexException { 328 int fk_index = loadIndexMetadata(); 329 return new DBQuadtree( fk_index, indexName, jdbc ); 330 } 331 332 /** 333 * stores one feature into the defined table 334 * 335 * @param feature 336 * @param jdbc 337 * @throws Exception 338 */ 339 private void storeFeature( Feature feature, String id, JDBCConnection jdbc ) 340 throws Exception { 341 342 Connection con = null; 343 DBConnectionPool pool = null; 344 345 FeatureType ft = feature.getFeatureType(); 346 PropertyType[] ftp = ft.getProperties(); 347 try { 348 pool = DBConnectionPool.getInstance(); 349 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 350 jdbc.getPassword() ); 351 352 StringBuffer sb = new StringBuffer( 100 ); 353 sb.append( "INSERT INTO " ).append( table ).append( '(' ); 354 sb.append( "FEATURE_ID," ); 355 for ( int i = 0; i < ftp.length; i++ ) { 356 if ( ftp[i].getType() == Types.GEOMETRY ) { 357 sb.append( column ).append( ' ' ); 358 } else { 359 sb.append( ftp[i].getName().getLocalName() ); 360 } 361 if ( i < ftp.length - 1 ) { 362 sb.append( ", " ); 363 } 364 } 365 sb.append( ") VALUES (?," ); 366 for ( int i = 0; i < ftp.length; i++ ) { 367 sb.append( '?' ); 368 if ( i < ftp.length - 1 ) { 369 sb.append( ", " ); 370 } 371 } 372 sb.append( ')' ); 373 LOG.logDebug( "SQL for inser feature: " + sb ); 374 375 PreparedStatement stmt = con.prepareStatement( sb.toString() ); 376 stmt.setString( 1, id ); 377 for ( int i = 0; i < ftp.length; i++ ) { 378 Object o = null; 379 if ( feature.getProperties( ftp[i].getName() ) != null ) { 380 if ( feature.getProperties( ftp[i].getName() ).length > 0 ) { 381 o = feature.getProperties( ftp[i].getName() )[0].getValue(); 382 } 383 } 384 if ( o == null ) { 385 stmt.setNull( i + 2, ftp[i].getType() ); 386 } else { 387 switch ( ftp[i].getType() ) { 388 case Types.CHAR: 389 case Types.VARCHAR: 390 stmt.setString( i + 2, o.toString() ); 391 break; 392 case Types.SMALLINT: 393 case Types.TINYINT: 394 case Types.INTEGER: 395 case Types.BIGINT: 396 stmt.setInt( i + 2, (int) Double.parseDouble( o.toString() ) ); 397 break; 398 case Types.DOUBLE: 399 case Types.FLOAT: 400 case Types.DECIMAL: 401 case Types.NUMERIC: 402 stmt.setFloat( i + 2, Float.parseFloat( o.toString() ) ); 403 break; 404 case Types.DATE: 405 case Types.TIME: 406 case Types.TIMESTAMP: 407 stmt.setDate( i + 2, (Date) o ); 408 break; 409 case Types.GEOMETRY: { 410 StringBuffer gs = GMLGeometryAdapter.export( (Geometry) o ); 411 String s = StringTools.replace( 412 gs.toString(), 413 ">", 414 " xmlns:gml=\"http://www.opengis.net/gml\">", 415 false ); 416 if ( backend.equals( "POSTGRES" ) || backend.equals( "HSQLDB" ) ) { 417 stmt.setString( i + 2, s ); 418 } else if ( backend.equals( "INGRES" ) ) { 419 stmt.setObject( i + 2, new StringReader( s ) ); 420 } else { 421 stmt.setObject( i + 2, s.getBytes() ); 422 } 423 break; 424 } 425 default: { 426 LOG.logWarning( "unsupported type: " + ftp[i].getType() ); 427 } 428 } 429 } 430 } 431 432 stmt.execute(); 433 stmt.close(); 434 435 } catch ( Exception e ) { 436 e.printStackTrace(); 437 throw new IndexException( "could not insert feature into database", e ); 438 } finally { 439 try { 440 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 441 jdbc.getPassword() ); 442 } catch ( Exception e1 ) { 443 e1.printStackTrace(); 444 } 445 } 446 } 447 448 /** 449 * initializes the root node of the quadtree 450 * 451 * @param fileName 452 * @throws IndexException 453 * @throws IOException 454 * 455 */ 456 protected void initRootNode( String fileName ) 457 throws IndexException, IOException { 458 ShapeFile sf = new ShapeFile( fileName ); 459 if ( envelope == null ) { 460 envelope = sf.getFileMBR(); 461 } 462 envelope = envelope.getBuffer( envelope.getWidth() / 20 ); 463 LOG.logInfo( "root envelope: " + envelope ); 464 sf.close(); 465 new DBNode( "1", envelope, null, indexName, jdbc, 1 ); 466 } 467 468 /** 469 * before importing a shape a user may set an envelope for the quadtree to bee created that is 470 * different from the one of the shape by calling this method. Notice: calling this method does 471 * not have any effect when calling 472 * 473 * @see #appendShape(String) method. 474 * @param envelope 475 */ 476 public void setRootEnvelope( Envelope envelope ) { 477 this.envelope = envelope; 478 } 479 480 /** 481 * initializes a new Quadtree by adding a row into table TAB_QUADTREE and into TAB_QTNODE (-> 482 * root node) 483 * 484 * @param fileName 485 * 486 * @return 487 * @throws IndexException 488 * @throws IOException 489 */ 490 protected int initQuadtree( String fileName ) 491 throws IndexException, IOException { 492 493 initRootNode( fileName ); 494 495 Connection con = null; 496 DBConnectionPool pool = null; 497 int id = -1; 498 try { 499 pool = DBConnectionPool.getInstance(); 500 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 501 jdbc.getPassword() ); 502 503 StringBuffer sb = new StringBuffer( 100 ); 504 sb.append( "INSERT INTO TAB_QUADTREE (" ); 505 if ( backend.equals( "INGRES" ) || backend.equals( "HSQLDB" ) ) { 506 sb.append( "ID, " ); 507 } 508 sb.append( "FK_ROOT, DEPTH ) VALUES ( " ); 509 if ( backend.equals( "INGRES" ) || backend.equals( "HSQLDB" ) ) { 510 Statement stm = con.createStatement(); 511 ResultSet rs = stm.executeQuery( "SELECT MAX(ID) FROM TAB_QUADTREE" ); 512 rs.next(); 513 int myid = rs.getInt( 1 ) + 1; 514 sb.append( myid + ", " ); 515 } 516 sb.append( " '1', ? ) " ); 517 518 PreparedStatement stmt = con.prepareStatement( sb.toString() ); 519 stmt.setInt( 1, maxDepth ); 520 stmt.execute(); 521 stmt.close(); 522 Statement stm = con.createStatement(); 523 ResultSet rs = stm.executeQuery( "select max(ID) from TAB_QUADTREE" ); 524 rs.next(); 525 id = rs.getInt( 1 ); 526 if ( id < 0 ) { 527 throw new IndexException( "could not read ID of quadtree from database." ); 528 } 529 } catch ( Exception e ) { 530 e.printStackTrace(); 531 throw new IndexException( "could not create node definition at database", e ); 532 } finally { 533 try { 534 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 535 jdbc.getPassword() ); 536 } catch ( Exception e1 ) { 537 e1.printStackTrace(); 538 } 539 } 540 return id; 541 } 542 543 /** 544 * 545 * @param fk_indexTree 546 * @return 547 * @throws IndexException 548 */ 549 public void insertIndexMetadata( int fk_indexTree ) 550 throws IndexException { 551 552 Connection con = null; 553 DBConnectionPool pool = null; 554 try { 555 pool = DBConnectionPool.getInstance(); 556 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 557 jdbc.getPassword() ); 558 559 StringBuffer sb = new StringBuffer( 100 ); 560 sb.append( "INSERT INTO TAB_DEEGREE_IDX ( " ); 561 if ( backend.equals( "INGRES" ) || backend.equals( "HSQLDB" ) ) { 562 sb.append( "ID, " ); 563 } 564 sb.append( "column_name, table_name, " ); 565 sb.append( "owner, INDEX_NAME, FK_indexTree ) " ); 566 sb.append( "VALUES ( " ); 567 if ( backend.equals( "INGRES" ) || backend.equals( "HSQLDB" ) ) { 568 Statement stm = con.createStatement(); 569 ResultSet rs = stm.executeQuery( "SELECT MAX(ID) FROM TAB_QUADTREE" ); 570 rs.next(); 571 int myid = rs.getInt( 1 ) + 1; 572 sb.append( myid + ", " ); 573 } 574 sb.append( "?, ?, ?, ?, ? ) " ); 575 PreparedStatement stmt = con.prepareStatement( sb.toString() ); 576 stmt.setString( 1, column ); 577 stmt.setString( 2, table ); 578 stmt.setString( 3, owner ); 579 stmt.setString( 4, indexName ); 580 stmt.setInt( 5, fk_indexTree ); 581 582 stmt.execute(); 583 stmt.close(); 584 } catch ( Exception e ) { 585 LOG.logError( e.getMessage(), e ); 586 throw new IndexException( "could not create node definition at database", e ); 587 } finally { 588 try { 589 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 590 jdbc.getPassword() ); 591 } catch ( Exception e1 ) { 592 e1.printStackTrace(); 593 } 594 } 595 } 596 597 /** 598 * creates table the shape data shall be stored 599 * 600 * @param fileName 601 * @throws IndexException 602 * @throws IOException 603 */ 604 protected void createDataTable( String fileName ) 605 throws IndexException, IOException { 606 ShapeFile sf = new ShapeFile( fileName ); 607 FeatureType ft = null; 608 try { 609 ft = sf.getFeatureByRecNo( 1 ).getFeatureType(); 610 } catch ( Exception e ) { 611 e.printStackTrace(); 612 throw new IndexException( e ); 613 } 614 sf.close(); 615 StringBuffer sb = new StringBuffer( 1000 ); 616 sb.append( "CREATE TABLE " ).append( table ).append( '(' ); 617 sb.append( "FEATURE_ID VARCHAR(50)," ); 618 PropertyType[] ftp = ft.getProperties(); 619 for ( int i = 0; i < ftp.length; i++ ) { 620 if ( ftp[i].getType() == Types.GEOMETRY ) { 621 sb.append( column ).append( ' ' ); 622 } else { 623 sb.append( ftp[i].getName().getLocalName() ).append( ' ' ); 624 } 625 sb.append( getDatabaseType( ftp[i].getType() ) ); 626 if ( i < ftp.length - 1 ) { 627 sb.append( ", " ); 628 } 629 } 630 sb.append( ')' ); 631 632 Connection con = null; 633 DBConnectionPool pool = null; 634 try { 635 pool = DBConnectionPool.getInstance(); 636 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 637 jdbc.getPassword() ); 638 639 Statement stmt = con.createStatement(); 640 LOG.logDebug( sb.toString() ); 641 stmt.execute( sb.toString() ); 642 stmt.close(); 643 } catch ( Exception e ) { 644 e.printStackTrace(); 645 throw new IndexException( "could not create node definition at database", e ); 646 } finally { 647 try { 648 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 649 jdbc.getPassword() ); 650 } catch ( Exception e1 ) { 651 e1.printStackTrace(); 652 } 653 } 654 } 655 656 /** 657 * returns the type name for a generic type code as used by SQLServer 658 * 659 * @param dataTypeCode 660 * @return the type name for a generic type code as used by SQLServer 661 * @throws IndexException 662 */ 663 protected String getDatabaseType( int dataTypeCode ) 664 throws IndexException { 665 String driver = jdbc.getDriver(); 666 String backend = null; 667 if ( driver.toUpperCase().indexOf( "POSTGRES" ) > -1 ) { 668 backend = "POSTGRES"; 669 } else if ( driver.toUpperCase().indexOf( "SQLSERVER" ) > -1 ) { 670 backend = "SQLSERVER"; 671 } else if ( driver.toUpperCase().indexOf( "INGRES" ) > -1 672 || driver.equals( "ca.edbc.jdbc.EdbcDriver" ) ) { 673 backend = "INGRES"; 674 } else if ( driver.toUpperCase().indexOf( "HSQLDB" ) > -1 ) { 675 backend = "HSQLDB"; 676 } else { 677 backend = "GENERICSQL"; 678 } 679 String type = null; 680 681 switch ( dataTypeCode ) { 682 case Types.CHAR: 683 case Types.VARCHAR: 684 type = DBQuadtreeDataTypes.getString( backend + ".string" ); 685 break; 686 case Types.SMALLINT: 687 case Types.TINYINT: 688 case Types.INTEGER: 689 case Types.BIGINT: 690 type = DBQuadtreeDataTypes.getString( backend + ".integer" ); 691 break; 692 case Types.DOUBLE: 693 case Types.FLOAT: 694 case Types.DECIMAL: 695 case Types.NUMERIC: 696 type = DBQuadtreeDataTypes.getString( backend + ".float" ); 697 break; 698 case Types.DATE: 699 case Types.TIME: 700 case Types.TIMESTAMP: 701 type = DBQuadtreeDataTypes.getString( backend + ".datetime" ); 702 break; 703 case Types.GEOMETRY: 704 type = DBQuadtreeDataTypes.getString( backend + ".geometry" ); 705 break; 706 default: 707 throw new IndexException( "unknown data type code: " + dataTypeCode ); 708 } 709 710 return type; 711 } 712 713 /** 714 * imports a shape into the database and builds a quadtree on it 715 * 716 * @param fileName 717 * @throws Exception 718 * @throws IOException 719 */ 720 public void importShape( String fileName ) 721 throws Exception, IOException { 722 723 createDataTable( fileName ); 724 725 int qtid = initQuadtree( fileName ); 726 727 insertIndexMetadata( qtid ); 728 729 qt = new DBQuadtree( qtid, indexName, jdbc ); 730 731 ShapeFile sf = new ShapeFile( fileName ); 732 733 int b = sf.getRecordNum() / 100; 734 if ( b == 0 ) 735 b = 1; 736 int k = 0; 737 Envelope sfEnv = sf.getFileMBR(); 738 739 for ( int i = 0; i < sf.getRecordNum(); i++ ) { 740 Feature feat = sf.getFeatureByRecNo( i + 1 ); 741 if ( i % b == 0 ) { 742 System.out.println( k + "%" ); 743 k++; 744 } 745 if ( i % 200 == 0 ) { 746 System.gc(); 747 } 748 Envelope env = feat.getDefaultGeometryPropertyValue().getEnvelope(); 749 LOG.logDebug( i + " --- " + env ); 750 if ( env == null ) { 751 // must be a point geometry 752 Point point = (Point) feat.getDefaultGeometryPropertyValue(); 753 double w = sfEnv.getWidth() / 1000; 754 double h = sfEnv.getHeight() / 1000; 755 env = GeometryFactory.createEnvelope( point.getX() - w / 2d, point.getY() - h / 2d, 756 point.getX() + w / 2d, point.getY() + h / 2d, 757 null ); 758 } 759 String id = UUID.randomUUID().toString(); 760 qt.insert( id, env ); 761 storeFeature( feat, id, jdbc ); 762 } 763 LOG.logInfo( " finished!" ); 764 sf.close(); 765 } 766 767 /** 768 * appends the features of a shape to an existing datatable and inserts references into the 769 * assigned quadtree table. 770 * <p> 771 * you have to consider that the quadtree is just valid for a defined area. if the features to 772 * append exceeds this area the quadtree has to be rebuilded. 773 * </p> 774 * 775 * @param fileName 776 * @throws Exception 777 * @throws IOException 778 */ 779 public void appendShape( String fileName ) 780 throws Exception, IOException { 781 782 ShapeFile sf = new ShapeFile( fileName ); 783 784 int b = sf.getRecordNum() / 100; 785 if ( b == 0 ) 786 b = 1; 787 int k = 0; 788 qt = getQuadtree(); 789 Envelope sfEnv = sf.getFileMBR(); 790 791 for ( int i = 0; i < sf.getRecordNum(); i++ ) { 792 Feature feat = sf.getFeatureByRecNo( i + 1 ); 793 if ( i % b == 0 ) { 794 System.out.println( k + "%" ); 795 k++; 796 } 797 if ( i % 200 == 0 ) { 798 System.gc(); 799 } 800 Envelope env = feat.getDefaultGeometryPropertyValue().getEnvelope(); 801 if ( env == null ) { 802 // must be a point geometry 803 Point point = (Point) feat.getDefaultGeometryPropertyValue(); 804 double w = sfEnv.getWidth() / 1000; 805 double h = sfEnv.getHeight() / 1000; 806 env = GeometryFactory.createEnvelope( point.getX() - w / 2d, point.getY() - h / 2d, 807 point.getX() + w / 2d, point.getY() + h / 2d, 808 null ); 809 } 810 String id = UUID.randomUUID().toString(); 811 qt.insert( id, env ); 812 storeFeature( feat, id, jdbc ); 813 } 814 LOG.logInfo( " finished!" ); 815 sf.close(); 816 } 817 818 /** 819 * creates a table that will store the nodes assigned to a specific quadtree index. 820 * 821 * @param indexTable 822 */ 823 protected void createIndexTable( String indexTable ) { 824 StringBuffer sb = new StringBuffer( 2000 ); 825 sb.append( "CREATE TABLE " ).append( indexTable ).append( " ( " ); 826 sb.append( "ID varchar(150) NOT NULL," ); 827 sb.append( "minx float NOT NULL," ); 828 sb.append( "miny float NOT NULL," ); 829 sb.append( "maxx float NOT NULL," ); 830 sb.append( "maxy float NOT NULL," ); 831 sb.append( "FK_SUBNODE1 varchar(150)," ); 832 sb.append( "FK_SUBNODE2 varchar(150)," ); 833 sb.append( "FK_SUBNODE3 varchar(150)," ); 834 sb.append( "FK_SUBNODE4 varchar(150) )" ); 835 836 StringBuffer sb2 = new StringBuffer( 1000 ); 837 sb2.append( "CREATE TABLE " ).append( indexName ).append( "_ITEM ( " ); 838 sb2.append( "FK_QTNODE varchar(150) NOT NULL," ); 839 sb2.append( "FK_ITEM varchar(150) NOT NULL )" ); 840 841 Connection con = null; 842 DBConnectionPool pool = null; 843 try { 844 pool = DBConnectionPool.getInstance(); 845 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 846 jdbc.getPassword() ); 847 848 Statement stmt = con.createStatement(); 849 stmt.execute( sb.toString() ); 850 stmt.close(); 851 852 stmt = con.createStatement(); 853 stmt.execute( sb2.toString() ); 854 stmt.close(); 855 } catch ( Exception e ) { 856 // throw new IndexException( "could not create node definition at database", e ); 857 } finally { 858 try { 859 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), 860 jdbc.getPassword() ); 861 } catch ( Exception e1 ) { 862 e1.printStackTrace(); 863 } 864 } 865 } 866 867 }