/*---------------- 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.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.transform.TransformerException; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.FileUtils; import org.deegree.framework.util.StringTools; import org.deegree.framework.xml.DOMPrinter; import org.deegree.framework.xml.NamespaceContext; import org.deegree.framework.xml.XMLFragment; import org.deegree.framework.xml.XMLParsingException; import org.deegree.framework.xml.XMLTools; import org.deegree.framework.xml.XSLTDocument; import org.deegree.io.DBPoolException; import org.deegree.ogcbase.CommonNamespaces; import org.deegree.ogcwebservices.EchoRequest; import org.deegree.ogcwebservices.InvalidParameterValueException; import org.deegree.ogcwebservices.MissingParameterValueException; import org.deegree.ogcwebservices.OGCWebServiceException; import org.deegree.ogcwebservices.csw.configuration.CatalogueConfiguration; import org.deegree.ogcwebservices.csw.configuration.CatalogueDeegreeParams; import org.deegree.ogcwebservices.csw.manager.HarvestRepository.ResourceType; import org.deegree.ogcwebservices.wfs.WFService; import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities; import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionResponse; import org.w3c.dom.Element; /** * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a> * * @author last edited by: $Author: mschneider $ * * @version 2.0, $Revision: 1.37 $, $Date: 2006/11/28 16:32:09 $ */ public class Manager { private static final ILogger LOG = LoggerFactory.getLogger( Manager.class ); private static Map<ResourceType, AbstractHarvester> harvester = null; private static XSLTDocument IN_XSL = null; private static XSLTDocument OUT_XSL = null; private WFService wfsService; /** * initializes a Manager instance * * @param wfsService * @param cswConfiguration */ public Manager( WFService wfsService, CatalogueConfiguration cswConfiguration ) throws MissingParameterValueException { this.wfsService = wfsService; try { CatalogueDeegreeParams cdp = cswConfiguration.getDeegreeParams(); URL url = cdp.getTransformationInputXSLT().getLinkage().getHref(); IN_XSL = new XSLTDocument(); IN_XSL.load( url ); url = cdp.getTransformationOutputXSLT().getLinkage().getHref(); OUT_XSL = new XSLTDocument(); OUT_XSL.load( url ); } catch ( Exception e ) { e.printStackTrace(); String s = "If a CS-W is defined to handle Transaction and/or Harvest requests " + "XSLT scripts for request transformations must be defined in " + "deegreeParams section of the capabilities document."; LOG.logError( s, e ); throw new MissingParameterValueException( getClass().getName(), s ); } WFSCapabilities capa = wfsService.getCapabilities(); initHarvester(); LOG.logInfo( "CSW Manager initialized with WFS resource " + capa.getServiceIdentification().getTitle() ); } /** * initializes a static Map containing a harvester for other * coatalogues, for services and for single CSW-profile documents. */ public static void initHarvester() { if ( harvester == null ) { harvester = new HashMap(); harvester.put( ResourceType.catalogue, CatalogueHarvester.getInstance() ); harvester.put( ResourceType.service, ServiceHarvester.getInstance() ); harvester.put( ResourceType.csw_profile, CSWProfileHarvester.getInstance() ); } } /** * starts all known/registered harvester. This method can be used * to start harvesting using requests e.g. if a server has * been shutdown and restarted. */ public static void startAllHarvester() { initHarvester(); Collection con = harvester.values(); for ( Iterator iter = con.iterator(); iter.hasNext(); ) { AbstractHarvester h = (AbstractHarvester) iter.next(); if ( !h.isRunning() ) { h.startHarvesting(); } } } /** * stpos all known/registered harvester. This method can be used * to stop harvesting using requests e.g. if a server has shall be * shut down. * */ public static void stopAllHarvester() { if ( harvester != null ) { Collection con = harvester.values(); for ( Iterator iter = con.iterator(); iter.hasNext(); ) { AbstractHarvester h = (AbstractHarvester) iter.next(); if ( h.isRunning() ) { h.stopHarvesting(); } } } } /** * @param request * @throws InvalidParameterValueException * @throws SQLException * @throws DBPoolException * @throws IOException */ public Object harvestRecords( Harvest request ) throws OGCWebServiceException { try { HarvesterFactory hf = new HarvesterFactory( harvester ); AbstractHarvester h = hf.findHarvester( request ); h.addRequest( request ); if ( !h.isRunning() ) { h.startHarvesting(); } if ( request.getHarvestInterval() == null ) { //h.removeRequest( request ); } } catch ( Exception e ) { e.printStackTrace(); LOG.logError( "could not perform harvest operation", e ); throw new OGCWebServiceException( getClass().getName(), "could not perform harvest operation" + e.getMessage() ); } return new EchoRequest( request.getId(), null ); } /** * performs a transaction request by transforming and forwarding it to the WFS used as backend * * @param request * @throws XMLParsingException * @throws OGCWebServiceException */ public TransactionResult transaction( Transaction request ) throws OGCWebServiceException { XMLFragment wfsTransactionDocument = null; try { XMLFragment transactionDocument = new XMLFragment( XMLFactory.export( request ).getRootElement() ); StringWriter sww = new StringWriter( 5000 ); transactionDocument.write( sww ); transactionDocument.load( new StringReader( sww.getBuffer().toString() ), XMLFragment.DEFAULT_URL ); wfsTransactionDocument = IN_XSL.transform( transactionDocument ); } catch ( Exception e ) { String msg = "Can't transform CSW Transaction request to WFS Transaction request: " + e.getMessage(); LOG.logError( msg, e ); throw new OGCWebServiceException( msg ); } if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { StringWriter sw = new StringWriter( 5000 ); try { wfsTransactionDocument.prettyPrint( sw ); } catch ( Exception e ) { e.printStackTrace(); wfsTransactionDocument.write( sw ); } try { FileUtils.writeToFile( "debug_transaction.xml", sw.getBuffer().toString() ); LOG.logDebug( "file: debug_transaction.xml has been written" ); } catch ( IOException e ) { } } org.deegree.ogcwebservices.wfs.operation.transaction.Transaction wfstrans = null; try { wfstrans = org.deegree.ogcwebservices.wfs.operation.transaction.Transaction.create( request.getId(), wfsTransactionDocument.getRootElement() ); } catch ( Exception e ) { LOG.logError( e.getMessage(), e ); String msg = "Cannot generate object representation for GetFeature request: " + e.getMessage(); LOG.logError( msg, e ); throw new OGCWebServiceException( msg ); } Object wfsResponse = null; try { wfsResponse = wfsService.doService( wfstrans ); } catch ( Exception e ) { String msg = "Generated WFS Transaction request failed: " + e.getMessage(); LOG.logError( msg, e ); throw new OGCWebServiceException( msg ); } if ( !( wfsResponse instanceof org.deegree.ogcwebservices.wfs.operation.transaction.TransactionResponse ) ) { String msg = "Unexpected result type '" + wfsResponse.getClass().getName() + "' from WFS (must be TransactionResponse)." + " Maybe a FeatureType is not correctly registered!?"; LOG.logError( msg ); throw new OGCWebServiceException( msg ); } TransactionResponse transResp = (TransactionResponse) wfsResponse; XMLFragment wfsTransRespDoc = null; try { wfsTransRespDoc = org.deegree.ogcwebservices.wfs.XMLFactory.export( transResp ); } catch ( IOException e ) { String msg = "export of WFS Transaction response as XML failed: " + e.getMessage(); LOG.logError( msg, e ); throw new OGCWebServiceException( msg ); } // -------------------------------------------------------------- // the following section will replace the feature ids returned by // the WFS for Insert requests by the ID of the inserted metadata sets List<String> ids = new ArrayList<String>(); List<Operation> ops = request.getOperations(); for ( int i = 0; i < ops.size(); i++ ) { if ( ops.get( i ) instanceof Insert ) { try { ids = extractIdentifiers( ids, (Insert) ops.get( i ) ); } catch ( Exception e ) { LOG.logError( e.getMessage(), e ); throw new OGCWebServiceException( getClass().getName(), e.getMessage() ); } } } try { if ( ids.size() > 0 ) { wfsTransRespDoc = replaceIds( wfsTransRespDoc, ids ); } } catch ( Exception e ) { LOG.logError( e.getMessage(), e ); throw new OGCWebServiceException( getClass().getName(), e.getMessage() ); } //--------------------------------------------------------------- TransactionResultDocument cswTransactionDocument = null; try { XMLFragment tmp = OUT_XSL.transform( wfsTransRespDoc ); cswTransactionDocument = new TransactionResultDocument(); cswTransactionDocument.setRootElement( tmp.getRootElement() ); } catch ( TransformerException e ) { String msg = "Can't transform GetRecord request to WFS GetFeature request: " + e.getMessage(); LOG.logError( msg, e ); throw new OGCWebServiceException( msg ); } TransactionResult result = null; try { result = cswTransactionDocument.parseTransactionResponse( request ); } catch ( XMLParsingException e ) { throw new OGCWebServiceException( "could not create TransactionResponse" ); } return result; } /** * replaces the id values of WFS Insert result with corresponding * metadata identifieres * * @param wfsTransRespDoc * @param ids * @return * @throws URISyntaxException * @throws XMLParsingException */ private XMLFragment replaceIds( XMLFragment wfsTransRespDoc, List<String> ids ) throws XMLParsingException { NamespaceContext nsc = CommonNamespaces.getNamespaceContext(); List nodes = XMLTools.getRequiredNodes( wfsTransRespDoc.getRootElement(), "./wfs:InsertResults/wfs:Feature/ogc:FeatureId", nsc ); for ( int i = 0; i < nodes.size(); i++ ) { Element elem = (Element) nodes.get( i ); elem.setAttribute( "fid", ids.get( i ) ); } return wfsTransRespDoc; } /** * extracts all identifiers of the records to be inserted in correct order * @param ids * @param insert * @return * @throws URISyntaxException * @throws XMLParsingException */ private List<String> extractIdentifiers( List<String> ids, Insert insert ) throws URISyntaxException, XMLParsingException { List<Element> records = insert.getRecords(); NamespaceContext nsc = CommonNamespaces.getNamespaceContext(); 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" ) ); nsc.addNamespace( "dc", new URI( "http://www.purl.org/dc/elements/1.1/" ) ); // nsc.addNamespace( "dc", new URI( "http://org/dc/elements/1.1/" ) ); for ( int i = 0; i < records.size(); i++ ) { String xpath = getIdentifierXPath( records.get( i ) ); String fileIdentifier = XMLTools.getRequiredNodeAsString( records.get( i ), xpath, nsc ); ids.add( fileIdentifier ); } return ids; } /** * returns the XPath the metadata records identifier * * @param metaData * @return */ private String getIdentifierXPath( Element metaData ) { // default is iso 19115 String xpath = "iso19115:fileIdentifier/smXML:CharacterString"; if ( metaData != null ) { String nspace = metaData.getNamespaceURI(); nspace = StringTools.replace( nspace, "http://", "", true ); xpath = Messages.getString( "Identifier_" + nspace ); } return xpath; } } /*************************************************************************************************** * Changes to this class. What the people have been up to: * $Log: Manager.java,v $ * Revision 1.37 2006/11/28 16:32:09 mschneider * Fixed dc identifier spelling. * * Revision 1.36 2006/11/23 18:42:02 poth * bug fix - setting correct IDs of inserted records in Transaction response * * Revision 1.35 2006/10/17 20:31:20 poth * *** empty log message *** * * Revision 1.34 2006/10/13 14:22:08 poth * changes required because of extending TransactionResult from DefaultOGCWebServiceResponse * * Revision 1.33 2006/07/10 15:01:36 poth * footer corrected * * Revision 1.32 2006/06/28 08:52:51 poth * bug fixes according catalog harvesting * Changes to this class. What the people have been up to: * Revision 1.31 2006/06/26 20:32:54 poth * bug fixes on harvester functionallity * Changes to this class. What the people have been up to: * Revision 1.30 2006/06/26 12:25:26 poth * public static method for stopping all running harvester added * Changes to this class. What the people have been up to: * Revision 1.29 2006/06/21 17:11:39 mschneider * Fixed error message. * Changes to this class. What the people have been up to: * Revision 1.28 2006/06/20 15:43:29 poth * *** empty log message *** * Changes to this class. What the people have been up to: * Revision 1.27 2006/06/20 13:38:37 poth * *** empty log message *** * Changes to this class. What the people have been up to: * Revision 1.26 2006/05/16 16:20:44 mschneider * Refactored due to the splitting of org.deegree.ogcwebservices.wfs.operation package. * Changes to this class. What the people have been up to: * Revision 1.25 2006/05/12 15:26:05 poth * *** empty log message *** * Changes to this class. What the people have been up to: * Revision 1.24 2006/05/09 15:51:37 poth * *** empty log message *** * Changes to this class. What the people have been up to: * Revision 1.23 2006/04/06 20:25:27 poth * *** empty log message *** * Changes to this class. What the people have been up to: * Revision 1.22 2006/04/04 20:39:43 poth * *** empty log message *** * Changes to this * class. What the people have been up to: Revision 1.21 2006/04/04 10:22:02 poth Changes to this * class. What the people have been up to: *** empty log message *** Changes to this class. What the * people have been up to: Revision 1.20 * 2006/03/30 21:20:26 poth *** empty log * message *** Changes to this class. What * the people have been up to: Revision 1.19 2006/03/28 09:06:41 poth Changes to this class. What * the people have been up to: *** empty log message *** Changes to this class. What the people have * been up to: Revision 1.18 2006/03/27 * 20:16:03 poth *** empty log message *** * Revision 1.17 2006/03/25 15:58:36 poth ** * empty log message *** * * Revision 1.16 2006/03/24 13:53:22 poth ** empty log message *** * * Revision 1.15 2006/03/22 13:22:14 poth ** empty log message *** * * Revision 1.14 2006/02/26 20:35:25 poth ** empty log message *** * * Revision 1.13 2006/02/23 17:35:12 poth ** empty log message *** * * Revision 1.12 2006/02/21 19:47:49 poth ** empty log message *** * * Revision 1.11 2006/02/20 14:15:25 poth ** empty log message *** * * Revision 1.10 2006/02/20 14:14:00 poth ** empty log message *** * * Revision 1.9 2006/02/20 12:40:02 poth ** empty log message *** * * * **************************************************************************************************/