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