001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/io/quadtree/DBQuadtreeManager.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001-2008 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.security.InvalidParameterException;
048 import java.sql.Connection;
049 import java.sql.Date;
050 import java.sql.PreparedStatement;
051 import java.sql.ResultSet;
052 import java.sql.ResultSetMetaData;
053 import java.sql.SQLException;
054 import java.sql.Statement;
055 import java.util.HashMap;
056 import java.util.UUID;
057
058 import org.deegree.datatypes.Types;
059 import org.deegree.framework.log.ILogger;
060 import org.deegree.framework.log.LoggerFactory;
061 import org.deegree.framework.util.StringTools;
062 import org.deegree.io.DBConnectionPool;
063 import org.deegree.io.DBPoolException;
064 import org.deegree.io.JDBCConnection;
065 import org.deegree.io.dbaseapi.DBaseException;
066 import org.deegree.io.shpapi.HasNoDBaseFileException;
067 import org.deegree.io.shpapi.ShapeFile;
068 import org.deegree.model.feature.Feature;
069 import org.deegree.model.feature.schema.FeatureType;
070 import org.deegree.model.feature.schema.PropertyType;
071 import org.deegree.model.spatialschema.Envelope;
072 import org.deegree.model.spatialschema.GMLGeometryAdapter;
073 import org.deegree.model.spatialschema.Geometry;
074 import org.deegree.model.spatialschema.GeometryException;
075 import org.deegree.model.spatialschema.GeometryFactory;
076 import org.deegree.model.spatialschema.Point;
077
078 /**
079 * Access control to a quadtree for managing spatial indizes stored in a usual database.
080 *
081 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
082 * @author last edited by: $Author: apoth $
083 *
084 * @version $Revision: 9342 $, $Date: 2007-12-27 13:32:57 +0100 (Do, 27 Dez 2007) $
085 * @param <T>
086 * the type of the quadtree. If unsure use the determineQuattreType() method to determine the type. Be
087 * carefull though, if you use a wrong generic here (e.g. not Integer or String) while supplying another
088 * types.Type to the constructor there is no way to check find the correct instance.
089 */
090 public class DBQuadtreeManager<T> {
091
092 private static final ILogger LOG = LoggerFactory.getLogger( DBQuadtreeManager.class );
093
094 protected JDBCConnection jdbc = null;
095
096 protected String table = null;
097
098 protected String column = null;
099
100 protected String owner = null;
101
102 protected String indexName = null;
103
104 protected int maxDepth = 6;
105
106 private DBQuadtree<T> qt = null;
107
108 protected Envelope envelope = null;
109
110 protected String backend = null;
111
112 private int TYPE;
113
114 private static HashMap<String, String> quadTreeVersionInfo = new HashMap<String, String>();
115
116 /**
117 * @param jdbc
118 * database connection info
119 * @param owner
120 * owner of the table (optional, database user will be used if set to null )
121 * @param indexName
122 * this name will be used to create the table that stores the nodes of a specific quadtree
123 * @param table
124 * name of table the index shall be created for
125 * @param column
126 * name of column the index shall be created for
127 * @param maxDepth
128 * max depth of the generated quadtree (default = 6 if a value < 2 will be passed)
129 * @param type
130 * the type of the id of the quadtree, valid are Types.INTEGER and Types.VARCHAR. if unsure use
131 * Intger.MIN_VALUE and call {@link #determineQuattreeType()}, to get an instance of the Type.
132 */
133 public DBQuadtreeManager( JDBCConnection jdbc, String owner, String indexName, String table, String column,
134 int maxDepth, int type ) {
135 TYPE = type;
136 if ( TYPE != Types.INTEGER && TYPE != Types.VARCHAR ) {
137 TYPE = Integer.MIN_VALUE;
138 }
139 if ( jdbc == null ) {
140 throw new InvalidParameterException( "The JDBCConnection reference parameter 'jdbc' may not be null." );
141 }
142 this.jdbc = jdbc;
143 if ( table == null || "".equals( table.trim() ) ) {
144 throw new InvalidParameterException( "The 'table' parameter may not be null or emtpy." );
145 }
146 this.table = table.trim();
147
148 if ( indexName == null || "".equals( indexName.trim() ) || "idx_".equalsIgnoreCase( indexName.trim() ) ) {
149 throw new InvalidParameterException( "The 'indexName' parameter may not be null or emtpy or solumnly exist of idx_." );
150 }
151 this.indexName = indexName.trim();
152
153 if ( column == null || "".equals( column.trim() ) ) {
154 throw new InvalidParameterException( "The 'column' parameter may not be null or emtpy." );
155 }
156 this.column = column.trim();
157
158 this.owner = owner;
159 if ( owner == null ) {
160 String user = jdbc.getUser();
161 if ( user == null || "".equals( user.trim() ) ) {
162 this.owner = "";
163 } else {
164 this.owner = user;
165 }
166 }
167 if ( maxDepth > 1 ) {
168 this.maxDepth = maxDepth;
169 } else {
170 this.maxDepth = 6;
171 }
172
173 String driver = jdbc.getDriver();
174 if ( driver == null || "".equals( driver.trim() ) ) {
175 throw new InvalidParameterException( "The JDBCConnection.driver may not be null or emtpy." );
176 }
177 // find out which database is used
178 if ( driver.toUpperCase().contains( "POSTGRES" ) ) {
179 backend = "POSTGRES";
180 } else if ( driver.toUpperCase().contains( "SQLSERVER" ) ) {
181 backend = "SQLSERVER";
182 } else if ( driver.toUpperCase().contains( "INGRES" ) || driver.equals( "ca.edbc.jdbc.EdbcDriver" ) ) {
183 backend = "INGRES";
184 } else if ( driver.toUpperCase().contains( "HSQLDB" ) ) {
185 backend = "HSQLDB";
186 } else {
187 backend = "GENERICSQL";
188 }
189
190 try {
191 if ( !hasIndexTable() ) {
192 LOG.logDebug( "It seems no indextable with name: '"+indexName +"' exists in the database backend, creating one." );
193 createIndexTable( indexName, "VARCHAR(50)" );
194 }
195 } catch ( IndexException e ) {
196 LOG.logError( "Following error occurred while trying to create the indexTable: " + e.getMessage(), e );
197 }
198 }
199
200
201 /**
202 *
203 * @param driver
204 * database connection driver
205 * @param logon
206 * database connection logon
207 * @param user
208 * database user
209 * @param password
210 * database user's password
211 * @param encoding
212 * character encoding to be used (if possible)
213 * @param indexName
214 * this name will be used to create the table that stores the nodes of a specific quadtree
215 * @param table
216 * name of table the index shall be created for
217 * @param column
218 * name of column the index shall be created for
219 * @param owner
220 * owner of the table (optional, database user will be used if set to null )
221 * @param maxDepth
222 * max depth of the generated quadtree (default = 6 if a value < 2 will be passed)
223 * @param type
224 * the type of the id of the quadtree, valid are Types.INTEGER and Types.VARCHAR. if unsure use
225 * Intger.MIN_VALUE and call {@link #determineQuattreeType()}, to get an instance of the Type.
226 */
227 public DBQuadtreeManager( String driver, String logon, String user, String password, String encoding,
228 String indexName, String table, String column, String owner, int maxDepth, int type ) {
229 this( new JDBCConnection( driver, logon, user, password, null, encoding, null ),
230 owner,
231 indexName,
232 table,
233 column,
234 maxDepth,
235 type );
236 }
237
238 /**
239 * initializes a QuadtreeManager to access an alread existing Quadtree
240 *
241 * @param jdbc
242 * database connection info
243 * @param table
244 * name of table the index shall be created for
245 * @param column
246 * name of column the index shall be created for
247 * @param owner
248 * owner of the table (optional, database user will be used if set to null )
249 * @param type
250 * the type of the id of the quadtree, valid are Types.INTEGER and Types.VARCHAR. if unsure use
251 * Intger.MIN_VALUE and call {@link #determineQuattreeType()}, to get an instance of the Type.
252 */
253 public DBQuadtreeManager( JDBCConnection jdbc, String table, String column, String owner, int type ) {
254 this( jdbc, owner, "idx_" + table, table, column, 6, type );
255 }
256
257 /**
258 * initializes a QuadtreeManager to access an alread existing Quadtree
259 *
260 * @param driver
261 * database connection driver
262 * @param logon
263 * database connection logon
264 * @param user
265 * database user
266 * @param password
267 * database user's password
268 * @param encoding
269 * character encoding to be used (if possible)
270 * @param table
271 * name of table the index shall be created for
272 * @param column
273 * name of column the index shall be created for
274 * @param owner
275 * owner of the table (optional, database user will be used if set to null )
276 * @param type
277 * the type of the id of the quadtree, valid are Types.INTEGER and Types.VARCHAR. if unsure use
278 * Intger.MIN_VALUE and call {@link #determineQuattreeType()}, to get an instance of the Type.
279 */
280 public DBQuadtreeManager( String driver, String logon, String user, String password, String encoding, String table,
281 String column, String owner, int type ) {
282 this( new JDBCConnection( driver, logon, user, password, null, encoding, null ),
283 owner,
284 "idx_" + table,
285 table,
286 column,
287 6,
288 type );
289 }
290
291 /**
292 * loads the metadata of a Index from the TAB_DEEGREE_IDX table
293 *
294 * @return FK to the index
295 * @throws IndexException
296 */
297 protected int loadIndexMetadata()
298 throws IndexException {
299 int fk_indexTree = -1;
300 Connection con = null;
301 DBConnectionPool pool = null;
302 try {
303 pool = DBConnectionPool.getInstance();
304 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
305
306 StringBuilder sb = new StringBuilder( 200 );
307 sb.append( "Select INDEX_NAME, FK_INDEXTREE from TAB_DEEGREE_IDX where " );
308 sb.append( "column_name = '" ).append( column ).append( "' AND " );
309 sb.append( "table_name = '" ).append( table ).append( "' AND " );
310 sb.append( "owner = '" ).append( owner ).append( "'" );
311
312 Statement stmt = con.createStatement();
313 ResultSet rs = stmt.executeQuery( sb.toString() );
314
315 if ( rs.next() ) {
316 indexName = rs.getString( "INDEX_NAME" );
317 fk_indexTree = rs.getInt( "FK_INDEXTREE" );
318 } else {
319 throw new IndexException( "Could not read the structure of the quadtree tables from database (did you run the base/scripts/index/quadtree.hsql script, which create the meta-info tables?)." );
320 }
321 rs.close();
322 stmt.close();
323 } catch ( SQLException e ) {
324 throw new IndexException( "Could not load quadtree definition from database (did you run the base/scripts/index/quadtree.hsql script, which create the meta-info tables?). The error message was: " + e.getMessage() );
325 } catch ( DBPoolException e ) {
326 throw new IndexException( "Could not acquire a database connection. The error message was: " + e.getMessage() );
327 } finally {
328 try {
329 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
330 } catch ( Exception e1 ) {
331 LOG.logError( "Could not release the jdbc connection because: " + e1.getMessage() );
332 }
333 }
334 LOG.logDebug( "It seems an indextable with name: '"+indexName +"' allready exists in the database backend." );
335 return fk_indexTree;
336 }
337
338 /**
339 * returns the current Quadtree
340 *
341 * @return the current Quadtree
342 * @throws IndexException
343 */
344 public DBQuadtree<T> getQuadtree()
345 throws IndexException {
346 if ( qt == null ) {
347 qt = loadQuadtree();
348 }
349 return qt;
350 }
351
352 /**
353 * loads an already existing quadtree
354 *
355 * @return the Quadtree structure read from the database
356 * @throws IndexException
357 */
358 private DBQuadtree<T> loadQuadtree()
359 throws IndexException {
360 int fk_index = loadIndexMetadata();
361
362 String version = getQTVersion( table );
363 return new DBQuadtree<T>( fk_index, indexName, jdbc, version );
364 }
365
366 /**
367 * @return an instance of the type of the feature id's stored in the db. Possible instances are
368 * <code>String<code>, <code>Integer</code> or <code>null</code> if the type could not be determined.
369 * @throws IndexException if the type information could not be retrieved either because no connection was acquired or an error occurred while executing the select statement.
370 */
371 public Object determineQuattreeType()
372 throws IndexException {
373
374 if ( TYPE == Integer.MIN_VALUE ) {
375 StringBuilder sb = new StringBuilder( 1000 );
376 sb.append( "SELECT FK_ITEM from " ).append( indexName ).append( "_ITEM " );
377 Connection con = null;
378 DBConnectionPool pool = null;
379
380 try {
381 pool = DBConnectionPool.getInstance();
382 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
383
384 PreparedStatement stmt = con.prepareStatement( sb.toString() );
385 ResultSet rs = stmt.executeQuery();
386 ResultSetMetaData metaData = rs.getMetaData();
387
388 if ( metaData != null ) {
389 TYPE = metaData.getColumnType( 1 );
390 LOG.logDebug( "Found type: "+ TYPE );
391 }
392 rs.close();
393 stmt.close();
394
395 } catch ( SQLException e ) {
396 throw new IndexException( "Could not get Type information because: " + e.getMessage(), e );
397 } catch ( DBPoolException e ) {
398 throw new IndexException( "Could not acquire a connection to the database to retrieve column information because: " + e.getMessage(),
399 e );
400 } finally {
401 try {
402 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
403 } catch ( DBPoolException e ) {
404 LOG.logError( "Could not release JDBC connection because: " + e.getMessage() );
405 }
406 }
407 }
408 Object result = null;
409 switch ( TYPE ) {
410 case Types.VARCHAR:
411 result = "";
412 break;
413 case Types.INTEGER:
414 result = new Integer( 1 );
415 break;
416 default:
417 TYPE = Integer.MAX_VALUE;
418 }
419 return result;
420 }
421
422 /**
423 * @param table
424 * to open a quadtree for.
425 * @return the version of the quadtree used.
426 */
427 private String getQTVersion( String table ) {
428 String version = "1.0.0";
429 if ( quadTreeVersionInfo.containsKey( table ) && quadTreeVersionInfo.get( table ) != null ) {
430 LOG.logDebug( "Retrieved the quatdree version info for table: " + table + " from cache." );
431 version = quadTreeVersionInfo.get( table );
432 } else {
433 Connection con = null;
434 DBConnectionPool pool = null;
435 Statement stmt = null;
436 ResultSet rs = null;
437 pool = DBConnectionPool.getInstance();
438 StringBuilder sb = new StringBuilder( 400 );
439 sb.append( "SELECT fk_indextree FROM tab_deegree_idx WHERE " );
440 sb.append( "column_name = 'geometry' AND " );
441 sb.append( "table_name = '" ).append( table.toLowerCase() ).append( "'" );
442
443 LOG.logDebug( "Get Index Metadata sql statement:\n", sb );
444 try {
445 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
446 stmt = con.createStatement();
447 rs = stmt.executeQuery( sb.toString() );
448 String tableID = null;
449 if ( rs.next() ) {
450 tableID = rs.getString( 1 );
451 }
452 if ( tableID != null ) {
453 sb = new StringBuilder( 400 );
454 sb.append( "SELECT * FROM tab_quadtree WHERE " );
455 sb.append( "fk_root = '" ).append( tableID.trim() ).append( "'" );
456 if ( rs != null ) {
457 rs.close();
458 }
459 if ( stmt != null ) {
460 stmt.close();
461 }
462 stmt = con.createStatement();
463 rs = stmt.executeQuery( sb.toString() );
464 if ( rs.next() ) {
465 boolean hasVersion = false;
466 ResultSetMetaData md = rs.getMetaData();
467 int numberOfColumns = md.getColumnCount();
468 System.out.println( "Columnecount: " + numberOfColumns );
469 for ( int i = 1; i <= numberOfColumns && !hasVersion; i++ ) {
470 String tmp = md.getColumnName( i );
471 LOG.logDebug( "Found columnname: " + tmp );
472 if ( tmp != null ) {
473 if ( "version".equalsIgnoreCase( tmp.trim() ) ) {
474 hasVersion = true;
475 version = rs.getString( i );
476 LOG.logDebug( "Found a version column, setting version to: " + rs.getString( i ) );
477 }
478 }
479 }
480 if ( !hasVersion ) {
481 try {
482 LOG.logInfo( "Found no Version Column in the TAB_QUADTREE table, assuming version 1.0.0, and adding the version column." );
483 if ( rs != null ) {
484 rs.close();
485 }
486 if ( stmt != null ) {
487 stmt.close();
488 }
489 stmt = con.createStatement();
490 rs = stmt.executeQuery( "ALTER TABLE TAB_QUADTREE ADD version VARCHAR(15)" );
491 rs.close();
492 stmt.close();
493 } catch ( SQLException e ) {
494 if ( rs != null ) {
495 rs.close();
496 }
497 if ( stmt != null ) {
498 stmt.close();
499 }
500 LOG.logError( "An error occurred while trying to insert a new 'version' column in the database: " + e.getMessage(),
501 e );
502 }
503 }
504 }
505 } else {
506 LOG.logError( "Could not find the foreign key (fk_root) of the table: '" + table
507 + "' is your database is set up correct?" );
508 }
509 } catch ( SQLException e ) {
510 LOG.logError( "An error occurred while determening version of quadtree, therefore setting version to '1.0.0'. Errormessage: " + e.getMessage(),
511 e );
512 } catch ( DBPoolException e ) {
513 LOG.logError( "An error occurred while acquiring connection to the database to determine version of quadtree, therefore setting version to '1.0.0'. Errormessage: " + e.getMessage(),
514 e );
515 } finally {
516 quadTreeVersionInfo.put( table, version );
517 try {
518 if ( rs != null ) {
519 rs.close();
520 }
521 if ( stmt != null ) {
522 stmt.close();
523 }
524 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
525 } catch ( SQLException e ) {
526 LOG.logError( "Could not close ResultSet or Statement because: " + e.getMessage() );
527 } catch ( DBPoolException e ) {
528 LOG.logError( "Could not reslease connection because: " + e.getMessage() );
529 }
530 }
531 }
532 return version;
533 }
534
535 /**
536 * stores one feature into the defined table
537 *
538 * @param feature
539 * the feature to insert into the 'table'
540 * @param id
541 * of the feature to store in the database, currently String and Integer are supported. If it is neither,
542 * the Object is saved as an object, which may result in inconsitencies.
543 * @param jdbc
544 * the connection to the database.
545 * @throws IndexException
546 * if the feature can not be inserted or a connection error occurrs.
547 */
548 protected void storeFeature( Feature feature, T id, JDBCConnection jdbc )
549 throws IndexException {
550
551 Connection con = null;
552 DBConnectionPool pool = null;
553
554 FeatureType ft = feature.getFeatureType();
555 PropertyType[] ftp = ft.getProperties();
556 try {
557 pool = DBConnectionPool.getInstance();
558 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
559
560 StringBuilder sb = new StringBuilder( 100 );
561 sb.append( "INSERT INTO " ).append( table ).append( '(' );
562 sb.append( "FEATURE_ID," );
563 for ( int i = 0; i < ftp.length; i++ ) {
564 if ( ftp[i].getType() == Types.GEOMETRY ) {
565 sb.append( column ).append( ' ' );
566 } else {
567 sb.append( ftp[i].getName().getLocalName() );
568 }
569 if ( i < ftp.length - 1 ) {
570 sb.append( ", " );
571 }
572 }
573 sb.append( ") VALUES (?," );
574 for ( int i = 0; i < ftp.length; i++ ) {
575 sb.append( '?' );
576 if ( i < ftp.length - 1 ) {
577 sb.append( ", " );
578 }
579 }
580 sb.append( ')' );
581
582 PreparedStatement stmt = con.prepareStatement( sb.toString() );
583 if ( id instanceof String ) {
584 LOG.logDebug( "Setting to id '" + id + "'an instance of String" );
585 stmt.setString( 1, (String) id );
586 } else if ( id instanceof Integer ) {
587 LOG.logDebug( "Setting to id '" + id + "'an instance of integer" );
588 stmt.setInt( 1, ( (Integer) id ).intValue() );
589 } else {
590 LOG.logWarning( "The type of id is uncertain (neiter String nor Integer), adding it as an 'object' to the database." );
591 stmt.setObject( 1, id );
592 }
593
594 for ( int i = 0; i < ftp.length; i++ ) {
595 Object o = null;
596 if ( feature.getProperties( ftp[i].getName() ) != null ) {
597 if ( feature.getProperties( ftp[i].getName() ).length > 0 ) {
598 o = feature.getProperties( ftp[i].getName() )[0].getValue();
599 }
600 }
601 if ( o == null ) {
602 stmt.setNull( i + 2, ftp[i].getType() );
603 } else {
604 switch ( ftp[i].getType() ) {
605 case Types.CHAR:
606 case Types.VARCHAR:
607 stmt.setString( i + 2, o.toString() );
608 break;
609 case Types.SMALLINT:
610 case Types.TINYINT:
611 case Types.INTEGER:
612 case Types.BIGINT:
613 stmt.setInt( i + 2, (int) Double.parseDouble( o.toString() ) );
614 break;
615 case Types.DOUBLE:
616 case Types.FLOAT:
617 case Types.DECIMAL:
618 case Types.NUMERIC:
619 stmt.setFloat( i + 2, Float.parseFloat( o.toString() ) );
620 break;
621 case Types.DATE:
622 case Types.TIME:
623 case Types.TIMESTAMP:
624 stmt.setDate( i + 2, (Date) o );
625 break;
626 case Types.GEOMETRY: {
627 StringBuffer gs = GMLGeometryAdapter.export( (Geometry) o );
628 String s = StringTools.replace( gs.toString(),
629 ">",
630 " xmlns:gml=\"http://www.opengis.net/gml\">",
631 false );
632 if ( backend.equals( "POSTGRES" ) || backend.equals( "HSQLDB" ) ) {
633 LOG.logDebug( "Adding geometry: " + s );
634 stmt.setString( i + 2, s );
635 } else if ( backend.equals( "INGRES" ) ) {
636 stmt.setObject( i + 2, new StringReader( s ) );
637 } else {
638 stmt.setObject( i + 2, s.getBytes() );
639 }
640 break;
641 }
642 default: {
643 LOG.logWarning( "unsupported type: " + ftp[i].getType() );
644 }
645 }
646 }
647 }
648 LOG.logDebug( "SQL statement for insert feature: " + sb );
649 if ( !stmt.execute() ) {
650 LOG.logError( "The insertion of the feature resulted in " + stmt.getUpdateCount() + " updates." );
651 }
652
653 stmt.close();
654 } catch ( SQLException e ) {
655 String msg = "Could not insert feature with id='" + id + "' into the database because: " + e.getMessage();
656 LOG.logError( msg, e );
657 throw new IndexException( msg, e );
658 } catch ( DBPoolException e ) {
659 String msg = "Could not acquire a connection to the database to insert the feature with id: " + id;
660 LOG.logError( msg, e );
661 throw new IndexException( msg, e );
662 } catch ( GeometryException e ) {
663 String msg = "Could not insert feature with id='" + id + "' into the database because: " + e.getMessage();
664 LOG.logError( msg, e );
665 throw new IndexException( msg, e );
666 } finally {
667 try {
668 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
669 } catch ( DBPoolException e ) {
670 LOG.logError( "Could not release JDBC connection because: " + e.getMessage() );
671 }
672 }
673 }
674
675 /**
676 * initializes the root node of the quadtree
677 *
678 * @param fileName
679 * @throws IndexException
680 * @throws IOException
681 *
682 */
683 protected void initRootNode( String fileName )
684 throws IndexException, IOException {
685 LOG.logDebug( "Trying to read shapefile from file: " + fileName );
686 ShapeFile sf = new ShapeFile( fileName );
687 if ( envelope == null ) {
688 envelope = sf.getFileMBR();
689 }
690 envelope = envelope.getBuffer( envelope.getWidth() / 20 );
691 LOG.logInfo( "Bounding box of the root feature: " + envelope );
692 sf.close();
693 // DBQuadtree<T> qtTmp = loadQuadtree();
694 Connection con = null;
695 DBConnectionPool pool = null;
696 try {
697 pool = DBConnectionPool.getInstance();
698 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
699
700 StringBuilder sb = new StringBuilder( 100 );
701 sb.append( "INSERT INTO " ).append( indexName );
702 sb.append( " ( ID, MINX, MINY, MAXX , MAXY ) " );
703 sb.append( "VALUES ( ?, ?, ?, ?, ? ) " );
704 PreparedStatement stmt = con.prepareStatement( sb.toString() );
705 stmt.setString( 1, "1" );
706 stmt.setFloat( 2, (float) envelope.getMin().getX() );
707 stmt.setFloat( 3, (float) envelope.getMin().getY() );
708 stmt.setFloat( 4, (float) envelope.getMax().getX() );
709 stmt.setFloat( 5, (float) envelope.getMax().getY() );
710 stmt.execute();
711 stmt.close();
712 } catch ( Exception e ) {
713 LOG.logError( e.getMessage(), e );
714 throw new IndexException( "could not create root node definition at database", e );
715 } finally {
716 try {
717 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
718 } catch ( Exception e1 ) {
719 e1.printStackTrace();
720 }
721 }
722 }
723
724 /**
725 * before importing a shape a user may set an envelope for the quadtree to bee created that is different from the
726 * one of the shape by calling this method. Notice: calling this method does not have any effect when calling
727 *
728 * @see #appendShape(String) method.
729 * @param envelope
730 */
731 public void setRootEnvelope( Envelope envelope ) {
732 this.envelope = envelope;
733 }
734
735 /**
736 * initializes a new Quadtree by adding a row into table TAB_QUADTREE and into TAB_QTNODE (-> root node)
737 *
738 * @param fileName
739 *
740 * @return the id of the inserted node
741 * @throws IndexException
742 * @throws IOException
743 * if the shape file could not be read.
744 */
745 protected int initQuadtree( String fileName )
746 throws IndexException, IOException {
747
748 initRootNode( fileName );
749 Connection con = null;
750 DBConnectionPool pool = null;
751 int id = -1;
752 try {
753 pool = DBConnectionPool.getInstance();
754 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
755
756 // first check if the version column exists;
757 StringBuilder versionCheck = new StringBuilder( "Select * from TAB_QUADTREE;" );
758 Statement stmt = con.createStatement();
759 ResultSet rs = stmt.executeQuery( versionCheck.toString() );
760 boolean hasVersion = false;
761 try {
762 ResultSetMetaData md = rs.getMetaData();
763 int numberOfColumns = md.getColumnCount();
764
765 for ( int i = 1; i <= numberOfColumns && !hasVersion; i++ ) {
766 String tmp = md.getColumnName( i );
767 if ( tmp != null ) {
768 if ( "version".equalsIgnoreCase( tmp.trim() ) ) {
769 hasVersion = true;
770 }
771 }
772 }
773 if ( !hasVersion ) {
774 LOG.logInfo( "Found no Version Column in the TAB_QUADTREE table, assuming version 2.0.0, and adding the version column." );
775 rs.close();
776 stmt.close();
777 stmt = con.createStatement();
778 rs = stmt.executeQuery( "ALTER TABLE TAB_QUADTREE ADD version VARCHAR(15)" );
779 rs.close();
780 stmt.close();
781 }
782 } catch ( SQLException e ) {
783 LOG.logError( "An error occurred while trying to determine if the database supports versioning: " + e.getMessage() );
784 }
785
786 StringBuilder sb = new StringBuilder( 100 );
787 sb.append( "INSERT INTO TAB_QUADTREE (" );
788 if ( backend.equals( "INGRES" ) || backend.equals( "HSQLDB" ) ) {
789 sb.append( "ID, " );
790 }
791 sb.append( "FK_ROOT, DEPTH, VERSION ) VALUES ( " );
792 if ( backend.equals( "INGRES" ) || backend.equals( "HSQLDB" ) ) {
793 stmt = con.createStatement();
794 rs = stmt.executeQuery( "SELECT MAX(ID) FROM TAB_QUADTREE" );
795 rs.next();
796 int myid = rs.getInt( 1 ) + 1;
797 sb.append( myid + ", " );
798 }
799 sb.append( " '1', ?, '2.0.0' ) " );
800
801 PreparedStatement pstmt = con.prepareStatement( sb.toString() );
802 pstmt.setInt( 1, maxDepth );
803 pstmt.execute();
804 pstmt.close();
805 stmt = con.createStatement();
806 rs = stmt.executeQuery( "select max(ID) from TAB_QUADTREE" );
807 rs.next();
808 id = rs.getInt( 1 );
809 if ( id < 0 ) {
810 throw new IndexException( "could not read ID of quadtree from database." );
811 }
812 } catch ( SQLException e ) {
813 throw new IndexException( "Could not load quadtree definition from database (did you run the base/scripts/index/quadtree.hsql script, which create the meta-info tables?). The error message was: " + e.getMessage() );
814 } catch ( DBPoolException e ) {
815 throw new IndexException( "Could not acquire a connection to the database to initiate the quattree index structure because: " + e.getMessage() );
816 } finally {
817 try {
818 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
819 } catch ( DBPoolException e ) {
820 LOG.logError( "Could not release JDBC connection because: " + e.getMessage() );
821 }
822 }
823 return id;
824 }
825
826 /**
827 * Inserts a row into the quadtree meta data structure 'TAB_DEEGREE_IDX', containing information on the table,
828 * geometry, indexname, owner and the foreign_key to the index table.
829 *
830 * @param fk_indexTree
831 * @throws IndexException
832 */
833 public void insertIndexMetadata( int fk_indexTree )
834 throws IndexException {
835
836 Connection con = null;
837 DBConnectionPool pool = null;
838 try {
839 pool = DBConnectionPool.getInstance();
840 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
841
842 StringBuilder sb = new StringBuilder( 100 );
843 sb.append( "INSERT INTO TAB_DEEGREE_IDX ( " );
844 if ( backend.equals( "INGRES" ) || backend.equals( "HSQLDB" ) ) {
845 sb.append( "ID, " );
846 }
847 sb.append( "column_name, table_name, " );
848 sb.append( "owner, INDEX_NAME, FK_indexTree ) " );
849 sb.append( "VALUES ( " );
850 if ( backend.equals( "INGRES" ) || backend.equals( "HSQLDB" ) ) {
851 Statement stm = con.createStatement();
852 ResultSet rs = stm.executeQuery( "SELECT MAX(ID) FROM TAB_QUADTREE" );
853 rs.next();
854 int myid = rs.getInt( 1 ) + 1;
855 sb.append( myid + ", " );
856 }
857 sb.append( "?, ?, ?, ?, ? ) " );
858 PreparedStatement stmt = con.prepareStatement( sb.toString() );
859 stmt.setString( 1, column );
860 stmt.setString( 2, table );
861 stmt.setString( 3, owner );
862 stmt.setString( 4, indexName );
863 stmt.setInt( 5, fk_indexTree );
864
865 stmt.execute();
866 stmt.close();
867 } catch ( SQLException e ) {
868 throw new IndexException( "Could not insert a new row into the quadtree index metadata table (did you run the base/scripts/index/quadtree.hsql script, which creates the meta-info tables?). The error message was: " + e.getMessage() );
869 } catch ( DBPoolException e ) {
870 throw new IndexException( "Could not acquire a connection to the database to store the quattree index metadata structure because: " + e.getMessage() );
871 } finally {
872 try {
873 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
874 } catch ( DBPoolException e ) {
875 LOG.logError( "Could not release JDBC connection because: " + e.getMessage() );
876 }
877 }
878 }
879
880 /**
881 * creates table the shape data shall be stored
882 *
883 * @param fileName
884 * @param idType
885 * the type of the feature_id column, for example VARCHAR(50) or NUMBER.
886 * @throws IndexException
887 * @throws IOException
888 */
889 protected void createDataTable( String fileName, String idType )
890 throws IndexException, IOException {
891 ShapeFile sf = new ShapeFile( fileName );
892 FeatureType ft = null;
893 try {
894 ft = sf.getFeatureByRecNo( 1 ).getFeatureType();
895 } catch ( HasNoDBaseFileException e ) {
896 throw new IndexException( e );
897 } catch ( DBaseException e ) {
898 throw new IndexException( e );
899 }
900 sf.close();
901 StringBuilder sb = new StringBuilder( 1000 );
902 sb.append( "CREATE TABLE " ).append( table ).append( '(' );
903
904 sb.append( "FEATURE_ID " ).append( idType ).append( "," );
905 PropertyType[] ftp = ft.getProperties();
906 for ( int i = 0; i < ftp.length; i++ ) {
907 if ( ftp[i].getType() == Types.GEOMETRY ) {
908 sb.append( column ).append( ' ' );
909 } else {
910 sb.append( ftp[i].getName().getLocalName() ).append( ' ' );
911 }
912 sb.append( getDatabaseType( ftp[i].getType() ) );
913 if ( i < ftp.length - 1 ) {
914 sb.append( ", " );
915 }
916 }
917 sb.append( ')' );
918
919 Connection con = null;
920 DBConnectionPool pool = null;
921 try {
922 pool = DBConnectionPool.getInstance();
923 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
924
925 Statement stmt = con.createStatement();
926 LOG.logDebug( sb.toString() );
927 stmt.execute( sb.toString() );
928 stmt.close();
929 } catch ( SQLException e ) {
930 throw new IndexException( "Could not create a DataTable: '" + table
931 + "' (which will hold the features from the shapefile: '"
932 + fileName
933 + "'). The error message was: "
934 + e.getMessage(), e );
935 } catch ( DBPoolException e ) {
936 throw new IndexException( "Could not acquire a connection to the database to create a DataTable because: " + e.getMessage(),
937 e );
938 } finally {
939 try {
940 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
941 } catch ( DBPoolException e ) {
942 LOG.logError( "Could not release JDBC connection because: " + e.getMessage() );
943 }
944 }
945 }
946
947 /**
948 * returns the type name for a generic type code as used by SQLServer
949 *
950 * @param dataTypeCode
951 * @return the type name for a generic type code as used by SQLServer
952 * @throws IndexException
953 */
954 String getDatabaseType( int dataTypeCode ) {
955 String type = null;
956
957 switch ( dataTypeCode ) {
958 case Types.CHAR:
959 case Types.VARCHAR:
960 type = DBQuadtreeDataTypes.getString( backend + ".string" );
961 break;
962 case Types.SMALLINT:
963 case Types.TINYINT:
964 case Types.INTEGER:
965 case Types.BIGINT:
966 type = DBQuadtreeDataTypes.getString( backend + ".integer" );
967 break;
968 case Types.DOUBLE:
969 case Types.FLOAT:
970 case Types.DECIMAL:
971 case Types.NUMERIC:
972 type = DBQuadtreeDataTypes.getString( backend + ".float" );
973 break;
974 case Types.DATE:
975 case Types.TIME:
976 case Types.TIMESTAMP:
977 type = DBQuadtreeDataTypes.getString( backend + ".datetime" );
978 break;
979 case Types.GEOMETRY:
980 type = DBQuadtreeDataTypes.getString( backend + ".geometry" );
981 break;
982 default:
983 throw new InvalidParameterException( "Unknown data type code: " + dataTypeCode );
984 }
985
986 return type;
987 }
988
989 /**
990 * imports a shape into the database and builds a quadtree on it
991 *
992 * @param fileName
993 * of the shapefile.
994 * @throws IOException
995 * if the shapefile could not be opened.
996 * @throws IndexException
997 * if an error occurred while talking to the jdbc database.
998 * @throws DBaseException
999 * if the connection to the shapefile could not be opened.
1000 * @throws HasNoDBaseFileException
1001 * if the feature could not be read from shape file's database file.
1002 */
1003 public void importShape( String fileName )
1004 throws IOException, IndexException, HasNoDBaseFileException,
1005 DBaseException {
1006 if ( TYPE == Integer.MIN_VALUE ) {
1007 LOG.logInfo( "You supplied an unknown type to the DBQuadtreeManager, therefore assuming you meant the Types.VARCHAR type" );
1008 TYPE = Types.VARCHAR;
1009 }
1010 StringBuilder typeName = new StringBuilder( 64 );
1011
1012 typeName.append( getDatabaseType( TYPE ) );
1013
1014 createDataTable( fileName, typeName.toString() );
1015
1016 int qtid = initQuadtree( fileName );
1017
1018 insertIndexMetadata( qtid );
1019
1020 qt = new DBQuadtree<T>( qtid, indexName, jdbc );
1021
1022 ShapeFile sf = new ShapeFile( fileName );
1023
1024 double step = 100.0 / sf.getRecordNum();
1025 double counter = 0;
1026 Envelope sfEnv = sf.getFileMBR();
1027
1028 LOG.logDebug( "The shape file read " + sf.getRecordNum() + " number of records" );
1029 for ( int i = 0; i < sf.getRecordNum(); i++ ) {
1030 Feature feat = sf.getFeatureByRecNo( i + 1 );
1031 if ( counter < step * i ) {
1032 if ( step < 1 ) {
1033 counter += 10;
1034 } else {
1035 counter += step;
1036 }
1037 System.out.println( counter + "%" );
1038 }
1039 if ( i % 200 == 0 ) {
1040 System.gc();
1041 }
1042 Envelope env = feat.getDefaultGeometryPropertyValue().getEnvelope();
1043 LOG.logDebug( i + " --- " + env );
1044 if ( env == null ) {
1045 // must be a point geometry
1046 Point point = (Point) feat.getDefaultGeometryPropertyValue();
1047 double w = sfEnv.getWidth() / 1000;
1048 double h = sfEnv.getHeight() / 1000;
1049 env = GeometryFactory.createEnvelope( point.getX() - w / 2d,
1050 point.getY() - h / 2d,
1051 point.getX() + w / 2d,
1052 point.getY() + h / 2d,
1053 null );
1054 }
1055 // map to the requested featuretype id's type
1056 T id = getMappedID( i );
1057 LOG.logDebug( "Inserting item : " + i );
1058 qt.insert( id, env );
1059 storeFeature( feat, id, jdbc );
1060 }
1061
1062 if ( "HSQLDB".equals( backend ) ) {
1063 LOG.logInfo( "Because you are using an hsql database, the current thread will wait '10' seconds, this gives the inmemory database time to flush it's tables" );
1064 try {
1065 Thread.sleep( 10000 );
1066 } catch ( InterruptedException e ) {
1067 LOG.logError( "Exception occurred while waitig for the db-manager to flush it's memory tables. Message: " + e.getMessage(),
1068 e );
1069 }
1070 }
1071 sf.close();
1072 LOG.logInfo( "finished!" );
1073 }
1074
1075 @SuppressWarnings("unchecked")
1076 private T getMappedID( int i ) {
1077 if ( TYPE == Types.VARCHAR ) {
1078 return (T) UUID.randomUUID().toString();
1079 } else if ( TYPE == Types.INTEGER ) {
1080 return (T) new Integer( i );
1081 }
1082 return null;
1083
1084 }
1085
1086 /**
1087 * appends the features of a shape to an existing datatable and inserts references into the assigned quadtree table.
1088 * <p>
1089 * you have to consider that the quadtree is just valid for a defined area. if the features to append exceeds this
1090 * area the quadtree has to be rebuilded.
1091 * </p>
1092 *
1093 * @param fileName
1094 * @throws IOException
1095 * if the shape file cannot be read.
1096 * @throws IndexException
1097 * if the quatree could not be read.
1098 */
1099 public void appendShape( String fileName )
1100 throws IOException, IndexException {
1101
1102 ShapeFile sf = new ShapeFile( fileName );
1103
1104 int b = sf.getRecordNum() / 100;
1105 if ( b == 0 )
1106 b = 1;
1107 int k = 0;
1108 qt = getQuadtree();
1109 Envelope sfEnv = sf.getFileMBR();
1110 int cnt = getMaxIdValue();
1111
1112 for ( int i = 0; i < sf.getRecordNum(); i++ ) {
1113 Feature feat = null;
1114 try {
1115 feat = sf.getFeatureByRecNo( i + 1 );
1116 } catch ( HasNoDBaseFileException e ) {
1117 throw new IndexException( e );
1118 } catch ( DBaseException e ) {
1119 throw new IndexException( e );
1120 }
1121 if ( i % b == 0 ) {
1122 System.out.println( k + "%" );
1123 k++;
1124 }
1125 if ( i % 200 == 0 ) {
1126 System.gc();
1127 }
1128 Envelope env = feat.getDefaultGeometryPropertyValue().getEnvelope();
1129 if ( env == null ) {
1130 // must be a point geometry
1131 Point point = (Point) feat.getDefaultGeometryPropertyValue();
1132 double w = sfEnv.getWidth() / 1000;
1133 double h = sfEnv.getHeight() / 1000;
1134 env = GeometryFactory.createEnvelope( point.getX() - w / 2d,
1135 point.getY() - h / 2d,
1136 point.getX() + w / 2d,
1137 point.getY() + h / 2d,
1138 null );
1139 }
1140 // map to the requested featuretype id's type
1141 T id = getMappedID( cnt + i + 1 );
1142 qt.insert( id, env );
1143 storeFeature( feat, id, jdbc );
1144 }
1145 LOG.logInfo( " finished!" );
1146 sf.close();
1147 }
1148
1149 /**
1150 * returns the maximum ID of the data table
1151 *
1152 * @return the maximum ID of the data table
1153 * @throws IndexException
1154 */
1155 private int getMaxIdValue()
1156 throws IndexException {
1157 if ( TYPE != Types.INTEGER ) {
1158 return 0;
1159 }
1160 String sql = "SELECT MAX( FEATURE_ID ) FROM " + table;
1161
1162 Connection con = null;
1163 DBConnectionPool pool = null;
1164 Statement stmt = null;
1165 int maxId = 0;
1166 try {
1167 pool = DBConnectionPool.getInstance();
1168 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
1169
1170 stmt = con.createStatement();
1171 LOG.logDebug( sql );
1172 ResultSet rs = stmt.executeQuery( sql );
1173 if ( rs.next() ) {
1174 maxId = rs.getInt( 1 );
1175 }
1176 } catch ( SQLException e ) {
1177 throw new IndexException( "Error while executing the sql statement while finding the max( Faeture_Id ) from table: " + table,
1178 e );
1179 } catch ( DBPoolException e ) {
1180 throw new IndexException( "Could not acquire a jdbc connection to read the max( Faeture_Id ) from table: " + table,
1181 e );
1182 } finally {
1183 try {
1184 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
1185 } catch ( DBPoolException e ) {
1186 LOG.logError( "Could not release JDBC connection because: " + e.getMessage() );
1187 }
1188 }
1189
1190 return maxId;
1191 }
1192
1193 /**
1194 * Creates actually two tables, an indextable, which will hold the actual quadtree and an index_item table which is
1195 * a join-table between the dbNodes and the feature_ids.
1196 *
1197 * @param indexTable
1198 * name of the index table.
1199 * @param idType
1200 * the type of the feature_id column, for example VARCHAR(50) or NUMBER.
1201 * @throws IndexException
1202 * if the table could not be created.
1203 */
1204 protected void createIndexTable( String indexTable, String idType )
1205 throws IndexException {
1206 StringBuilder sb = new StringBuilder( 2000 );
1207 String qtDataType = getDatabaseType( Types.VARCHAR );
1208 sb.append( "CREATE TABLE " ).append( indexTable ).append( " ( " );
1209 sb.append( "ID " ).append( qtDataType ).append( " NOT NULL," );
1210 sb.append( "minx float NOT NULL," );
1211 sb.append( "miny float NOT NULL," );
1212 sb.append( "maxx float NOT NULL," );
1213 sb.append( "maxy float NOT NULL," );
1214 sb.append( "FK_SUBNODE1 " ).append( qtDataType );
1215 sb.append( ", FK_SUBNODE2 " ).append( qtDataType );
1216 sb.append( ", FK_SUBNODE3 " ).append( qtDataType );
1217 sb.append( ", FK_SUBNODE4 " ).append( qtDataType ).append( ")" );
1218
1219 StringBuilder sb2 = new StringBuilder( 1000 );
1220 sb2.append( "CREATE TABLE " ).append( indexName ).append( "_ITEM ( " );
1221 sb2.append( "FK_QTNODE " ).append( qtDataType ).append( " NOT NULL," );
1222 sb2.append( "FK_ITEM " ).append( idType ).append( " NOT NULL )" );
1223
1224 Connection con = null;
1225 DBConnectionPool pool = null;
1226 try {
1227 pool = DBConnectionPool.getInstance();
1228 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
1229
1230 Statement stmt = con.createStatement();
1231 stmt.execute( sb.toString() );
1232 stmt.close();
1233
1234 stmt = con.createStatement();
1235 stmt.execute( sb2.toString() );
1236 stmt.close();
1237 } catch ( SQLException e ) {
1238 throw new IndexException( "Could not create the indextable: '" + indexTable
1239 + "' and/or the index_item table: '"
1240 + indexTable
1241 + "_ITEM'. The error message was: "
1242 + e.getMessage(), e );
1243 } catch ( DBPoolException e ) {
1244 throw new IndexException( "Could not acquire a connection to the database to store create the necessary tables: " + e.getMessage(),
1245 e );
1246 } finally {
1247 try {
1248 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
1249 } catch ( DBPoolException e ) {
1250 LOG.logError( "Could not release JDBC connection because: " + e.getMessage() );
1251 }
1252 }
1253 }
1254
1255 /**
1256 * Executes a simple select from indextable, and returns true if no SQL exception occurred.
1257 * @return true if a select * from indextable resulted in no exceptions, false otherwise.
1258 */
1259 private boolean hasIndexTable() {
1260 DBConnectionPool pool = DBConnectionPool.getInstance();
1261 Connection con = null;
1262 try {
1263 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
1264 } catch ( DBPoolException e ) {
1265 LOG.logError( "Could not aqcuire connection to the database backend because: " + e.getMessage(), e );
1266 return false;
1267 } finally {
1268 try {
1269 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
1270 } catch ( Exception e1 ) {
1271 LOG.logError( "Could not release the jdbc connection because: " + e1.getMessage() );
1272 }
1273 }
1274
1275 try {
1276 Statement stmt = con.createStatement();
1277 stmt.execute( "SELECT * from " + indexName );
1278 } catch ( SQLException e ) {
1279 return false;
1280 }
1281
1282 return true;
1283 }
1284
1285
1286 }