001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/csw/manager/HarvestRepository.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 ---------------------------------------------------------------------------*/
044 package org.deegree.ogcwebservices.csw.manager;
045
046 import java.io.IOException;
047 import java.io.InputStream;
048 import java.net.URI;
049 import java.net.URISyntaxException;
050 import java.net.URL;
051 import java.sql.Connection;
052 import java.sql.PreparedStatement;
053 import java.sql.ResultSet;
054 import java.sql.SQLException;
055 import java.sql.Statement;
056 import java.sql.Timestamp;
057 import java.util.ArrayList;
058 import java.util.Date;
059 import java.util.Iterator;
060 import java.util.List;
061 import java.util.Properties;
062
063 import org.deegree.datatypes.time.TimeDuration;
064 import org.deegree.framework.log.ILogger;
065 import org.deegree.framework.log.LoggerFactory;
066 import org.deegree.io.DBConnectionPool;
067 import org.deegree.io.DBPoolException;
068 import org.deegree.io.JDBCConnection;
069
070 /**
071 * A harvest repository is a database that stores harvest requests and that caches basic record
072 * informations to optimizes harvesting of large sources (e.g. other catalogues). This class
073 * encapsulates access to this database.
074 *
075 *
076 * @version $Revision: 9345 $
077 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
078 * @author last edited by: $Author: apoth $
079 *
080 * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
081 */
082 class HarvestRepository {
083
084 private static final ILogger LOG = LoggerFactory.getLogger( HarvestRepository.class );
085
086 private static final URL url = HarvestRepository.class.getResource( "harvestrepository.properties" );
087
088 private static HarvestRepository repository = null;
089
090 private static DBConnectionPool pool = DBConnectionPool.getInstance();
091
092 private JDBCConnection jdbc = null;
093
094 private Properties prop = null;
095
096 // possible metadata source types
097 static enum ResourceType {
098 catalogue, service, csw_profile, FGDC, dublincore, unknown
099 };
100
101 /**
102 * returns an instance of a <code>HarvestRepository</code>
103 *
104 * @return an instance of a <code>HarvestRepository</code>
105 * @throws IOException
106 */
107 static HarvestRepository getInstance()
108 throws IOException {
109 if ( repository == null ) {
110 repository = new HarvestRepository();
111 }
112 return repository;
113 }
114
115 /**
116 *
117 * @param jdbc
118 */
119 private HarvestRepository() throws IOException {
120 prop = new Properties();
121 InputStream is = url.openStream();
122 prop.load( is );
123 is.close();
124 jdbc = new JDBCConnection( prop.getProperty( "harvester.Driver" ),
125 prop.getProperty( "harvester.Url" ),
126 prop.getProperty( "harvester.User" ),
127 prop.getProperty( "harvester.Password" ), null, null, null );
128 }
129
130 /**
131 * stores a harvest request
132 *
133 * @param request
134 * @throws DBPoolException
135 * @throws SQLException
136 */
137 synchronized void storeRequest( Harvest request )
138 throws DBPoolException, SQLException {
139
140 LOG.logDebug( "storing harvest request into harvest repository ..." );
141
142 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
143 jdbc.getPassword() );
144 try {
145 con.setAutoCommit( false );
146 } catch ( Exception ignore ) {
147 }
148
149 try {
150 // insert into harvestsource table
151 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.storeRequest1" ) );
152 ps.setString( 1, request.getSource().toASCIIString() );
153 TimeDuration td = request.getHarvestInterval();
154 if ( td != null ) {
155 ps.setLong( 2, td.getAsMilliSeconds() / 1000 );
156 } else {
157 ps.setLong( 2, -1 );
158 }
159 ps.setTimestamp( 3, new Timestamp( request.getStartTimestamp().getTime() ) );
160 ps.setBoolean( 4, false );
161 if ( request.getResourceType() == null ) {
162 ps.setString( 5, "unknown" );
163 } else {
164 ps.setString( 5, request.getResourceType().toASCIIString() );
165 }
166 ps.execute();
167 ps.close();
168 Statement stmt = con.createStatement();
169 ResultSet rs = stmt.executeQuery( "select max(id) from harvestsource" );
170 rs.next();
171 int id1 = rs.getInt( 1 );
172 rs.close();
173 stmt.close();
174
175 // insert into responsehandler table and assigns to harvestsource by
176 // performing an insert into jt_source_responsehandler
177 List<URI> list = request.getResponseHandler();
178 for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
179 URI handler = (URI) iter.next();
180 ps = con.prepareStatement( prop.getProperty( "harvester.storeRequest2" ) );
181 ps.setString( 1, handler.toASCIIString() );
182 ps.setBoolean( 2, handler.toASCIIString().toLowerCase().startsWith( "mailto:" ) );
183 ps.execute();
184 ps.close();
185
186 stmt = con.createStatement();
187 rs = stmt.executeQuery( "select max(id) from responsehandler" );
188 rs.next();
189 int id2 = rs.getInt( 1 );
190 rs.close();
191 stmt.close();
192
193 ps = con.prepareStatement( prop.getProperty( "harvester.storeRequest3" ) );
194 ps.setInt( 1, id1 );
195 ps.setInt( 2, id2 );
196 ps.execute();
197 ps.close();
198 }
199
200 con.commit();
201 } catch ( SQLException e ) {
202 con.rollback();
203 e.printStackTrace();
204 throw new SQLException( getClass().getName() + " storeRequest(..) " + e.getMessage() );
205 } catch ( Exception e ) {
206 con.rollback();
207 e.printStackTrace();
208 throw new SQLException( getClass().getName() + " storeRequest(..) "
209 + "could not insert harvest request into repository: "
210 + e.getMessage() );
211 } finally {
212 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
213 jdbc.getPassword() );
214 }
215 }
216
217 /**
218 * drops a request from the backend
219 *
220 * @param source
221 * @throws DBPoolException
222 * @throws SQLException
223 */
224 synchronized void dropRequest( URI source )
225 throws DBPoolException, SQLException {
226
227 LOG.logDebug( "dropping harvest request from harvest repository ..." );
228
229 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
230 jdbc.getPassword() );
231 try {
232 con.setAutoCommit( false );
233 } catch ( Exception ignore ) {
234 }
235
236 try {
237 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.dropRequest1" ) );
238 ps.setString( 1, source.toASCIIString() );
239 ResultSet rs = ps.executeQuery();
240 rs.next();
241 int id1 = rs.getInt( 1 );
242 rs.close();
243 ps = con.prepareStatement( prop.getProperty( "harvester.dropRequest2" ) );
244 ps.setInt( 1, id1 );
245 rs = ps.executeQuery();
246 List<Integer> handlers = new ArrayList<Integer>();
247 while ( rs.next() ) {
248 handlers.add( rs.getInt( 1 ) );
249 }
250 rs.close();
251 ps.close();
252 // remove assigned entries from jointable
253 ps = con.prepareStatement( prop.getProperty( "harvester.dropRequest3" ) );
254 ps.setInt( 1, id1 );
255 ps.execute();
256 // remove assigend entries from reponse handler table
257 for ( int i = 0; i < handlers.size(); i++ ) {
258 Integer id = handlers.get( i );
259 ps = con.prepareStatement( prop.getProperty( "harvester.dropRequest4" ) );
260 ps.setInt( 1, id.intValue() );
261 ps.execute();
262 ps.close();
263 }
264 // remove records from cache table
265 ps = con.prepareStatement( prop.getProperty( "harvester.dropRequest5" ) );
266 ps.setInt( 1, id1 );
267 ps.execute();
268 ps.close();
269
270 // remove root from harvest source table
271 ps = con.prepareStatement( prop.getProperty( "harvester.dropRequest6" ) );
272 ps.setInt( 1, id1 );
273 ps.execute();
274 ps.close();
275
276 con.commit();
277
278 } catch ( SQLException e ) {
279 con.rollback();
280 throw e;
281 } catch ( Exception e ) {
282 con.rollback();
283 throw new SQLException( "could not frop request from repository: " + e.getMessage() );
284 } finally {
285 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
286 jdbc.getPassword() );
287 }
288
289 }
290
291 /**
292 * returns all sources registered to a harvest process
293 *
294 * @return all sources registered to a harvest process
295 * @throws DBPoolException
296 * @throws SQLException
297 * @throws URISyntaxException
298 */
299 synchronized List<URI> getSources()
300 throws DBPoolException, SQLException, URISyntaxException {
301
302 LOG.logDebug( "reading sources from harvest repository ..." );
303
304 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
305 jdbc.getPassword() );
306 List<URI> sources = new ArrayList<URI>();
307 try {
308 Statement stmt = con.createStatement();
309 ResultSet rs = stmt.executeQuery( prop.getProperty( "harvester.getSources" ) );
310 while ( rs.next() ) {
311 sources.add( new URI( rs.getString( 1 ) ) );
312 }
313 rs.close();
314 stmt.close();
315 } catch ( SQLException e ) {
316 throw e;
317 } catch ( URISyntaxException e ) {
318 throw e;
319 } finally {
320 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
321 jdbc.getPassword() );
322 }
323
324 return sources;
325 }
326
327 /**
328 * returns the type of the passed source
329 *
330 * @param source
331 * @return the type of the passed source
332 * @throws DBPoolException
333 * @throws SQLException
334 */
335 synchronized ResourceType getSourceType( URI source )
336 throws DBPoolException, SQLException {
337
338 LOG.logDebug( "reading sources type for source: " + source );
339
340 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
341 jdbc.getPassword() );
342 String s = null;
343
344 try {
345 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getSourceType" ) );
346 ps.setString( 1, source.toASCIIString() );
347 ResultSet rs = ps.executeQuery();
348 rs.next();
349 s = rs.getString( 1 );
350 rs.close();
351 ps.close();
352 } catch ( SQLException e ) {
353 throw e;
354 } finally {
355 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
356 jdbc.getPassword() );
357 }
358
359 ResourceType st = ResourceType.unknown;
360
361 if ( "csw:profile".equals( s ) ) {
362 st = ResourceType.csw_profile;
363 } else if ( "dublincore".equals( s ) ) {
364 st = ResourceType.dublincore;
365 } else if ( "FGDC".equals( s ) ) {
366 st = ResourceType.FGDC;
367 } else if ( "service".equals( s ) ) {
368 st = ResourceType.service;
369 } else if ( "catalogue".equals( s ) ) {
370 st = ResourceType.catalogue;
371 }
372
373 return st;
374 }
375
376 /**
377 * returns true if last harvesting iteration for the passed source has been successful
378 *
379 * @param source
380 *
381 * @return <code>true</code> if last harvesting iteration for the passed source has been
382 * successful
383 * @throws DBPoolException
384 * @throws SQLException
385 */
386 synchronized boolean getStatus( URI source )
387 throws DBPoolException, SQLException {
388
389 LOG.logDebug( "reading sources status for source: " + source );
390
391 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
392 jdbc.getPassword() );
393 boolean status = false;
394
395 try {
396 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getStatus" ) );
397 ps.setString( 1, source.toASCIIString() );
398 ResultSet rs = ps.executeQuery();
399 rs.next();
400 status = rs.getBoolean( 1 );
401 rs.close();
402 ps.close();
403 } catch ( SQLException e ) {
404 throw e;
405 } finally {
406 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
407 jdbc.getPassword() );
408 }
409
410 return status;
411 }
412
413 /**
414 * returns the <code>Date</code> a source has been harvested successful the last time
415 *
416 * @param source
417 * @return the <code>Date</code> a source has been harvested successful the last time
418 * @throws DBPoolException
419 * @throws SQLException
420 */
421 synchronized Date getLastHarvestingTimestamp( URI source )
422 throws DBPoolException, SQLException {
423
424 LOG.logDebug( "reading sources last harvesting timestamp for source: " + source );
425
426 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
427 jdbc.getPassword() );
428 Date date = null;
429 try {
430 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getLastHarvestingTimestamp" ) );
431 ps.setString( 1, source.toASCIIString() );
432 ResultSet rs = ps.executeQuery();
433 rs.next();
434 Timestamp ts = rs.getTimestamp( 1 );
435 rs.close();
436 ps.close();
437 if ( ts != null ) {
438 date = new Date( ts.getTime() );
439 }
440 } catch ( SQLException e ) {
441 throw e;
442 } finally {
443 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
444 jdbc.getPassword() );
445 }
446 return date;
447 }
448
449 /**
450 * sets the timestamp when a source has been harvested successfully for the last time
451 *
452 * @param source
453 * @param date
454 * @throws DBPoolException
455 * @throws SQLException
456 */
457 synchronized void setLastHarvestingTimestamp( URI source, Date date )
458 throws DBPoolException, SQLException {
459
460 LOG.logDebug( "set timestamp for source: " + source + " last harvesting" );
461
462 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
463 jdbc.getPassword() );
464 try {
465 con.setAutoCommit( false );
466 } catch ( Exception ignore ) {
467 }
468 try {
469 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.setLastHarvestingTimestamp" ) );
470 ps.setTimestamp( 1, new Timestamp( date.getTime() ) );
471 ps.setString( 2, source.toASCIIString() );
472 ps.execute();
473 ps.close();
474 con.commit();
475 } catch ( SQLException e ) {
476 con.rollback();
477 throw e;
478 } finally {
479 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
480 jdbc.getPassword() );
481 }
482 }
483
484 /**
485 * returns the next Date a source shall be harvested
486 *
487 * @param source
488 * @return the next Date a source shall be harvested
489 * @throws DBPoolException
490 * @throws SQLException
491 */
492 synchronized Date getNextHarvestingTimestamp( URI source )
493 throws DBPoolException, SQLException {
494 LOG.logDebug( "reading timestamp for source: " + source + " next harvesting" );
495
496 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
497 jdbc.getPassword() );
498 Date date = null;
499 try {
500 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getNextHarvestingTimestamp" ) );
501 ps.setString( 1, source.toASCIIString() );
502 ResultSet rs = ps.executeQuery();
503 rs.next();
504 Timestamp ts = rs.getTimestamp( 1 );
505 rs.close();
506 ps.close();
507 date = new Date( ts.getTime() );
508 } catch ( SQLException e ) {
509 throw e;
510 } finally {
511 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
512 jdbc.getPassword() );
513 }
514 return date;
515 }
516
517 /**
518 * sets the next date a source shall be harvested
519 *
520 * @param source
521 * @param date
522 * @throws DBPoolException
523 * @throws SQLException
524 */
525 synchronized void setNextHarvestingTimestamp( URI source, Date date )
526 throws DBPoolException, SQLException {
527
528 LOG.logDebug( "set timestamp for source: " + source + " last harvesting" );
529
530 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
531 jdbc.getPassword() );
532 try {
533 con.setAutoCommit( false );
534 } catch ( Exception ignore ) {
535 }
536 try {
537 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.setNextHarvestingTimestamp" ) );
538 ps.setTimestamp( 1, new Timestamp( date.getTime() ) );
539 ps.setString( 2, source.toASCIIString() );
540 ps.execute();
541 ps.close();
542 con.commit();
543 } catch ( SQLException e ) {
544 con.rollback();
545 } finally {
546 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
547 jdbc.getPassword() );
548 }
549
550 }
551
552 /**
553 * returns the interval in
554 *
555 * @param source
556 * @return
557 * @throws DBPoolException
558 * @throws SQLException
559 */
560 synchronized long getHarvestInterval( URI source )
561 throws DBPoolException, SQLException {
562
563 LOG.logDebug( "reading harvest interval for source: " + source );
564
565 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
566 jdbc.getPassword() );
567 long interval = 0;
568 try {
569 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getHarvestInterval" ) );
570 ps.setString( 1, source.toASCIIString() );
571 ResultSet rs = ps.executeQuery();
572 rs.next();
573 interval = rs.getLong( 1 ) * 1000l;
574 rs.close();
575 ps.close();
576 } catch ( SQLException e ) {
577 throw e;
578 } finally {
579 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
580 jdbc.getPassword() );
581 }
582
583 return interval;
584 }
585
586 /**
587 * returns a list
588 *
589 * @param source
590 * @return
591 * @throws DBPoolException
592 * @throws SQLException
593 * @throws URISyntaxException
594 */
595 synchronized List<ResponseHandler> getResponseHandlers( URI source )
596 throws DBPoolException, SQLException, URISyntaxException {
597
598 LOG.logDebug( "reading response handler for source: " + source );
599
600 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
601 jdbc.getPassword() );
602 List<ResponseHandler> list = new ArrayList<ResponseHandler>();
603 try {
604 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getResponseHandlers1" ) );
605 ps.setString( 1, source.toASCIIString() );
606 ResultSet rs = ps.executeQuery();
607 rs.next();
608 int id1 = rs.getInt( 1 );
609 rs.close();
610 ps.close();
611
612 ps = con.prepareStatement( prop.getProperty( "harvester.getResponseHandlers2" ) );
613 ps.setInt( 1, id1 );
614 rs = ps.executeQuery();
615 StringBuffer sb = new StringBuffer( " (" );
616 int kk = 0;
617 while ( rs.next() ) {
618 kk++;
619 sb.append( rs.getInt( 1 ) ).append( ',' );
620 }
621 rs.close();
622 ps.close();
623
624 if ( kk > 0 ) {
625 // just access response handler informations if available
626 String s = sb.substring( 0, sb.length() - 1 ) + ')';
627 ps = con.prepareStatement( prop.getProperty( "harvester.getResponseHandlers3" ) + s );
628 rs = ps.executeQuery();
629
630 while ( rs.next() ) {
631 String addr = rs.getString( 1 );
632 boolean isMail = rs.getBoolean( 2 );
633 list.add( new ResponseHandler( new URI( addr ), isMail ) );
634 }
635 rs.close();
636 ps.close();
637 }
638 } catch ( SQLException e ) {
639 throw e;
640 } catch ( URISyntaxException e ) {
641 throw e;
642 } finally {
643 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
644 jdbc.getPassword() );
645 }
646
647 return list;
648 }
649
650 /**
651 * returns a <code>Record</code> from the harvesters cache. A instance of a
652 * <code>Record</code> includes its fileIdentifier,the datestamp when it has been changed for
653 * the last time and the source it belongs too.
654 *
655 * @param source
656 * @param fileIdentifier
657 * @return a <code>Record</code> from the harvesters cache
658 * @throws DBPoolException
659 * @throws SQLException
660 */
661 synchronized Record getRecordByID( URI source, String fileIdentifier )
662 throws DBPoolException, SQLException {
663
664 LOG.logDebug( "reading record: " + fileIdentifier + " from harvest cache" );
665
666 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
667 jdbc.getPassword() );
668 Record record = null;
669 try {
670 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getRecordByID1" ) );
671 ps.setString( 1, source.toASCIIString() );
672 ResultSet rs = ps.executeQuery();
673 rs.next();
674 int id = rs.getInt( 1 );
675 rs.close();
676 ps.close();
677
678 ps = con.prepareStatement( prop.getProperty( "harvester.getRecordByID2" ) );
679 ps.setInt( 1, id );
680 ps.setString( 2, fileIdentifier );
681 rs = ps.executeQuery();
682
683 if ( rs.next() ) {
684 Date date = rs.getDate( 1 );
685 record = new Record( id, date, fileIdentifier, source );
686 }
687 rs.close();
688 ps.close();
689 } catch ( SQLException e ) {
690 throw e;
691 } finally {
692 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
693 jdbc.getPassword() );
694 }
695
696 return record;
697 }
698
699 /**
700 * stores a record into the cache table used by the harvester
701 *
702 * @param record
703 * @throws DBPoolException
704 * @throws SQLException
705 */
706 synchronized void storeRecord( Record record )
707 throws DBPoolException, SQLException {
708
709 LOG.logDebug( "storing record in cache; fileIdentifier: " + record.getFileIdentifier() );
710
711 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
712 jdbc.getPassword() );
713 try {
714 con.setAutoCommit( false );
715 } catch ( Exception ignore ) {
716 }
717 try {
718 String fid = record.getFileIdentifier();
719 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.storeRecord1" ) );
720 ps.setString( 1, fid );
721 ResultSet rs = ps.executeQuery();
722 rs.next();
723 int count = rs.getInt( 1 );
724 if ( count == 0 ) {
725 ps = con.prepareStatement( prop.getProperty( "harvester.storeRecord2" ) );
726 ps.setInt( 1, getSourceID( record.getSource() ) );
727 ps.setString( 2, fid );
728 ps.setTimestamp( 3, new Timestamp( record.getDatestamp().getTime() ) );
729 ps.execute();
730 ps.close();
731
732 con.commit();
733 }
734
735 } catch ( SQLException e ) {
736 con.rollback();
737 throw e;
738 } catch ( Exception e ) {
739 con.rollback();
740 throw new SQLException( "could not insert harvest request " + "into repository: "
741 + e.getMessage() );
742 } finally {
743 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
744 jdbc.getPassword() );
745 }
746
747 }
748
749 /**
750 * updates a record within the cache table used by the harvester
751 *
752 * @param record
753 * @throws DBPoolException
754 * @throws SQLException
755 */
756 synchronized void updateRecord( Record record )
757 throws DBPoolException, SQLException {
758
759 LOG.logDebug( "updating record in cache; fileIdentifier: " + record.getFileIdentifier() );
760
761 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
762 jdbc.getPassword() );
763 try {
764 con.setAutoCommit( false );
765 } catch ( Exception ignore ) {
766 }
767 try {
768 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.updateRecord" ) );
769 ps.setDate( 1, new java.sql.Date( record.getDatestamp().getTime() ) );
770 ps.setString( 2, record.getFileIdentifier() );
771 ps.setInt( 3, record.getSourceId() );
772 ps.execute();
773 ps.close();
774
775 con.commit();
776
777 } catch ( SQLException e ) {
778 con.rollback();
779 throw e;
780 } catch ( Exception e ) {
781 con.rollback();
782 throw new SQLException( "could not insert harvest request " + "into repository: "
783 + e.getMessage() );
784 } finally {
785 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
786 jdbc.getPassword() );
787 }
788
789 }
790
791 /**
792 * drops a record from the cache table used by the harvester
793 *
794 * @param record
795 * @throws DBPoolException
796 * @throws SQLException
797 */
798 synchronized void dropRecord( Record record )
799 throws DBPoolException, SQLException {
800
801 LOG.logDebug( "deleting record from cache; fileIdentifier: " + record.getFileIdentifier() );
802
803 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
804 jdbc.getPassword() );
805 try {
806 con.setAutoCommit( false );
807 } catch ( Exception ignore ) {
808 }
809 try {
810
811 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.dropRecord" ) );
812 ps.setString( 1, record.getFileIdentifier() );
813 ps.setInt( 2, record.getSourceId() );
814 ps.execute();
815 ps.close();
816
817 con.commit();
818
819 } catch ( SQLException e ) {
820 con.rollback();
821 throw e;
822 } catch ( Exception e ) {
823 con.rollback();
824 throw new SQLException( "could not insert harvest request " + "into repository: "
825 + e.getMessage() );
826 } finally {
827 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
828 jdbc.getPassword() );
829 }
830
831 }
832
833 /**
834 * returns fileidentifiers of all records assigend to a source from the harvest cache
835 *
836 * @param source
837 * @return fileidentifiers of all records assigend to a source from the harvest cache
838 * @throws DBPoolException
839 * @throws SQLException
840 */
841 synchronized List<String> getAllRecords( URI source )
842 throws DBPoolException, SQLException {
843
844 LOG.logDebug( "getting list of all record fileidentifiers for source: " + source
845 + " from cache" );
846
847 List<String> fileIds = new ArrayList<String>( 10000 );
848
849 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
850 jdbc.getPassword() );
851 try {
852 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getAllRecords1" ) );
853 ps.setString( 1, source.toASCIIString() );
854 ResultSet rs = ps.executeQuery();
855 rs.next();
856 int id = rs.getInt( 1 );
857 rs.close();
858 ps.close();
859
860 ps = con.prepareStatement( prop.getProperty( "harvester.getAllRecords2" ) );
861 ps.setInt( 1, id );
862 rs = ps.executeQuery();
863 while ( rs.next() ) {
864 fileIds.add( rs.getString( 1 ) );
865 }
866 rs.close();
867 ps.close();
868 } catch ( SQLException e ) {
869 throw e;
870 } finally {
871 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
872 jdbc.getPassword() );
873 }
874
875 return fileIds;
876 }
877
878 /**
879 * returns the row ID of the passed source
880 *
881 * @param source
882 * @return the row ID of the passed source
883 * @throws DBPoolException
884 * @throws SQLException
885 */
886 synchronized int getSourceID( URI source )
887 throws DBPoolException, SQLException {
888 LOG.logDebug( "reading row ID of source: " + source );
889
890 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
891 jdbc.getPassword() );
892 int id = -1;
893 try {
894 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.getSourceID" ) );
895 ps.setString( 1, source.toASCIIString() );
896 ResultSet rs = ps.executeQuery();
897 rs.next();
898 id = rs.getInt( 1 );
899 rs.close();
900 ps.close();
901 } catch ( SQLException e ) {
902 throw e;
903 } finally {
904 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
905 jdbc.getPassword() );
906 }
907
908 return id;
909 }
910
911 /**
912 * returs true is a harvesting shall be forced outside the regular harvesting interval
913 *
914 * @param source
915 * @return true if a CSW shall be harvested outside the regular harvesting interval
916 * @throws DBPoolException
917 */
918 synchronized boolean shallForceHarvesting(URI source) throws DBPoolException {
919 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
920 jdbc.getPassword() );
921 boolean force = false;
922 try {
923 PreparedStatement ps = con.prepareStatement( prop.getProperty( "harvester.forceHarvesting" ) );
924 ps.setString( 1, source.toASCIIString() );
925 ResultSet rs = ps.executeQuery();
926 rs.next();
927 force = rs.getInt( 1 ) == 1;
928 rs.close();
929 ps.close();
930 } catch ( Exception e ) {
931 // TODO
932 // this is because downward compliance; older CSW does not know the requested field
933 // harvestsource.forceharvesting
934 //throw e;
935 } finally {
936 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(),
937 jdbc.getPassword() );
938 }
939 return force;
940 }
941
942 /**
943 * inner class for encapsulating response handler informations
944 *
945 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
946 * @author last edited by: $Author: apoth $
947 *
948 * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
949 */
950 class ResponseHandler {
951
952 private URI uri = null;
953
954 private boolean isMailAddress = false;
955
956 /**
957 * @param uri
958 * @param isMailAddress
959 */
960 ResponseHandler( URI uri, boolean isMailAddress ) {
961 this.uri = uri;
962 this.isMailAddress = isMailAddress;
963 }
964
965 /**
966 * @return
967 */
968 boolean isMailAddress() {
969 return isMailAddress;
970 }
971
972 /**
973 * @return uri
974 */
975 URI getUri() {
976 return uri;
977 }
978
979 }
980
981 /**
982 *
983 *
984 *
985 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
986 * @author last edited by: $Author: apoth $
987 *
988 * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
989 *
990 */
991 public class Record {
992
993 private Date datestamp = null;
994
995 private String fileIdentifier = null;
996
997 private URI source = null;
998
999 private int sourceId;
1000
1001 /**
1002 * @param sourceId
1003 * @param datestamp
1004 * @param fileIdentifier
1005 * @param source
1006 */
1007 public Record( int sourceId, Date datestamp, String fileIdentifier, URI source ) {
1008 this.datestamp = datestamp;
1009 this.fileIdentifier = fileIdentifier;
1010 this.source = source;
1011 this.sourceId = sourceId;
1012 }
1013
1014 /**
1015 * @return datestamp
1016 */
1017 public Date getDatestamp() {
1018 return datestamp;
1019 }
1020
1021 /**
1022 * @return fileIdentifier
1023 */
1024 public String getFileIdentifier() {
1025 return fileIdentifier;
1026 }
1027
1028 /**
1029 * @return source
1030 */
1031 public URI getSource() {
1032 return source;
1033 }
1034
1035 /**
1036 * @return sourceId
1037 */
1038 public int getSourceId() {
1039 return sourceId;
1040 }
1041
1042 }
1043
1044 }