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 **************************************************************************************************/