001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wpvs/WFSInvoker.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2006 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 Aennchenstraße 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 044 package org.deegree.ogcwebservices.wpvs; 045 046 import java.io.StringReader; 047 import java.util.ArrayList; 048 049 import org.deegree.datatypes.QualifiedName; 050 import org.deegree.datatypes.Types; 051 import org.deegree.framework.log.ILogger; 052 import org.deegree.framework.log.LoggerFactory; 053 import org.deegree.framework.util.CharsetUtils; 054 import org.deegree.framework.util.IDGenerator; 055 import org.deegree.framework.util.StringTools; 056 import org.deegree.framework.xml.XMLTools; 057 import org.deegree.model.feature.Feature; 058 import org.deegree.model.feature.FeatureCollection; 059 import org.deegree.model.feature.FeatureProperty; 060 import org.deegree.model.feature.schema.FeatureType; 061 import org.deegree.model.feature.schema.PropertyType; 062 import org.deegree.model.filterencoding.ComplexFilter; 063 import org.deegree.model.filterencoding.FeatureFilter; 064 import org.deegree.model.filterencoding.FeatureId; 065 import org.deegree.model.filterencoding.Filter; 066 import org.deegree.model.spatialschema.GMLGeometryAdapter; 067 import org.deegree.model.spatialschema.GeometryException; 068 import org.deegree.ogcbase.PropertyPath; 069 import org.deegree.ogcwebservices.OGCWebServiceException; 070 import org.deegree.ogcwebservices.wfs.WFService; 071 import org.deegree.ogcwebservices.wfs.operation.FeatureResult; 072 import org.deegree.ogcwebservices.wfs.operation.GetFeature; 073 import org.deegree.ogcwebservices.wpvs.configuration.AbstractDataSource; 074 import org.deegree.ogcwebservices.wpvs.configuration.LocalWFSDataSource; 075 import org.deegree.ogcwebservices.wpvs.j3d.DefaultSurface; 076 import org.deegree.ogcwebservices.wpvs.j3d.Object3DFactory; 077 import org.deegree.ogcwebservices.wpvs.j3d.PointsToPointListFactory; 078 import org.deegree.ogcwebservices.wpvs.utils.ResolutionStripe; 079 import org.w3c.dom.Document; 080 081 /** 082 * Invoker for a Web Feature Service. 083 * 084 * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a> 085 * @author last edited by: $Author: bezema $ 086 * 087 * $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $ 088 * 089 */ 090 public class WFSInvoker extends GetViewServiceInvoker { 091 092 private static final ILogger LOG = LoggerFactory.getLogger( WFSInvoker.class ); 093 094 /* whether the returned data is a 3D object or data for the elevation model */ 095 private final boolean isElevationModelRequest; 096 097 private int id; 098 099 /** 100 * Creates a new instance of this class. 101 * 102 * @param owner 103 * the ResolutionStripe that calls this invoker 104 * @param id 105 * @param isElevationModelRequest 106 */ 107 public WFSInvoker( ResolutionStripe owner, int id, boolean isElevationModelRequest ) { 108 super( owner ); 109 this.id = id; 110 this.isElevationModelRequest = isElevationModelRequest; 111 } 112 113 @Override 114 public void invokeService( AbstractDataSource dataSource ) { 115 if ( !( dataSource instanceof LocalWFSDataSource ) ) { 116 LOG.logError( "The given AbstractDataSource is no WFSDataSource instance. It is needed for a WFSInvoker" ); 117 throw new RuntimeException( "DataSource should be a WFS-instance for a WFSInvoker" ); 118 } 119 WFService service = null; 120 try { 121 service = (WFService) dataSource.getOGCWebService(); 122 } catch ( OGCWebServiceException ogcwe ) { 123 LOG.logError( ogcwe.getMessage() ); 124 throw new RuntimeException( ogcwe ); 125 } 126 Object response = null; 127 try { 128 GetFeature getFeature = createGetFeatureRequest( (LocalWFSDataSource) dataSource ); 129 LOG.logDebug( "sending wfs request: " + dataSource.getName() ); 130 response = service.doService( getFeature ); 131 } catch ( OGCWebServiceException ogcwse ) { 132 if( !Thread.currentThread().isInterrupted() ){ 133 LOG.logError( "Exception while performing WFS-GetFeature: ", ogcwse ); 134 } 135 return; 136 } catch ( GeometryException ge ) { 137 LOG.logError( "Exception while creating WFS-GetFeature request: ", ge ); 138 ge.printStackTrace(); 139 return; 140 } 141 142 if ( response != null && response instanceof FeatureResult ) { 143 FeatureCollection result = (FeatureCollection) ( (FeatureResult) response ).getResponse(); 144 // System.out.println("resulting featureCollection: " + result ); 145 if ( result != null ) { 146 147 if ( isElevationModelRequest ) { 148 // PointListFactory adapter = (PointListFactory) ( (LocalWFSDataSource) 149 // dataSource ).getFeatureCollectionAdapter(); 150 PointsToPointListFactory ptpFac = new PointsToPointListFactory(); 151 resolutionStripe.setElevationModelFromMeassurePoints( ptpFac.createFromFeatureCollection( result ) ); 152 } else { 153 Object3DFactory o3DFactory = new Object3DFactory(); 154 for ( int i = 0; i < result.size(); ++i ) { 155 Feature feature = result.getFeature( i ); 156 // System.out.println( "feature: " + feature ); 157 createSurfaces( o3DFactory, feature ); 158 } 159 } 160 } 161 } else { 162 LOG.logError( "ERROR while invoking wfs-datasource: " + dataSource.getName() 163 + " the result was no WFS-response or no FeatureResult instance" ); 164 } 165 166 } 167 168 /** 169 * This method recursively constructs all the surfaces contained in the given feature. If the 170 * Feature contains a PropertyType of {@link Types#FEATURE} this Feature will also be traversed, 171 * if it contains a {@link Types#GEOMETRY} a {@link DefaultSurface} will be created. 172 * 173 * @param o3DFactory 174 * the Factory to create the defaultservice 175 * @param feature 176 * the feature to traverse. 177 */ 178 private void createSurfaces( Object3DFactory o3DFactory, Feature feature ) { 179 180 FeatureType ft = feature.getFeatureType(); 181 PropertyType[] propertyTypes = ft.getProperties(); 182 for ( PropertyType pt : propertyTypes ) { 183 if ( pt.getType() == Types.FEATURE ) { 184 FeatureProperty[] fp = feature.getProperties( pt.getName() ); 185 if ( fp != null ) { 186 for ( int i = 0; i < fp.length; i++ ) { 187 createSurfaces( o3DFactory, (Feature) fp[i].getValue() ); 188 } 189 } 190 } else if ( pt.getType() == Types.GEOMETRY ) { 191 DefaultSurface ds = o3DFactory.createSurface( feature ); 192 if ( ds != null ) { 193 resolutionStripe.addFeature( id + "_" + ds.getDefaultSurfaceID(), ds ); 194 } 195 } 196 } 197 } 198 199 /** 200 * Creates a new <code>GetFeature</code> object from an "XML-String" not nice. 201 * 202 * @param ds 203 * the datasource containig service data 204 * @param id 205 * the request id 206 * @return a new GetFeature request 207 * @throws GeometryException 208 * @throws OGCWebServiceException 209 * @throws Exception 210 */ 211 private GetFeature createGetFeatureRequest( LocalWFSDataSource dataSource /* 212 * String id, 213 * Surface[] boxes 214 */) 215 throws GeometryException, OGCWebServiceException { 216 217 QualifiedName qn = dataSource.getName(); 218 219 StringBuffer sb = new StringBuffer( 5000 ); 220 sb.append( "<?xml version='1.0' encoding='" + CharsetUtils.getSystemCharset() + "'?>" ); 221 sb.append( "<wfs:GetFeature xmlns:wfs='http://www.opengis.net/wfs' " ); 222 sb.append( "xmlns:ogc='http://www.opengis.net/ogc' " ); 223 sb.append( "xmlns:gml='http://www.opengis.net/gml' " ); 224 sb.append( "xmlns:" ).append( qn.getPrefix() ).append( '=' ); 225 sb.append( "'" ).append( qn.getNamespace() ).append( "' " ); 226 227 if ( dataSource.getServiceType() == AbstractDataSource.LOCAL_WFS ) { 228 sb.append( "outputFormat='FEATURECOLLECTION'>" ); 229 } else { 230 sb.append( "outputFormat='text/xml; subtype=gml/3.1.1'>" ); 231 } 232 233 /** 234 * To make things a little clearer compare with this SQL-Statement: SELECT ( !texture )? 235 * geoProperty : * FROM qn.getLocalName() WHERE geoPoperty intersects with 236 * resolutionStripe.getSurface() AND FilterConditions. 237 */ 238 PropertyPath geoProperty = dataSource.getGeometryProperty(); 239 240 // FROM 241 sb.append( "<wfs:Query typeName='" ).append( qn.getPrefix() ).append( ":" ); 242 sb.append( qn.getLocalName() ).append( "'>" ); 243 244 // SELECT 245 /* 246 * if ( !isElevationModelRequest ) { sb.append( "<wfs:PropertyName>" ); sb.append( 247 * geoProperty.getAsString() ); sb.append( "</wfs:PropertyName>" ); } 248 */ 249 250 StringBuffer sbArea = GMLGeometryAdapter.export( resolutionStripe.getSurface() ); 251 252 // WHERE 253 sb.append( "<ogc:Filter>" ); 254 255 // AND 256 Filter filter = dataSource.getFilter(); 257 if ( filter != null ) { 258 if ( filter instanceof ComplexFilter ) { 259 sb.append( "<ogc:And>" ); 260 sb.append( "<ogc:Intersects>"); 261 sb.append( "<wfs:PropertyName>" ); 262 sb.append( geoProperty.getAsString() ); 263 sb.append( "</wfs:PropertyName>" ); 264 sb.append( sbArea ); 265 sb.append( "</ogc:Intersects>" ); 266 // add filter as defined in the layers datasource description 267 // to the filter expression 268 org.deegree.model.filterencoding.Operation op = ( (ComplexFilter) filter ).getOperation(); 269 sb.append( op.toXML() ).append( "</ogc:And>" ); 270 } else { 271 if ( filter instanceof FeatureFilter ) { 272 ArrayList<FeatureId> featureIds = ( (FeatureFilter) filter ).getFeatureIds(); 273 if ( featureIds.size() != 0 ) 274 sb.append( "<ogc:And>" ); 275 for ( FeatureId fid : featureIds ) { 276 sb.append( fid.toXML() ); 277 } 278 if ( featureIds.size() != 0 ) 279 sb.append( "</ogc:And>" ); 280 } 281 } 282 } else { 283 sb.append( "<ogc:Intersects>"); 284 sb.append( "<wfs:PropertyName>" ); 285 sb.append( geoProperty.getAsString() ); 286 sb.append( "</wfs:PropertyName>" ); 287 sb.append( sbArea ); 288 sb.append( "</ogc:Intersects>" ); 289 } 290 291 sb.append( "</ogc:Filter></wfs:Query></wfs:GetFeature>" ); 292 293 String s = sb.toString(); 294 295 Document doc; 296 try { 297 doc = XMLTools.parse( new StringReader( s ) ); 298 } catch ( Exception e ) { 299 e.printStackTrace(); 300 String mesg = "Could not parse GetFeature request "; 301 LOG.logError( StringTools.concat( s.length() + 100, mesg, sb.toString() ) ); 302 throw new OGCWebServiceException( mesg ); 303 } 304 305 IDGenerator idg = IDGenerator.getInstance(); 306 return GetFeature.create( String.valueOf( idg.generateUniqueID() ), 307 doc.getDocumentElement() ); 308 } 309 310 } 311 312 /*************************************************************************************************** 313 * <code> 314 * Changes to this class. What the people have been up to: 315 * 316 * $Log$ 317 * Revision 1.45 2007/03/19 09:58:52 poth 318 * bug fix - considering filter condition 319 * 320 * Revision 1.44 2007/01/31 09:49:05 bezema 321 * added support for the max request time 322 * 323 * Revision 1.43 2007/01/30 14:53:41 bezema 324 * removed unnecesary try catch 325 * 326 * Revision 1.42 2007/01/23 15:08:23 bezema 327 * added a single configuration/capabilities parsing of the datasources 328 * 329 * Revision 1.41 2007/01/15 17:00:30 bezema 330 * added some debug statements 331 * 332 * 333 * Revision 1.40 2006/12/15 13:18:49 poth code formatting 334 * 335 * Revision 1.39 2006/12/14 16:15:34 poth set corrected error message : 336 * Revision 1.38 2006/12/06 16:10:25 poth bug fix - transperent colors 337 * Revision 1.37 2006/12/06 15:12:57 bezema renamed the 338 * wpvs.util package into wpvs.utils 339 * Revision 1.36 2006/12/06 11:24:33 bezema can use the wcs as a 340 * localdatasource for textures and dgm, also added support for the wfs features in gml. Still 341 * trying to figure out how the eyepoint is set by java3d 342 * Revision 1.35 2006/11/27 15:43:34 bezema 343 * Updated the coordinatesystem handling 344 * Revision 1.34 2006/11/23 11:46:14 bezema The initial 345 * version of the new wpvs 346 * Revision 1.32 2006/07/20 08:12:21 taddei use of QualiName for geometry 347 * property 348 * Revision 1.31 2006/07/05 15:57:47 poth useless parameter removed from method signature 349 * Revision 1.30 2006/07/05 11:22:10 taddei include par to set buildings elev to 0 350 * Revision 1.29 2006/07/04 09:06:22 taddei todo: excp handling 351 * Revision 1.28 2006/06/29 16:50:09 poth *** empty log message *** 352 * Revision 1.27 2006/06/20 10:16:01 taddei clean up and 353 * javadoc Changes to this class. 354 * Revision 1.26 2006/06/20 07:39:59 taddei added parent dataset and change in ft name 355 * Revision 1.25 2006/05/12 13:12:45 taddei clean up 356 * Revision 1.24 2006/05/10 15:01:19 taddei now collecting boxes into a 357 * united geom 358 * Revision 1.23 2006/05/05 12:41:02 taddei added to to list 359 * 360 * Revision 1.22 2006/04/18 18:20:26 poth ** empty log message *** 361 * 362 * Revision 1.21 2006/04/06 20:25:30 poth ** empty log message *** 363 * 364 * Revision 1.20 2006/04/06 15:07:59 taddei added support for ValidArea 365 * 366 * Revision 1.19 2006/04/05 09:07:03 taddei added code for computing res of different surfs; and fc 367 * adapter 368 * 369 * Revision 1.17 2006/03/29 15:08:21 taddei with buildings 370 * 371 * Revision 1.16 2006/03/10 10:31:40 taddei changes regarding cood sys and scale calculation 372 * 373 * Revision 1.15 2006/03/09 08:57:58 taddei debug mesgs 374 * 375 * Revision 1.14 2006/03/07 08:49:20 taddei changes due to pts list factories 376 * 377 * Revision 1.13 2006/03/02 15:23:52 taddei using now StringTools and StringBuilder 378 * 379 * Revision 1.12 2006/02/22 17:12:31 taddei implemented correct drawing order 380 * 381 * Revision 1.11 2006/02/22 13:36:02 taddei refactoring: added service, createOGCWebService; also 382 * better except handling 383 * 384 * Revision 1.10 2006/02/17 13:38:12 taddei bug fix when counting (resol was using wrong dim) and 385 * fixed � (sz) 386 * 387 * Revision 1.9 2006/02/14 15:21:41 taddei now working with remote WFS 388 * 389 * Revision 1.8 2006/02/09 15:47:24 taddei bug fixes, refactoring and javadoc 390 * 391 * Revision 1.7 2006/01/30 14:58:37 taddei minor internal refactoring 392 * 393 * Revision 1.6 2006/01/27 10:39:13 taddei query optmization 394 * 395 * Revision 1.5 2006/01/26 14:42:31 taddei WMS and WFS invokers woring; minor refactoring 396 * 397 * Revision 1.4 2006/01/18 10:21:07 taddei putting wfs service to work 398 * 399 * Revision 1.3 2006/01/18 08:59:36 taddei commented out (due to wrong refactoring); fix is coming 400 * 401 * Revision 1.2 2006/01/18 08:58:00 taddei implementation (WFS) 402 * 403 * Revision 1.1 2005/12/16 15:19:11 taddei added DeafultViewHandler and the Invokers 404 * 405 * </code> 406 **************************************************************************************************/