//$HeadURL$ /*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001-2008 by: 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 53177 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.igeo.dataadapter.wfs; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; import org.deegree.datatypes.QualifiedName; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.FileUtils; import org.deegree.framework.util.HttpUtils; import org.deegree.framework.utils.OWSExceptionParser; import org.deegree.framework.xml.XMLFragment; import org.deegree.framework.xml.XMLParsingException; import org.deegree.framework.xml.XMLTools; import org.deegree.igeo.ApplicationContainer; import org.deegree.igeo.dataadapter.DataAccessException; import org.deegree.igeo.i18n.Messages; import org.deegree.igeo.mapmodel.Layer; import org.deegree.model.feature.Feature; import org.deegree.model.feature.FeatureCollection; import org.deegree.model.feature.FeatureProperty; import org.deegree.model.filterencoding.FeatureFilter; import org.deegree.model.filterencoding.FeatureId; import org.deegree.ogcbase.CommonNamespaces; import org.deegree.ogcbase.PropertyPath; import org.deegree.ogcbase.PropertyPathFactory; import org.deegree.ogcwebservices.wfs.XMLFactory; import org.deegree.ogcwebservices.wfs.operation.transaction.Delete; import org.deegree.ogcwebservices.wfs.operation.transaction.Insert; import org.deegree.ogcwebservices.wfs.operation.transaction.Transaction; import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionOperation; import org.deegree.ogcwebservices.wfs.operation.transaction.Update; import org.deegree.ogcwebservices.wfs.operation.transaction.Insert.ID_GEN; /** * Implementation of {@link WFSDataWriter} for WFS 1.1.0 * * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> * * @author last edited by: $Author$ * * @version $Revision$, $Date$ * */ public class WFS110DataWriter implements WFSDataWriter { private static final ILogger LOG = LoggerFactory.getLogger( WFS110DataWriter.class ); private int timeout = 25000; /** * package protected to avoid uncontrolled access */ WFS110DataWriter() { } /* * (non-Javadoc) * * @see org.deegree.igeo.dataadapter.WFSDataWriter#setTimeout(int) */ public void setTimeout( int timeout ) { this.timeout = timeout; } /* * (non-Javadoc) * * @see org.deegree.igeo.dataadapter.WFSDataWriter#deleteFeatures(java.io.URL, * org.deegree.model.feature.FeatureCollection) */ public int deleteFeatures( URL wfsURL, FeatureCollection featureCollection, Layer layer ) { int count = 0; if ( featureCollection.size() > 0 ) { List<TransactionOperation> list = new ArrayList<TransactionOperation>( featureCollection.size() ); Iterator<Feature> iter = featureCollection.iterator(); while ( iter.hasNext() ) { Feature feature = (Feature) iter.next(); FeatureFilter filter = new FeatureFilter( new ArrayList<FeatureId>( 1 ) ); filter.addFeatureId( new FeatureId( feature.getId() ) ); QualifiedName qn = feature.getFeatureType().getName(); Delete delete = new Delete( UUID.randomUUID().toString(), qn, filter ); list.add( delete ); } XMLFragment xml = performTransaction( wfsURL, list, layer.getOwner().getApplicationContainer() ); String xpath = "wfs:TransactionSummary/wfs:totalUpdated"; try { count = XMLTools.getNodeAsInt( xml.getRootElement(), xpath, CommonNamespaces.getNamespaceContext(), featureCollection.size() ); } catch ( XMLParsingException e ) { LOG.logError( e.getMessage(), e ); String[] exc = OWSExceptionParser.parseException( xml ); throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10084", wfsURL, exc[0], exc[1] ) ); } } return count; } /* * (non-Javadoc) * * @see org.deegree.igeo.dataadapter.WFSDataWriter#insertFeatures(java.io.URL, * org.deegree.model.feature.FeatureCollection) */ public List<String> insertFeatures( URL wfsURL, FeatureCollection featureCollection, Layer layer ) { if ( featureCollection.size() > 0 ) { // force that a WFS generates new IDs to ensure ID - data type matches data type of the backend // ad that a features ID is really unique Insert insert = new Insert( UUID.randomUUID().toString(), ID_GEN.GENERATE_NEW, null, featureCollection ); List<TransactionOperation> list = new ArrayList<TransactionOperation>(); list.add( insert ); XMLFragment xml = performTransaction( wfsURL, list, layer.getOwner().getApplicationContainer() ); // read and return IDs of inserted features. This is required to update features within the layer // on which a transaction has been performed with IDs generated by the WFS String xpath = "wfs:InsertResults/wfs:Feature/ogc:FeatureId/@fid"; List<String> ids = null; try { String[] tmp = XMLTools.getRequiredNodesAsStrings( xml.getRootElement(), xpath, CommonNamespaces.getNamespaceContext() ); ids = new ArrayList<String>( tmp.length ); for ( String string : tmp ) { ids.add( string ); } } catch ( XMLParsingException e ) { LOG.logError( e.getMessage(), e ); String[] exc = OWSExceptionParser.parseException( xml ); throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10084", wfsURL, exc[0], exc[1] ) ); } return ids; } else { return new ArrayList<String>( 1 ); } } /* * (non-Javadoc) * * @see org.deegree.igeo.dataadapter.WFSDataWriter#updateFeatures(java.io.URL, * org.deegree.model.feature.FeatureCollection) */ public int updateFeatures( URL wfsURL, FeatureCollection featureCollection, Layer layer ) { int count = 0; if ( featureCollection.size() > 0 ) { List<TransactionOperation> list = new ArrayList<TransactionOperation>( featureCollection.size() ); Iterator<Feature> iter = featureCollection.iterator(); while ( iter.hasNext() ) { Feature feature = (Feature) iter.next(); FeatureFilter filter = new FeatureFilter( new ArrayList<FeatureId>( 1 ) ); filter.addFeatureId( new FeatureId( feature.getId() ) ); QualifiedName qn = feature.getFeatureType().getName(); FeatureProperty[] fp = feature.getProperties(); Map<PropertyPath, FeatureProperty> propertyMap = new HashMap<PropertyPath, FeatureProperty>(); for ( FeatureProperty featureProperty : fp ) { PropertyPath pp = PropertyPathFactory.createPropertyPath( featureProperty.getName() ); propertyMap.put( pp, featureProperty ); } Update update = new Update( UUID.randomUUID().toString(), qn, propertyMap, filter ); list.add( update ); } XMLFragment xml = performTransaction( wfsURL, list, layer.getOwner().getApplicationContainer() ); String xpath = "wfs:TransactionSummary/wfs:totalUpdated"; try { count = XMLTools.getNodeAsInt( xml.getRootElement(), xpath, CommonNamespaces.getNamespaceContext(), featureCollection.size() ); } catch ( XMLParsingException e ) { LOG.logError( e.getMessage(), e ); String[] exc = OWSExceptionParser.parseException( xml ); throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10084", wfsURL, exc[0], exc[1] ) ); } } return count; } private XMLFragment performTransaction( URL wfsURL, List<TransactionOperation> list, ApplicationContainer<?> appCont ) { Transaction transaction = new Transaction( null, null, null, null, list, true, null ); InputStream is; try { XMLFragment xml = XMLFactory.export( transaction ); HttpUtils.addAuthenticationForXML( xml, appCont.getUser(), appCont.getPassword(), appCont.getCertificate( wfsURL.toURI().toASCIIString() ) ); if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { LOG.logDebug( "WFS Transaction: ", xml.getAsString() ); } is = HttpUtils.performHttpPost( wfsURL.toURI().toASCIIString(), xml, timeout, appCont.getUser(), appCont.getPassword(), null ).getResponseBodyAsStream(); } catch ( Exception e ) { LOG.logError( e.getMessage(), e ); throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10082", wfsURL ) ); } XMLFragment xml = null; try { if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { String st = FileUtils.readTextFile( is ).toString(); is = new ByteArrayInputStream( st.getBytes() ); LOG.logDebug( "WFS transaction result: ", st ); } xml = new XMLFragment(); xml.load( is, wfsURL.toExternalForm() ); } catch ( Exception e ) { LOG.logError( e.getMessage() + ": " + xml.getAsString(), e ); throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10080", wfsURL, "" ) ); } if ( "ExceptionReport".equalsIgnoreCase( xml.getRootElement().getLocalName() ) ) { LOG.logError( "Transaction on: " + xml.getAsString() + " failed" ); // TODO // extract exception message throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10083", wfsURL, "" ) ); } return xml; } }