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