001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/io/quadtree/DBQuadtree.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 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.ResultSet;
047 import java.sql.SQLException;
048 import java.sql.Statement;
049 import java.util.ArrayList;
050 import java.util.HashMap;
051 import java.util.List;
052 import java.util.Map;
053
054 import org.deegree.framework.log.ILogger;
055 import org.deegree.framework.log.LoggerFactory;
056 import org.deegree.io.DBConnectionPool;
057 import org.deegree.io.DBPoolException;
058 import org.deegree.io.JDBCConnection;
059 import org.deegree.model.spatialschema.Envelope;
060 import org.deegree.model.spatialschema.GeometryFactory;
061 import org.deegree.model.spatialschema.Point;
062
063 /**
064 *
065 *
066 *
067 * @version $Revision: 9342 $
068 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
069 * @author last edited by: $Author: apoth $
070 *
071 * @version 1.0. $Revision: 9342 $, $Date: 2007-12-27 13:32:57 +0100 (Do, 27 Dez 2007) $
072 * @param <T>
073 * the datatype to be used as id
074 *
075 * @since 2.0
076 */
077 public class DBQuadtree<T> implements Quadtree<T> {
078
079 private static ILogger LOG = LoggerFactory.getLogger( DBQuadtree.class );
080
081 private String fk_root;
082
083 private int depth;
084
085 private int id = 0;
086
087 private String indexName = null;
088
089 private JDBCConnection jdbc = null;
090
091 private Map<String, DBNode<T>> nodeCache = new HashMap<String, DBNode<T>>( 10000 );
092
093 private double accuracyX;
094
095 private double accuracyY;
096
097 private DBQuadtree.SupportedVersions version;
098
099 private Connection con = null;
100
101 private DBConnectionPool pool = null;
102
103 /**
104 * The <code>SupportedVersions</code> supported by this quatree
105 *
106 */
107 public static enum SupportedVersions {
108 /**
109 * the old version or 1.0.0
110 */
111 ONE,
112 /**
113 * The new version or "2.0.0"
114 */
115 TWO
116 }
117
118 /**
119 * Creates a Database with given version.
120 *
121 * @param id
122 * of the table which contains the features.
123 * @param indexName
124 * this name will be used to create the table that stores the nodes of a specific
125 * quadtree
126 * @param jdbc
127 * description of database connection
128 * @param version
129 * of the quadtree, which is usefull for the determination of the layout, if null
130 * then the version is assumed to be unknown and the old layout is used.
131 * @throws IndexException
132 */
133 public DBQuadtree( int id, String indexName, JDBCConnection jdbc, String version ) throws IndexException {
134 this( id, indexName, jdbc, 0.0001, 0.0001, version );
135 }
136
137 /**
138 * initializes a quadtree already existing in a database. New items will have a slightly larger
139 * bbox with 0.0001 added to each boundary, this is usefull for point geometries.
140 *
141 * @param id
142 * of the table which contains the features.
143 * @param indexName
144 * this name will be used to create the table that stores the nodes of a specific
145 * quadtree
146 * @param jdbc
147 * description of database connection
148 * @throws IndexException
149 * if the quadtree node with 'id' could not be read from the database.
150 */
151 public DBQuadtree( int id, String indexName, JDBCConnection jdbc ) throws IndexException {
152 this( id, indexName, jdbc, 0.0001, 0.0001, "1.0.0" );
153 }
154
155 /**
156 * initializes a quadtree already existing in a database
157 *
158 * @param id
159 * of the table which contains the features.
160 * @param indexName
161 * this name will be used to create the table that stores the nodes of a specific
162 * quadtree
163 * @param jdbc
164 * description of database connection
165 * @param accuracyX
166 * @param accuracyY
167 * @param version
168 * of the quadtree, which is usefull for the determination of the layout, if null
169 * then the version is assumed to be "1.0.0" (the first version) and the old layout
170 * is used.
171 * @throws IndexException
172 * if the quadtree node with 'id' could not be read from the database.
173 */
174 public DBQuadtree( int id, String indexName, JDBCConnection jdbc, double accuracyX, double accuracyY, String version )
175 throws IndexException {
176 this.id = id;
177 this.jdbc = jdbc;
178 this.indexName = indexName;
179 this.accuracyX = accuracyX;
180 this.accuracyY = accuracyY;
181 pool = DBConnectionPool.getInstance();
182 try {
183 con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
184 } catch ( DBPoolException e ) {
185 String msg = "Could not acquire a database connection for the quadtree, no possibility to go on!";
186 LOG.logError( msg + " Cause: " + e.getMessage() );
187 throw new IndexException( msg, e );
188 }
189
190 if ( version == null || !"2.0.0".equals( version.trim() ) ) {
191 this.version = SupportedVersions.ONE;
192 } else {
193 this.version = SupportedVersions.TWO;
194 }
195 readRootNodeId();
196 }
197
198 /**
199 *
200 * @param id
201 * @return node
202 */
203 DBNode<T> getFromCache( String id ) {
204 return nodeCache.get( id );
205 }
206
207 /**
208 *
209 * @param node
210 */
211 void addToCache( DBNode<T> node ) {
212 nodeCache.put( node.getId(), node );
213 }
214
215 /**
216 *
217 * @param node
218 */
219 DBNode<T> removeFromCache( DBNode<T> node ) {
220 return nodeCache.remove( node.getId() );
221 }
222
223 /**
224 * inserts a new item into a quadtree
225 *
226 * @param item
227 * @param envelope
228 */
229 public void insert( T item, Envelope envelope )
230 throws IndexException {
231 DBNode<T> node = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version );
232 node.insert( item, envelope );
233 }
234
235 /**
236 * @param item
237 * @param point
238 */
239 public void insert( T item, Point point )
240 throws IndexException {
241 DBNode<T> node = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version );
242 Envelope envelope = GeometryFactory.createEnvelope( point.getX() - accuracyX, point.getY() - accuracyY,
243 point.getX() + accuracyX, point.getY() + accuracyY, null );
244 node.insert( item, envelope );
245 }
246
247 /**
248 *
249 * @param envelope
250 * @return list a items intersecting with the passed envelope
251 */
252 public List<T> query( Envelope envelope )
253 throws IndexException {
254 LOG.logDebug( "Performing query for envelope: " + envelope );
255 // Thread.dumpStack();
256 List<T> visitor = new ArrayList<T>( 1000 );
257 DBNode<T> node = new DBNode<T>( fk_root, null, this, indexName, jdbc, 1, version );
258 envelope = envelope.createIntersection( node.getEnvelope() );
259 if ( envelope == null ) {
260 LOG.logDebug( "Found no intersection with the root element of the quadtree, returning an emtpy feature collection." );
261 return new ArrayList<T>();
262 }
263 return node.query( envelope, visitor, 1 );
264 }
265
266 /**
267 * deletes an item from a quadtree
268 *
269 * @param item
270 */
271 public void deleteItem( T item )
272 throws IndexException {
273 DBNode<T> root = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version );
274 root.delete( item, root.getEnvelope() );
275 }
276
277 /**
278 * updates the envelope of an item
279 *
280 * @param item
281 * @param newBBox
282 */
283 public void update( T item, Envelope newBBox )
284 throws IndexException {
285 Node<T> root = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version );
286 root.update( item, newBBox );
287 }
288
289 public void deleteRange( Envelope envelope ) {
290 throw new UnsupportedOperationException();
291 // TODO
292 // and even more magic
293 }
294
295 /**
296 * @return depth of a quadtree
297 */
298 public int getDepth() {
299 return depth;
300 }
301
302 /**
303 * @return true if the db connection could be released to the pool, false otherwise.
304 */
305 public boolean releaseConnection() {
306 try {
307 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() );
308 } catch ( DBPoolException e ) {
309 LOG.logError( "Could not release database connection because: " + e.getMessage() );
310 return false;
311 }
312 return true;
313 }
314
315 /**
316 * reads the root node from the database
317 *
318 * @throws IndexException
319 * if the database could not be loaded or no quadtree rootnode was found.
320 */
321 private void readRootNodeId()
322 throws IndexException {
323
324 try {
325 StringBuffer sb = new StringBuffer( 200 );
326 sb.append( "Select FK_ROOT, DEPTH from TAB_QUADTREE where ID = " );
327 sb.append( id );
328
329 Statement stmt = con.createStatement();
330 ResultSet rs = stmt.executeQuery( sb.toString() );
331 if ( rs.next() ) {
332 fk_root = rs.getString( "FK_ROOT" );
333 depth = rs.getInt( "DEPTH" );
334 } else {
335 throw new IndexException( "Could not read FK_ROOT and DEPTH for Quadtree with ID" + id );
336 }
337 rs.close();
338 stmt.close();
339 } catch ( SQLException e ) {
340 throw new IndexException( "Could not load quadtree definition from database because: " + e.getMessage() );
341 }
342
343 }
344
345 /**
346 * @return envelope of a quadtree's root node
347 */
348 public Envelope getRootBoundingBox()
349 throws IndexException {
350 DBNode<T> root = new DBNode<T>( fk_root, this, indexName, jdbc, 1, version );
351 return root.getEnvelope();
352 }
353
354 }