/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53115 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.ogcwebservices.csw.manager;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.mail.EMailMessage;
import org.deegree.framework.mail.MailHelper;
import org.deegree.framework.mail.MailMessage;
import org.deegree.framework.mail.SendMailException;
import org.deegree.framework.util.StringTools;
import org.deegree.framework.xml.NamespaceContext;
import org.deegree.framework.xml.XMLFragment;
import org.deegree.framework.xml.XMLParsingException;
import org.deegree.io.DBPoolException;
import org.deegree.ogcbase.CommonNamespaces;
import org.deegree.ogcwebservices.OGCWebServiceException;
import org.deegree.ogcwebservices.csw.CSWFactory;
import org.deegree.ogcwebservices.csw.manager.HarvestRepository.ResourceType;
import org.xml.sax.SAXException;
/**
* Abstract super class of all CS-W harvesters. For each kind of source a specialized harvester
* shall be implemented. A concrete implementation of AbstractHarvester will be called within a
* timer loop.
*
*
* @version $Revision: 1.15 $
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author: poth $
*
* @version 1.0. $Revision: 1.15 $, $Date: 2006/07/12 14:46:17 $
*
* @since 2.0
*/
public abstract class AbstractHarvester extends TimerTask {
private static final ILogger LOG = LoggerFactory.getLogger( AbstractHarvester.class );
private boolean stopped = true;
private Timer timer = null;
protected List<URI> inProgress = new Vector<URI>();
protected static NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
static {
try {
nsc.addNamespace( "smXML", new URI( "http://metadata.dgiwg.org/smXML" ) );
nsc.addNamespace( "iso19119", new URI( "http://schemas.opengis.net/iso19119" ) );
nsc.addNamespace( "iso19115", new URI( "http://schemas.opengis.net/iso19115full" ) );
} catch ( URISyntaxException e ) {
e.printStackTrace();
}
}
/**
* adds a request to the harvesting process
*
* @param request
* @throws SQLException
* @throws DBPoolException
*/
public void addRequest( Harvest request )
throws IOException, DBPoolException, SQLException {
HarvestRepository.getInstance().storeRequest( request );
}
/**
* returns true if the harvesting process is running
*
* @return
*/
public boolean isRunning() {
return !stopped;
}
/**
* removes a request from the harvesting request.
* <p>
* <b> !! At the moment the OGC CSW does not know a mechanism/request to stop a cyclic
* harvesting job, so this method can not be called with a standard OGC OWS request !!</b>
* </p>
*
* @param request
* @throws SQLException
* @throws DBPoolException
*/
public void removeRequest( Harvest request )
throws IOException, DBPoolException, SQLException {
HarvestRepository.getInstance().dropRequest( request.getSource() );
}
/**
* starts the harvesting process
*
*/
public void startHarvesting() {
timer = new Timer();
timer.schedule( this, 0, 10000 );
stopped = false;
LOG.logInfo( "harvesting has been started" );
}
/**
* stops the harvesting process
*
*/
public void stopHarvesting() {
timer.purge();
timer.cancel();
stopped = true;
LOG.logInfo( "harvesting has been stopped" );
}
/**
* informs all response handlers assigend to a source about successful harvesting of the source
*
* @param source
* @throws URISyntaxException
* @throws SQLException
* @throws DBPoolException
* @throws MalformedURLException
*/
protected void informResponseHandlers( URI source )
throws SendMailException, IOException, DBPoolException, SQLException,
URISyntaxException {
List<HarvestRepository.ResponseHandler> list = HarvestRepository.getInstance().getResponseHandlers(
source );
for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
HarvestRepository.ResponseHandler handler = (HarvestRepository.ResponseHandler) iter.next();
String message = "source: " + source + " has been harvested successfully!";
sendMessage( handler, message );
}
}
/**
* returns true if the passed source shall be harvested. this is true if a source has not been
* harvested before or the next harvesting timestamp has been reached and the source is of type
*
* @see HarvestRepository.ResourceType service
*
* @param source
* @return
* @throws DBPoolException
* @throws SQLException
*/
protected boolean shallHarvest( URI source, ResourceType targetType )
throws IOException, DBPoolException, SQLException {
if ( inProgress.contains( source ) ) {
return false;
}
HarvestRepository repository = HarvestRepository.getInstance();
ResourceType st = repository.getSourceType( source );
if ( !st.equals( targetType ) ) {
return false;
}
Date lastHarvesting = repository.getLastHarvestingTimestamp( source );
Date nextHarvesting = repository.getNextHarvestingTimestamp( source );
long tmp = System.currentTimeMillis() - nextHarvesting.getTime();
return lastHarvesting == null || tmp >= 0;
}
/**
* informs all response handlers assigend to a source about an exception that occurs when
* harvesting a source
*
* @param source
* @param e
* @throws URISyntaxException
* @throws SQLException
* @throws DBPoolException
*/
protected void informResponseHandlers( URI source, Exception e )
throws SendMailException, IOException, DBPoolException, SQLException,
URISyntaxException {
List<HarvestRepository.ResponseHandler> list = HarvestRepository.getInstance().getResponseHandlers(
source );
for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
HarvestRepository.ResponseHandler handler = (HarvestRepository.ResponseHandler) iter.next();
String message = StringTools.concat( 500, "exception occures harvesting source: ",
source, "; exception: ", e.getMessage() );
sendMessage( handler, message );
}
}
/**
*
* @param handler
* @param message
* @throws SendMailException
* @throws MalformedURLException
* @throws IOException
* @throws HttpException
*/
private void sendMessage( HarvestRepository.ResponseHandler handler, String message )
throws SendMailException {
if ( handler.isMailAddress() ) {
String s = handler.getUri().toASCIIString();
int p = s.indexOf( ":" );
s = s.substring( p + 1, s.length() );
LOG.logDebug( StringTools.concat( 200, "informing response handler ", s, "via mail" ) );
MailMessage mm = new EMailMessage( "info@lat-lon.de", s, "CS-W harvesting", message );
MailHelper.createAndSendMail( mm, System.getProperty( "mailHost" ) );
} else {
LOG.logDebug( StringTools.concat( 200, "informing response handler ", handler.getUri(),
"via HTTP GET" ) );
HttpClient client = new HttpClient();
System.out.println( message );
try {
GetMethod get = new GetMethod( handler.getUri().toURL().toExternalForm() +
"?message=" + message );
client.executeMethod( get );
} catch ( Exception e ) {
LOG.logInfo( "could not post message: '" + message + "' to: " + handler.getUri() +
"; reason: " + e.getMessage() );
}
}
}
/**
* abstract super class for all harvest processores
*
*
* @version $Revision: 1.15 $
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author: poth $
*
* @version 1.0. $Revision: 1.15 $, $Date: 2006/07/12 14:46:17 $
*
* @since 2.0
*/
protected abstract class AbstractHarvestProcessor extends Thread {
protected URI source = null;
protected AbstractHarvester owner = null;
protected AbstractHarvestProcessor( AbstractHarvester owner, URI source ) {
this.owner = owner;
this.source = source;
}
/**
* performs a transaction for inserting or updating a service meta data record in the
* catalogue a harvester instance belongs too
*
* @param trans
* @throws SAXException
* @throws IOException
* @throws XMLParsingException
* @throws OGCWebServiceException
*/
protected void performTransaction( String trans )
throws SAXException, IOException, OGCWebServiceException {
StringReader sr = new StringReader( trans );
XMLFragment xml = new XMLFragment();
xml.load( sr, XMLFragment.DEFAULT_URL );
Transaction transaction = Transaction.create( "id", xml.getRootElement() );
CSWFactory.getService().doService( transaction );
}
/**
* creates a CSW Transaction including an Update operation for the passed meta data.
*
* @param metaData
* @return
* @throws XMLParsingException
*/
protected String createUpdateRequest( String identifier, String xpath, XMLFragment metaData ) {
LOG.logDebug( "creating csw update request" );
StringBuffer sb = new StringBuffer( 50000 );
sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
sb.append( "<csw:Transaction xmlns:csw=\"http://www.opengis.net/cat/csw\" " );
sb.append( "xmlns:ogc=\"http://www.opengis.net/ogc\" >" );
sb.append( "<csw:Update>" );
String s = metaData.getAsString();
int p = s.lastIndexOf( "?>" );
if ( p > -1 ) {
s = s.substring( p + 2, s.length() );
}
sb.append( s );
sb.append( createConstraint( identifier, xpath ) );
sb.append( "</csw:Update></csw:Transaction>" );
return sb.toString();
}
/**
* creates a transaction request including a delete operation to remove the metadata record
* with the passed fileIdentifier from the catalogue
*
* @param identifier
* @return
*/
protected String createDeleteRequest( String identifier, String xpath ) {
LOG.logDebug( "creating csw delete request" );
StringBuffer sb = new StringBuffer( 2000 );
sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
sb.append( "<csw:Transaction xmlns:csw=\"http://www.opengis.net/cat/csw\" " );
sb.append( "xmlns:ogc=\"http://www.opengis.net/ogc\" >" );
sb.append( "<csw:Delete>" );
sb.append( createConstraint( identifier, xpath ) );
sb.append( "</csw:Delete></csw:Transaction>" );
return sb.toString();
}
/**
* a constraint for delete und update operation depends on concrete metadata format. An
* implementing class must consider this.
*
* @param fileIdentifier
* value to be compared
* @param xpath
* comparable property
* @return
*/
protected abstract StringBuffer createConstraint( String fileIdentifier, String xpath );
/**
* creates a CSW Transaction including an Update operation for the passed meta data
*
* @param metaData
* @return
*/
protected String createInsertRequest( XMLFragment metaData ) {
LOG.logDebug( "creating csw insert request" );
StringBuffer sb = new StringBuffer( 50000 );
sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
sb.append( "<csw:Transaction xmlns:csw=\"http://www.opengis.net/cat/csw\">" );
sb.append( "<csw:Insert>" );
String s = metaData.getAsString();
int p = s.lastIndexOf( "?>" );
if ( p > -1 ) {
s = s.substring( p + 2, s.length() );
}
sb.append( s );
sb.append( "</csw:Insert></csw:Transaction>" );
return sb.toString();
}
/**
* actualizes the source in the repository with timestamp of last harvesting
*
* @param source
* @param date
* @throws SQLException
* @throws DBPoolException
*/
protected void writeLastHarvestingTimestamp( URI source, Date date )
throws IOException, DBPoolException, SQLException {
HarvestRepository repository = HarvestRepository.getInstance();
repository.setLastHarvestingTimestamp( source, date );
}
/**
* actualizes the source in the repository with timestamp when next harvesting shall be
* performed
*
* @param source
* @param date
* @throws SQLException
* @throws DBPoolException
*/
protected void writeNextHarvestingTimestamp( URI source, Date date )
throws IOException, DBPoolException, SQLException {
HarvestRepository repository = HarvestRepository.getInstance();
long ts = repository.getHarvestInterval( source );
date = new Date( ts + date.getTime() );
repository.setNextHarvestingTimestamp( source, date );
}
}
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: AbstractHarvester.java,v $
Revision 1.15 2006/07/12 14:46:17 poth
comment footer added
********************************************************************** */